Compare commits
161 Commits
renovate/v
...
9d35e8eef3
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d35e8eef3 | |||
|
|
cb788952a4 | ||
|
|
cd18a9d108 | ||
|
|
a6d91a93a5 | ||
|
|
66694c7d7e | ||
|
|
cfd3028218 | ||
|
|
f09c6e3a1c | ||
|
|
edf06b5f99 | ||
|
|
cb5e3a84ae | ||
|
|
94ba0b0c5e | ||
|
|
c352b38417 | ||
|
|
cb84cf4cfe | ||
|
|
563f1c3ba7 | ||
| f2bfca6685 | |||
| 4772d02349 | |||
|
|
ccc2ff1b57 | ||
|
|
cef44cab0a | ||
|
|
ac98fb6e8b | ||
|
|
88059c5ea7 | ||
| 8ccee184f5 | |||
| 6adb7061f4 | |||
|
|
637aeaa04e | ||
|
|
5070c0706d | ||
|
|
92a13efabc | ||
|
|
1accd657e0 | ||
|
|
943c2aa35d | ||
|
|
9dd7592c45 | ||
|
|
f51b1b04ae | ||
|
|
485278558f | ||
|
|
ceb61ef992 | ||
|
|
4cafcfac6f | ||
|
|
a623e8217c | ||
|
|
4b67552a14 | ||
|
|
6f50cf2989 | ||
|
|
aa243c6493 | ||
|
|
10cec68ee2 | ||
|
|
3addaf391e | ||
|
|
3b5a9abefa | ||
|
|
70d5ef950b | ||
|
|
140b2deda8 | ||
|
|
83128bb467 | ||
|
|
3ff646db0f | ||
|
|
c4bfcb07c1 | ||
|
|
cd937a86c7 | ||
|
|
c79e6e8bad | ||
|
|
70dcdf8160 | ||
|
|
9feb94ea9e | ||
|
|
a890d1c855 | ||
|
|
e3bb50e2c9 | ||
| cd17be8c6d | |||
|
|
25d5defdca | ||
|
|
f78b9f318a | ||
|
|
3b90384f8f | ||
|
|
c1705c1587 | ||
|
|
87c9c637be | ||
|
|
981e989461 | ||
|
|
d1ff6b31e2 | ||
|
|
9f5f0edfd9 | ||
|
|
4d5c188599 | ||
|
|
ec91f8e5ee | ||
|
|
d38e220df8 | ||
|
|
da0847b3f9 | ||
|
|
ec5e5bdc87 | ||
|
|
fe5cfbe99c | ||
|
|
c789de3ad8 | ||
|
|
a510dbc77b | ||
|
|
5f85938449 | ||
|
|
9fde8dc57c | ||
|
|
d682643407 | ||
|
|
0718ba48bd | ||
|
|
9680a7007d | ||
| a8b2c1e098 | |||
|
|
6d52c4ee31 | ||
|
|
c80b25b0e0 | ||
|
|
7e14f27df4 | ||
|
|
5bc1e65a61 | ||
|
|
53bc4407b3 | ||
|
|
66289da64c | ||
|
|
679a624fab | ||
|
|
ba76f38bc4 | ||
| 13a7c44aae | |||
|
|
c7a68d8653 | ||
|
|
87e7b74ed6 | ||
|
|
4b82b8e627 | ||
|
|
4f69f667b0 | ||
|
|
0b8418e114 | ||
|
|
65447a6fec | ||
|
|
15a9ef3f79 | ||
|
|
7132f7a463 | ||
|
|
56f05e93e7 | ||
|
|
9beddc0877 | ||
|
|
8a354b5519 | ||
|
|
5de4773974 | ||
|
|
1090a685d2 | ||
|
|
f537490f40 | ||
|
|
2348ea9bc1 | ||
|
|
0619af6524 | ||
|
|
993e97676f | ||
|
|
95f53b8a00 | ||
|
|
8b948b2251 | ||
|
|
626a9292d5 | ||
| cb40ecff06 | |||
| b9b9f37859 | |||
|
|
363c7d24f4 | ||
|
|
d57654d872 | ||
|
|
0b7d9383ec | ||
|
|
c380fe9d08 | ||
|
|
92722444cf | ||
|
|
882054b53d | ||
|
|
1c0519cfaf | ||
|
|
f69125012e | ||
|
|
8c8560b63c | ||
|
|
86e8a7bd92 | ||
|
|
12878cd76b | ||
|
|
308025d662 | ||
|
|
2094f254b3 | ||
|
|
8ce4a959a6 | ||
| 3708059da4 | |||
|
|
cd8b5e6364 | ||
|
|
a48b623822 | ||
|
|
499e1e174b | ||
|
|
6b9c177ae7 | ||
|
|
b73b053cc8 | ||
|
|
bbad86bf97 | ||
|
|
6ae311cdfd | ||
|
|
03eca8a1af | ||
|
|
c03d697361 | ||
|
|
3847686d54 | ||
|
|
9801444c0a | ||
|
|
68d8c9fa84 | ||
|
|
cba42bfa52 | ||
|
|
874da0b963 | ||
|
|
bb0579408d | ||
|
|
b39c5946f9 | ||
|
|
aaf494e27a | ||
|
|
dbc5694b6d | ||
|
|
86582de0c5 | ||
|
|
72495bb9b5 | ||
|
|
312c103e71 | ||
|
|
a252cfec27 | ||
|
|
4a5f4c329d | ||
|
|
6f96608f64 | ||
| 0bc29b2cb9 | |||
|
|
8642619a6a | ||
|
|
e8b8df9449 | ||
|
|
3695128923 | ||
|
|
1f14e8be6b | ||
|
|
adc8835304 | ||
|
|
8b06c56ec0 | ||
|
|
003d2f19a2 | ||
|
|
15f6d695f8 | ||
|
|
64583601dc | ||
|
|
cf4ba5805f | ||
|
|
90db94e905 | ||
|
|
336ea67ea2 | ||
|
|
1af839f036 | ||
|
|
6bdf2a4d87 | ||
| 8d55a67e75 | |||
|
|
a1ec5c4781 | ||
| 756b652861 | |||
| 59f9358b9a |
@@ -1,6 +1,6 @@
|
|||||||
# Effect FC Monorepo
|
# Effect FC Monorepo
|
||||||
|
|
||||||
[Effect-TS](https://effect.website/) integration for React 19.2+ that allows you to write function components using Effect generators.
|
[Effect-TS](https://effect.website/) integration for React 19+ that allows you to write function components using Effect generators.
|
||||||
|
|
||||||
This monorepo contains:
|
This monorepo contains:
|
||||||
- [The `effect-fc` library](packages/effect-fc)
|
- [The `effect-fc` library](packages/effect-fc)
|
||||||
|
|||||||
359
bun.lock
359
bun.lock
@@ -5,21 +5,18 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "@effect-fc/monorepo",
|
"name": "@effect-fc/monorepo",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.3.11",
|
"@biomejs/biome": "^2.3.8",
|
||||||
"@effect/language-service": "^0.75.0",
|
"@effect/language-service": "^0.65.0",
|
||||||
"@types/bun": "^1.3.6",
|
"@types/bun": "^1.3.3",
|
||||||
"npm-check-updates": "^19.3.1",
|
"npm-check-updates": "^19.1.2",
|
||||||
"npm-sort": "^0.0.4",
|
"npm-sort": "^0.0.4",
|
||||||
"turbo": "^2.7.5",
|
"turbo": "^2.6.1",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/effect-fc": {
|
"packages/effect-fc": {
|
||||||
"name": "effect-fc",
|
"name": "effect-fc",
|
||||||
"version": "0.2.3",
|
"version": "0.2.1",
|
||||||
"devDependencies": {
|
|
||||||
"@effect/platform-browser": "^0.74.0",
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0",
|
"@types/react": "^19.2.0",
|
||||||
"effect": "^3.19.0",
|
"effect": "^3.19.0",
|
||||||
@@ -30,47 +27,59 @@
|
|||||||
"name": "@effect-fc/example",
|
"name": "@effect-fc/example",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform": "^0.94.2",
|
"@effect/platform": "^0.93.6",
|
||||||
"@effect/platform-browser": "^0.74.0",
|
"@effect/platform-browser": "^0.73.0",
|
||||||
"@radix-ui/themes": "^3.2.1",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
"@typed/id": "^0.17.2",
|
"@typed/id": "^0.17.2",
|
||||||
"effect": "^3.19.15",
|
"effect": "^3.19.8",
|
||||||
"effect-fc": "workspace:*",
|
"effect-fc": "workspace:*",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tanstack/react-router": "^1.154.12",
|
"@tanstack/react-router": "^1.139.12",
|
||||||
"@tanstack/react-router-devtools": "^1.154.12",
|
"@tanstack/react-router-devtools": "^1.139.12",
|
||||||
"@tanstack/router-plugin": "^1.154.12",
|
"@tanstack/router-plugin": "^1.139.12",
|
||||||
"@types/react": "^19.2.9",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
"globals": "^17.0.0",
|
"globals": "^16.5.0",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.0",
|
||||||
"type-fest": "^5.4.1",
|
"type-fest": "^5.2.0",
|
||||||
"vite": "^7.3.1",
|
"vite": "^7.2.6",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages": {
|
"packages": {
|
||||||
"@babel/code-frame": ["@babel/code-frame@7.28.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q=="],
|
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||||
|
|
||||||
"@babel/compat-data": ["@babel/compat-data@7.28.6", "", {}, "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg=="],
|
"@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="],
|
||||||
|
|
||||||
"@babel/core": ["@babel/core@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw=="],
|
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
|
||||||
|
|
||||||
"@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="],
|
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
|
||||||
|
|
||||||
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
|
"@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
|
||||||
|
|
||||||
|
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="],
|
||||||
|
|
||||||
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
|
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
|
||||||
|
|
||||||
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
|
"@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
|
||||||
|
|
||||||
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
|
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
|
||||||
|
|
||||||
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="],
|
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
|
||||||
|
|
||||||
|
"@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
|
||||||
|
|
||||||
|
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
|
||||||
|
|
||||||
|
"@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.27.1", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA=="],
|
||||||
|
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
|
||||||
|
|
||||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||||
|
|
||||||
@@ -78,101 +87,107 @@
|
|||||||
|
|
||||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||||
|
|
||||||
"@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
|
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
|
||||||
|
|
||||||
"@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="],
|
"@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
||||||
|
|
||||||
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="],
|
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
|
||||||
|
|
||||||
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="],
|
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="],
|
||||||
|
|
||||||
|
"@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="],
|
||||||
|
|
||||||
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
|
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
|
||||||
|
|
||||||
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
|
||||||
|
|
||||||
"@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
|
"@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="],
|
||||||
|
|
||||||
"@babel/traverse": ["@babel/traverse@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/types": "^7.28.6", "debug": "^4.3.1" } }, "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg=="],
|
"@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
|
||||||
|
|
||||||
"@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="],
|
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||||
|
|
||||||
"@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="],
|
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
|
||||||
|
|
||||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="],
|
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
|
||||||
|
|
||||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="],
|
"@biomejs/biome": ["@biomejs/biome@2.3.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="],
|
||||||
|
|
||||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="],
|
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="],
|
||||||
|
|
||||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="],
|
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA=="],
|
||||||
|
|
||||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="],
|
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g=="],
|
||||||
|
|
||||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="],
|
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA=="],
|
||||||
|
|
||||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="],
|
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw=="],
|
||||||
|
|
||||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="],
|
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.8", "", { "os": "win32", "cpu": "x64" }, "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w=="],
|
||||||
|
|
||||||
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
|
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
|
||||||
|
|
||||||
"@effect/language-service": ["@effect/language-service@0.75.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-DxRN8+b5IEQ/x8hukpV39kJe7fs6er7LDWp1PvKjOxPkN5UJ8VJovUVzoHtOX6XWzMmJBRCN9/j0s8jujXTduw=="],
|
"@effect/language-service": ["@effect/language-service@0.65.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-eHcpLNCZa1XEDRrXLZqTdky6jAQojL6zQEW53Ba6vJL35j77tJTnV9BFkk34G3rxKoplNo39U0Mum3RfuH9rsg=="],
|
||||||
|
|
||||||
"@effect/platform": ["@effect/platform@0.94.2", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.15" } }, "sha512-85vdwpnK4oH/rJ3EuX/Gi2Hkt+K4HvXWr9bxCuqvty9hxyEcRxkJcqTesYrcVoQB6aULb1Za2B0MKoTbvffB3Q=="],
|
"@effect/platform": ["@effect/platform@0.93.6", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.8" } }, "sha512-I5lBGQWzWXP4zlIdPs7z7WHmEFVBQhn+74emr/h16GZX96EEJ6I1rjGaKyZF7mtukbMuo9wEckDPssM8vskZ/w=="],
|
||||||
|
|
||||||
"@effect/platform-browser": ["@effect/platform-browser@0.74.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13" } }, "sha512-PAgkg5L5cASQpScA0SZTSy543MVA4A9kmpVCjo2fCINLRpTeuCFAOQHgPmw8dKHnYS0yGs2TYn7AlrhhqQ5o3g=="],
|
"@effect/platform-browser": ["@effect/platform-browser@0.73.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.93.0", "effect": "^3.19.0" } }, "sha512-G/LWu+roBHtjb9JEpCYe47XG0oB2xlUIp7fBQznDPYYMksqtrusEdtVtAWfPhO21aNvVmv7+agonisxK2vGaCQ=="],
|
||||||
|
|
||||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
|
||||||
|
|
||||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
|
||||||
|
|
||||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="],
|
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
|
||||||
|
|
||||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="],
|
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
|
||||||
|
|
||||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="],
|
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
|
||||||
|
|
||||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="],
|
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="],
|
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
|
||||||
|
|
||||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="],
|
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="],
|
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
|
||||||
|
|
||||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="],
|
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
|
||||||
|
|
||||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="],
|
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
|
||||||
|
|
||||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="],
|
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
|
||||||
|
|
||||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="],
|
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
|
||||||
|
|
||||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="],
|
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
|
||||||
|
|
||||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="],
|
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
|
||||||
|
|
||||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="],
|
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
|
||||||
|
|
||||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="],
|
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
|
||||||
|
|
||||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="],
|
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
|
||||||
|
|
||||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="],
|
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
|
||||||
|
|
||||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="],
|
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
|
||||||
|
|
||||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="],
|
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
|
||||||
|
|
||||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="],
|
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
|
||||||
|
|
||||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="],
|
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
|
||||||
|
|
||||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="],
|
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
|
||||||
|
|
||||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="],
|
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
|
||||||
|
|
||||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
|
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
|
||||||
|
|
||||||
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
|
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
|
||||||
|
|
||||||
@@ -328,81 +343,75 @@
|
|||||||
|
|
||||||
"@radix-ui/themes": ["@radix-ui/themes@3.2.1", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.3", "react-remove-scroll-bar": "^2.3.8" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg=="],
|
"@radix-ui/themes": ["@radix-ui/themes@3.2.1", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.3", "react-remove-scroll-bar": "^2.3.8" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg=="],
|
||||||
|
|
||||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="],
|
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.47", "", {}, "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw=="],
|
||||||
|
|
||||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="],
|
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="],
|
||||||
|
|
||||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg=="],
|
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="],
|
||||||
|
|
||||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg=="],
|
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="],
|
||||||
|
|
||||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ=="],
|
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="],
|
||||||
|
|
||||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg=="],
|
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="],
|
||||||
|
|
||||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw=="],
|
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ=="],
|
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg=="],
|
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ=="],
|
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA=="],
|
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g=="],
|
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw=="],
|
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw=="],
|
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw=="],
|
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw=="],
|
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg=="],
|
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg=="],
|
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg=="],
|
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="],
|
||||||
|
|
||||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w=="],
|
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="],
|
||||||
|
|
||||||
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg=="],
|
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="],
|
||||||
|
|
||||||
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.1", "", { "os": "none", "cpu": "arm64" }, "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw=="],
|
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="],
|
||||||
|
|
||||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g=="],
|
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="],
|
||||||
|
|
||||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA=="],
|
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||||
|
|
||||||
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg=="],
|
"@tanstack/history": ["@tanstack/history@1.140.0", "", {}, "sha512-u+/dChlWlT3kYa/RmFP+E7xY5EnzvKEKcvKk+XrgWMpBWExQIh3RQX/eUqhqwCXJPNc4jfm1Coj8umnm/hDgyA=="],
|
||||||
|
|
||||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="],
|
"@tanstack/react-router": ["@tanstack/react-router@1.140.0", "", { "dependencies": { "@tanstack/history": "1.140.0", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.140.0", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-Xe4K1bEtU5h0cAhaKYXDQA2cuITgEs1x6tOognJbcxamlAdzDAkhYBhRg8dKSVAyfGejAUNlUi4utnN0s6R+Yw=="],
|
||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.140.0", "", { "dependencies": { "@tanstack/router-devtools-core": "1.140.0" }, "peerDependencies": { "@tanstack/react-router": "^1.140.0", "@tanstack/router-core": "^1.140.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-11NFwHCG8KphG7Bif570qOxBVwNBTkIOExsf42WNv7cgRhwD6cHjUvfx20/WzkAlvFbEGlV+pp7wiJm3HR56bQ=="],
|
||||||
|
|
||||||
"@tanstack/history": ["@tanstack/history@1.154.7", "", {}, "sha512-YBgwS9qG4rs1ZY/ZrhQtjOH8BG9Qa2wf2AsxT/SnZ4HZJ1DcCEqkoiHH0yH6CYvdDit31X5HokOqQrRSsZEwGA=="],
|
|
||||||
|
|
||||||
"@tanstack/react-router": ["@tanstack/react-router@1.154.12", "", { "dependencies": { "@tanstack/history": "1.154.7", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.154.12", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-WiYfC6IYC2HwjkATouJCQlAM5RJ8MViefslfUcZpsbCb+WGQpdpvUY7GPJLEeessSpqgiC2EabRYC2kYVNyMPg=="],
|
|
||||||
|
|
||||||
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.154.12", "", { "dependencies": { "@tanstack/router-devtools-core": "1.154.12" }, "peerDependencies": { "@tanstack/react-router": "^1.154.12", "@tanstack/router-core": "^1.154.12", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-TcGe7pmeVjk1zD58eMR87GG9OXMx6LDGz5QopmJS4LafvK2hvuaht+eKBnZlCvKLPlXu5juwHT4u+2bYdn6sqQ=="],
|
|
||||||
|
|
||||||
"@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="],
|
"@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="],
|
||||||
|
|
||||||
"@tanstack/router-core": ["@tanstack/router-core@1.154.12", "", { "dependencies": { "@tanstack/history": "1.154.7", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-p+TKxkXcLGtCwwW237D8pV4f6ea2K1pzc/e65ljugoTawsA/YR2/gmTSBDTUsSYy6Tmu4mMJmZ0Q4zNkcfCS3g=="],
|
"@tanstack/router-core": ["@tanstack/router-core@1.140.0", "", { "dependencies": { "@tanstack/history": "1.140.0", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.0", "seroval-plugins": "^1.4.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-/Te/mlAzi5FEpZ9NF9RhVw/n+cWYLiCHpvevNKo7JPA8ZYWF58wkalPtNWSocftX4P+OIBNerFAW9UbLgSbvSw=="],
|
||||||
|
|
||||||
"@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.154.12", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.154.12", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-lvnP9cqknvSSkUjqQRVn61TcBhq72hCFFOzMwdFdFPTO8nMEXvYE6ZZJiXtivwcvsKmO6XVFLMXuJr/928gNkw=="],
|
"@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.140.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.140.0", "csstype": "^3.0.10", "solid-js": ">=1.9.5" }, "optionalPeers": ["csstype"] }, "sha512-jrfJZabe2ndKgoQWd7xLdfLFG/ew6hfPMjCmx2Ep+KBkSqfR19Pww8UtJ8Y0KcfTEFKL3YzVEsRS4EZDX3A1Qw=="],
|
||||||
|
|
||||||
"@tanstack/router-generator": ["@tanstack/router-generator@1.154.12", "", { "dependencies": { "@tanstack/router-core": "1.154.12", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-cjr3KS3Esnyh05CWl78KgK2Z9kTjeFasZXcSUrh//TzzU72eXQ+dzKppD3kMsjuyRfUxAfdufsR9GDNMMuLk9w=="],
|
"@tanstack/router-generator": ["@tanstack/router-generator@1.140.0", "", { "dependencies": { "@tanstack/router-core": "1.140.0", "@tanstack/router-utils": "1.140.0", "@tanstack/virtual-file-routes": "1.140.0", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-YYq/DSn7EkBboCySf87RDH3mNq3AfN18v4qHmre73KOdxUJchTZ4LC1+8vbO/1K/Uus2ZFXUDy7QX5KziNx08g=="],
|
||||||
|
|
||||||
"@tanstack/router-plugin": ["@tanstack/router-plugin@1.154.12", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.154.12", "@tanstack/router-generator": "1.154.12", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.154.12", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-YlFjrL5j7RbYT/B3RZZedbXOHXfqRV7b/qIGyojBaHsrIgKFGo4AHg/FyS50HJaHGQ27vvgWNSy/4Orrozbm0Q=="],
|
"@tanstack/router-plugin": ["@tanstack/router-plugin@1.140.0", "", { "dependencies": { "@babel/core": "^7.27.7", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", "@tanstack/router-core": "1.140.0", "@tanstack/router-generator": "1.140.0", "@tanstack/router-utils": "1.140.0", "@tanstack/virtual-file-routes": "1.140.0", "babel-dead-code-elimination": "^1.0.10", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.140.0", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-hUOOYTPLFS3LvGoPoQNk3BY3ZvPlVIgxnJT3JMJMdstLMT2RUYha3ddsaamZd4ONUSWmt+7N5OXmiG0v4XmzMw=="],
|
||||||
|
|
||||||
"@tanstack/router-utils": ["@tanstack/router-utils@1.154.7", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-61bGx32tMKuEpVRseu2sh1KQe8CfB7793Mch/kyQt0EP3tD7X0sXmimCl3truRiDGUtI0CaSoQV1NPjAII1RBA=="],
|
"@tanstack/router-utils": ["@tanstack/router-utils@1.140.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-gobraqMjkR5OO4nNbnwursGo08Idla6Yu30RspIA9IR1hv4WPJlxIyRWJcKjiQeXGyu5TuekLPUOHM46oood7w=="],
|
||||||
|
|
||||||
"@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="],
|
"@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="],
|
||||||
|
|
||||||
"@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="],
|
"@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.140.0", "", {}, "sha512-LVmd19QkxV3x40oHkuTii9ey3l5XDV+X8locO2p5zfVDUC+N58H2gA7cDUtVc9qtImncnz3WxQkO/6kM3PMx2w=="],
|
||||||
|
|
||||||
"@typed/id": ["@typed/id@0.17.2", "", { "peerDependencies": { "effect": "^3.14.7" } }, "sha512-z/Z14/moeu9x45IpkGaRwuvb+CQ3s3UCc/agcpZibTz1yPb3RgSDXx4rOHIuyb6hG6oNzqe9yY4GbbMq3Hb5Ug=="],
|
"@typed/id": ["@typed/id@0.17.2", "", { "peerDependencies": { "effect": "^3.14.7" } }, "sha512-z/Z14/moeu9x45IpkGaRwuvb+CQ3s3UCc/agcpZibTz1yPb3RgSDXx4rOHIuyb6hG6oNzqe9yY4GbbMq3Hb5Ug=="],
|
||||||
|
|
||||||
@@ -414,17 +423,17 @@
|
|||||||
|
|
||||||
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
"@types/bun": ["@types/bun@1.3.4", "", { "dependencies": { "bun-types": "1.3.4" } }, "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="],
|
"@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="],
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
||||||
|
|
||||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="],
|
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.47", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||||
|
|
||||||
@@ -436,9 +445,9 @@
|
|||||||
|
|
||||||
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
|
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
|
||||||
|
|
||||||
"babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="],
|
"babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.10", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA=="],
|
||||||
|
|
||||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.14", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg=="],
|
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.4", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA=="],
|
||||||
|
|
||||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||||
|
|
||||||
@@ -446,9 +455,9 @@
|
|||||||
|
|
||||||
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
"bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="],
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001764", "", {}, "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g=="],
|
"caniuse-lite": ["caniuse-lite@1.0.30001759", "", {}, "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw=="],
|
||||||
|
|
||||||
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||||
|
|
||||||
@@ -468,15 +477,15 @@
|
|||||||
|
|
||||||
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
|
||||||
|
|
||||||
"diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
|
"diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
|
||||||
|
|
||||||
"effect": ["effect@3.19.15", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-vzMmgfZKLcojmUjBdlQx+uaKryO7yULlRxjpDnHdnvcp1NPHxJyoM6IOXBLlzz2I/uPtZpGKavt5hBv7IvGZkA=="],
|
"effect": ["effect@3.19.9", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-taMXnfG/p+j7AmMOHHQaCHvjqwu9QBO3cxuZqL2dMG/yWcEMw0ZHruHe9B49OxtfKH/vKKDDKRhZ+1GJ2p5R5w=="],
|
||||||
|
|
||||||
"effect-fc": ["effect-fc@workspace:packages/effect-fc"],
|
"effect-fc": ["effect-fc@workspace:packages/effect-fc"],
|
||||||
|
|
||||||
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="],
|
"electron-to-chromium": ["electron-to-chromium@1.5.266", "", {}, "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg=="],
|
||||||
|
|
||||||
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
|
||||||
|
|
||||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||||
|
|
||||||
@@ -500,7 +509,7 @@
|
|||||||
|
|
||||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||||
|
|
||||||
"globals": ["globals@17.0.0", "", {}, "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw=="],
|
"globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="],
|
||||||
|
|
||||||
"goober": ["goober@2.1.18", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw=="],
|
"goober": ["goober@2.1.18", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw=="],
|
||||||
|
|
||||||
@@ -524,7 +533,7 @@
|
|||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
"msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="],
|
"msgpackr": ["msgpackr@1.11.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA=="],
|
||||||
|
|
||||||
"msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="],
|
"msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="],
|
||||||
|
|
||||||
@@ -538,7 +547,7 @@
|
|||||||
|
|
||||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||||
|
|
||||||
"npm-check-updates": ["npm-check-updates@19.3.1", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-v92fHH8fmf9VVmQwwL5JWpX8GDEe8BDyrz4w3GF6D6JBUZKpQNcTfBBgxVkCcAPzVUjCHSZEXYmZAAKfLTsDBA=="],
|
"npm-check-updates": ["npm-check-updates@19.1.2", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g=="],
|
||||||
|
|
||||||
"npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="],
|
"npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="],
|
||||||
|
|
||||||
@@ -550,15 +559,15 @@
|
|||||||
|
|
||||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||||
|
|
||||||
"prettier": ["prettier@3.8.0", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA=="],
|
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
|
||||||
|
|
||||||
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
||||||
|
|
||||||
"radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
|
"radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
|
||||||
|
|
||||||
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
"react": ["react@19.2.1", "", {}, "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw=="],
|
||||||
|
|
||||||
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
"react-dom": ["react-dom@19.2.1", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.1" } }, "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg=="],
|
||||||
|
|
||||||
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
"react-icons": ["react-icons@5.5.0", "", { "peerDependencies": { "react": "*" } }, "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw=="],
|
||||||
|
|
||||||
@@ -576,15 +585,17 @@
|
|||||||
|
|
||||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||||
|
|
||||||
"rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="],
|
"rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="],
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||||
|
|
||||||
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
"seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="],
|
"seroval": ["seroval@1.4.0", "", {}, "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg=="],
|
||||||
|
|
||||||
"seroval-plugins": ["seroval-plugins@1.4.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA=="],
|
"seroval-plugins": ["seroval-plugins@1.4.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ=="],
|
||||||
|
|
||||||
|
"solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="],
|
||||||
|
|
||||||
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||||
|
|
||||||
@@ -604,21 +615,21 @@
|
|||||||
|
|
||||||
"tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="],
|
"tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="],
|
||||||
|
|
||||||
"turbo": ["turbo@2.7.5", "", { "optionalDependencies": { "turbo-darwin-64": "2.7.5", "turbo-darwin-arm64": "2.7.5", "turbo-linux-64": "2.7.5", "turbo-linux-arm64": "2.7.5", "turbo-windows-64": "2.7.5", "turbo-windows-arm64": "2.7.5" }, "bin": { "turbo": "bin/turbo" } }, "sha512-7Imdmg37joOloTnj+DPrab9hIaQcDdJ5RwSzcauo/wMOSAgO+A/I/8b3hsGGs6PWQz70m/jkPgdqWsfNKtwwDQ=="],
|
"turbo": ["turbo@2.6.3", "", { "optionalDependencies": { "turbo-darwin-64": "2.6.3", "turbo-darwin-arm64": "2.6.3", "turbo-linux-64": "2.6.3", "turbo-linux-arm64": "2.6.3", "turbo-windows-64": "2.6.3", "turbo-windows-arm64": "2.6.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-bf6YKUv11l5Xfcmg76PyWoy/e2vbkkxFNBGJSnfdSXQC33ZiUfutYh6IXidc5MhsnrFkWfdNNLyaRk+kHMLlwA=="],
|
||||||
|
|
||||||
"turbo-darwin-64": ["turbo-darwin-64@2.7.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-nN3wfLLj4OES/7awYyyM7fkU8U8sAFxsXau2bYJwAWi6T09jd87DgHD8N31zXaJ7LcpyppHWPRI2Ov9MuZEwnQ=="],
|
"turbo-darwin-64": ["turbo-darwin-64@2.6.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlJJDc1CQ7SK5Y5qnl7AzpkvKSnpkfPmnA+HeU/sgny3oHZckPV2776ebO2M33CYDSor7+8HQwaodY++IINhYg=="],
|
||||||
|
|
||||||
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.7.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wCoDHMiTf3FgLAbZHDDx/unNNonSGhsF5AbbYODbxnpYyoKDpEYacUEPjZD895vDhNvYCH0Nnk24YsP4n/cD6g=="],
|
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.6.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MwVt7rBKiOK7zdYerenfCRTypefw4kZCue35IJga9CH1+S50+KTiCkT6LBqo0hHeoH2iKuI0ldTF2a0aB72z3w=="],
|
||||||
|
|
||||||
"turbo-linux-64": ["turbo-linux-64@2.7.5", "", { "os": "linux", "cpu": "x64" }, "sha512-KKPvhOmJMmzWj/yjeO4LywkQ85vOJyhru7AZk/+c4B6OUh/odQ++SiIJBSbTG2lm1CuV5gV5vXZnf/2AMlu3Zg=="],
|
"turbo-linux-64": ["turbo-linux-64@2.6.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cqpcw+dXxbnPtNnzeeSyWprjmuFVpHJqKcs7Jym5oXlu/ZcovEASUIUZVN3OGEM6Y/OTyyw0z09tOHNt5yBAVg=="],
|
||||||
|
|
||||||
"turbo-linux-arm64": ["turbo-linux-arm64@2.7.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-8PIva4L6BQhiPikUTds9lSFSHXVDAsEvV6QUlgwPsXrtXVQMVi6Sv9p+IxtlWQFvGkdYJUgX9GnK2rC030Xcmw=="],
|
"turbo-linux-arm64": ["turbo-linux-arm64@2.6.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-MterpZQmjXyr4uM7zOgFSFL3oRdNKeflY7nsjxJb2TklsYqiu3Z9pQ4zRVFFH8n0mLGna7MbQMZuKoWqqHb45w=="],
|
||||||
|
|
||||||
"turbo-windows-64": ["turbo-windows-64@2.7.5", "", { "os": "win32", "cpu": "x64" }, "sha512-rupskv/mkIUgQXzX/wUiK00mKMorQcK8yzhGFha/D5lm05FEnLx8dsip6rWzMcVpvh+4GUMA56PgtnOgpel2AA=="],
|
"turbo-windows-64": ["turbo-windows-64@2.6.3", "", { "os": "win32", "cpu": "x64" }, "sha512-biDU70v9dLwnBdLf+daoDlNJVvqOOP8YEjqNipBHzgclbQlXbsi6Gqqelp5er81Qo3BiRgmTNx79oaZQTPb07Q=="],
|
||||||
|
|
||||||
"turbo-windows-arm64": ["turbo-windows-arm64@2.7.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-G377Gxn6P42RnCzfMyDvsqQV7j69kVHKlhz9J4RhtJOB5+DyY4yYh/w0oTIxZQ4JRMmhjwLu3w9zncMoQ6nNDw=="],
|
"turbo-windows-arm64": ["turbo-windows-arm64@2.6.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-dDHVKpSeukah3VsI/xMEKeTnV9V9cjlpFSUs4bmsUiLu3Yv2ENlgVEZv65wxbeE0bh0jjpmElDT+P1KaCxArQQ=="],
|
||||||
|
|
||||||
"type-fest": ["type-fest@5.4.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ=="],
|
"type-fest": ["type-fest@5.3.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
@@ -626,7 +637,7 @@
|
|||||||
|
|
||||||
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
|
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
|
||||||
|
|
||||||
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
|
"update-browserslist-db": ["update-browserslist-db@1.2.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA=="],
|
||||||
|
|
||||||
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
|
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
|
||||||
|
|
||||||
@@ -634,7 +645,7 @@
|
|||||||
|
|
||||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||||
|
|
||||||
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
|
"vite": ["vite@7.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ=="],
|
||||||
|
|
||||||
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
|
"webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
|
||||||
|
|
||||||
@@ -647,5 +658,63 @@
|
|||||||
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||||
|
|
||||||
|
"solid-js/seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="],
|
||||||
|
|
||||||
|
"solid-js/seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="],
|
||||||
|
|
||||||
|
"tsx/esbuild": ["esbuild@0.27.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.1", "@esbuild/android-arm": "0.27.1", "@esbuild/android-arm64": "0.27.1", "@esbuild/android-x64": "0.27.1", "@esbuild/darwin-arm64": "0.27.1", "@esbuild/darwin-x64": "0.27.1", "@esbuild/freebsd-arm64": "0.27.1", "@esbuild/freebsd-x64": "0.27.1", "@esbuild/linux-arm": "0.27.1", "@esbuild/linux-arm64": "0.27.1", "@esbuild/linux-ia32": "0.27.1", "@esbuild/linux-loong64": "0.27.1", "@esbuild/linux-mips64el": "0.27.1", "@esbuild/linux-ppc64": "0.27.1", "@esbuild/linux-riscv64": "0.27.1", "@esbuild/linux-s390x": "0.27.1", "@esbuild/linux-x64": "0.27.1", "@esbuild/netbsd-arm64": "0.27.1", "@esbuild/netbsd-x64": "0.27.1", "@esbuild/openbsd-arm64": "0.27.1", "@esbuild/openbsd-x64": "0.27.1", "@esbuild/openharmony-arm64": "0.27.1", "@esbuild/sunos-x64": "0.27.1", "@esbuild/win32-arm64": "0.27.1", "@esbuild/win32-ia32": "0.27.1", "@esbuild/win32-x64": "0.27.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.1", "", { "os": "android", "cpu": "arm" }, "sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.1", "", { "os": "android", "cpu": "arm64" }, "sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.1", "", { "os": "android", "cpu": "x64" }, "sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.1", "", { "os": "linux", "cpu": "none" }, "sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.1", "", { "os": "linux", "cpu": "x64" }, "sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.1", "", { "os": "none", "cpu": "arm64" }, "sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.1", "", { "os": "none", "cpu": "x64" }, "sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ=="],
|
||||||
|
|
||||||
|
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.1", "", { "os": "win32", "cpu": "x64" }, "sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@effect-fc/monorepo",
|
"name": "@effect-fc/monorepo",
|
||||||
"packageManager": "bun@1.3.6",
|
"packageManager": "bun@1.3.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./packages/*"
|
"./packages/*"
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
"clean:modules": "turbo clean:modules && rm -rf node_modules"
|
"clean:modules": "turbo clean:modules && rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.3.11",
|
"@biomejs/biome": "^2.3.8",
|
||||||
"@effect/language-service": "^0.75.0",
|
"@effect/language-service": "^0.65.0",
|
||||||
"@types/bun": "^1.3.6",
|
"@types/bun": "^1.3.3",
|
||||||
"npm-check-updates": "^19.3.1",
|
"npm-check-updates": "^19.1.2",
|
||||||
"npm-sort": "^0.0.4",
|
"npm-sort": "^0.0.4",
|
||||||
"turbo": "^2.7.5",
|
"turbo": "^2.6.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
# Effect FC
|
# Effect FC
|
||||||
|
|
||||||
[Effect-TS](https://effect.website/) integration for React 19.2+ that allows you to write function components using Effect generators.
|
[Effect-TS](https://effect.website/) integration for React 19+ that allows you to write function components using Effect generators.
|
||||||
|
|
||||||
This library is in early development. While it is (almost) feature complete and mostly usable, expect bugs and quirks. Things are still being ironed out, so ideas and criticisms are more than welcome.
|
This library is in early development. While it is (almost) feature complete and mostly usable, expect bugs and quirks. Things are still being ironed out, so ideas and criticisms are more than welcome.
|
||||||
|
|
||||||
Documentation is currently being written. In the meantime, you can take a look at the `packages/example` directory.
|
Documentation is currently being written. In the meantime, you can take a look at the `packages/example` directory.
|
||||||
|
|
||||||
## Peer dependencies
|
## Peer dependencies
|
||||||
- `effect` 3.19+
|
- `effect` 3.15+
|
||||||
- `react` & `@types/react` 19.2+
|
- `react` & `@types/react` 19+
|
||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
- React Refresh doesn't work for Effect FC's yet. Page reload is required to view changes. Regular React components are unaffected.
|
- React Refresh doesn't work for Effect FC's yet. Page reload is required to view changes. Regular React components are unaffected.
|
||||||
|
|
||||||
## What writing components looks like
|
## What writing components looks like
|
||||||
```typescript
|
```typescript
|
||||||
export class Todos extends Component.make("Todos")(function*() {
|
import { Component } from "effect-fc"
|
||||||
|
import { useOnce, useSubscribables } from "effect-fc/Hooks"
|
||||||
|
import { Todo } from "./Todo"
|
||||||
|
import { TodosState } from "./TodosState.service"
|
||||||
|
|
||||||
|
|
||||||
|
export class Todos extends Component.makeUntraced("Todos")(function*() {
|
||||||
const state = yield* TodosState
|
const state = yield* TodosState
|
||||||
const [todos] = yield* useSubscribables(state.ref)
|
const [todos] = yield* useSubscribables(state.ref)
|
||||||
|
|
||||||
yield* useOnMount(() => Effect.andThen(
|
yield* useOnce(() => Effect.andThen(
|
||||||
Console.log("Todos mounted"),
|
Console.log("Todos mounted"),
|
||||||
Effect.addFinalizer(() => Console.log("Todos unmounted")),
|
Effect.addFinalizer(() => Console.log("Todos unmounted")),
|
||||||
))
|
))
|
||||||
@@ -43,8 +49,8 @@ export class Todos extends Component.make("Todos")(function*() {
|
|||||||
|
|
||||||
const TodosStateLive = TodosState.Default("todos")
|
const TodosStateLive = TodosState.Default("todos")
|
||||||
|
|
||||||
const Index = Component.make("Index")(function*() {
|
const Index = Component.makeUntraced("Index")(function*() {
|
||||||
const context = yield* useContext(TodosStateLive)
|
const context = yield* useContext(TodosStateLive, { finalizerExecutionMode: "fork" })
|
||||||
const TodosFC = yield* Effect.provide(Todos, context)
|
const TodosFC = yield* Effect.provide(Todos, context)
|
||||||
|
|
||||||
return <TodosFC />
|
return <TodosFC />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "effect-fc",
|
"name": "effect-fc",
|
||||||
"description": "Write React function components with Effect",
|
"description": "Write React function components with Effect",
|
||||||
"version": "0.2.3",
|
"version": "0.2.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"./README.md",
|
"./README.md",
|
||||||
@@ -37,9 +37,6 @@
|
|||||||
"clean:dist": "rm -rf dist",
|
"clean:dist": "rm -rf dist",
|
||||||
"clean:modules": "rm -rf node_modules"
|
"clean:modules": "rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@effect/platform-browser": "^0.74.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0",
|
"@types/react": "^19.2.0",
|
||||||
"effect": "^3.19.0",
|
"effect": "^3.19.0",
|
||||||
|
|||||||
@@ -1,49 +1,35 @@
|
|||||||
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
||||||
import { Effect, type Equivalence, Function, Predicate, Runtime, Scope } from "effect"
|
import { Effect, Function, Predicate, Runtime, Scope } from "effect"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as Component from "./Component.js"
|
import * as Component from "./Component.js"
|
||||||
|
|
||||||
|
|
||||||
export const AsyncTypeId: unique symbol = Symbol.for("@effect-fc/Async/Async")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/Async/Async")
|
||||||
export type AsyncTypeId = typeof AsyncTypeId
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
|
export interface Async extends Async.Options {
|
||||||
/**
|
readonly [TypeId]: TypeId
|
||||||
* A trait for `Component`'s that allows them running asynchronous effects.
|
|
||||||
*/
|
|
||||||
export interface Async extends AsyncPrototype, AsyncOptions {}
|
|
||||||
|
|
||||||
export interface AsyncPrototype {
|
|
||||||
readonly [AsyncTypeId]: AsyncTypeId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export namespace Async {
|
||||||
* Configuration options for `Async` components.
|
export interface Options {
|
||||||
*/
|
readonly defaultFallback?: React.ReactNode
|
||||||
export interface AsyncOptions {
|
}
|
||||||
/**
|
|
||||||
* The default fallback React node to display while the async operation is pending.
|
export type Props = Omit<React.SuspenseProps, "children">
|
||||||
* Used if no fallback is provided to the component when rendering.
|
|
||||||
*/
|
|
||||||
readonly defaultFallback?: React.ReactNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Props for `Async` components.
|
|
||||||
*/
|
|
||||||
export type AsyncProps = Omit<React.SuspenseProps, "children">
|
|
||||||
|
|
||||||
|
const AsyncProto = Object.freeze({
|
||||||
|
[TypeId]: TypeId,
|
||||||
|
|
||||||
export const AsyncPrototype: AsyncPrototype = Object.freeze({
|
makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
|
||||||
[AsyncTypeId]: AsyncTypeId,
|
|
||||||
|
|
||||||
asFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
|
|
||||||
this: Component.Component<P, A, E, R> & Async,
|
this: Component.Component<P, A, E, R> & Async,
|
||||||
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
|
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
|
||||||
) {
|
) {
|
||||||
const Inner = (props: { readonly promise: Promise<React.ReactNode> }) => React.use(props.promise)
|
const SuspenseInner = (props: { readonly promise: Promise<React.ReactNode> }) => React.use(props.promise)
|
||||||
|
|
||||||
return ({ fallback, name, ...props }: AsyncProps) => {
|
return ({ fallback, name, ...props }: Async.Props) => {
|
||||||
const promise = Runtime.runPromise(runtimeRef.current)(
|
const promise = Runtime.runPromise(runtimeRef.current)(
|
||||||
Effect.andThen(
|
Effect.andThen(
|
||||||
Component.useScope([], this),
|
Component.useScope([], this),
|
||||||
@@ -54,116 +40,45 @@ export const AsyncPrototype: AsyncPrototype = Object.freeze({
|
|||||||
return React.createElement(
|
return React.createElement(
|
||||||
React.Suspense,
|
React.Suspense,
|
||||||
{ fallback: fallback ?? this.defaultFallback, name },
|
{ fallback: fallback ?? this.defaultFallback, name },
|
||||||
React.createElement(Inner, { promise }),
|
React.createElement(SuspenseInner, { promise }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
} as const)
|
} as const)
|
||||||
|
|
||||||
/**
|
|
||||||
* An equivalence function for comparing `AsyncProps` that ignores the `fallback` property.
|
|
||||||
* Used by default by async components with `Memoized.memoized` applied.
|
|
||||||
*/
|
|
||||||
export const defaultPropsEquivalence: Equivalence.Equivalence<AsyncProps> = (
|
|
||||||
self: Record<string, unknown>,
|
|
||||||
that: Record<string, unknown>,
|
|
||||||
) => {
|
|
||||||
if (self === that)
|
|
||||||
return true
|
|
||||||
|
|
||||||
for (const key in self) {
|
export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, TypeId)
|
||||||
if (key === "fallback")
|
|
||||||
continue
|
|
||||||
if (!(key in that) || !Object.is(self[key], that[key]))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key in that) {
|
|
||||||
if (key === "fallback")
|
|
||||||
continue
|
|
||||||
if (!(key in self))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, AsyncTypeId)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a Component into an `Async` component that supports running asynchronous effects.
|
|
||||||
*
|
|
||||||
* Note: The component cannot have a prop named "promise" as it's reserved for internal use.
|
|
||||||
*
|
|
||||||
* @param self - The component to convert to an Async component
|
|
||||||
* @returns A new `Async` component with the same body, error, and context types as the input
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* const MyAsyncComponent = MyComponent.pipe(
|
|
||||||
* Async.async,
|
|
||||||
* )
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const async = <T extends Component.Component<any, any, any, any>>(
|
export const async = <T extends Component.Component<any, any, any, any>>(
|
||||||
self: T & (
|
self: T
|
||||||
"promise" extends keyof Component.Component.Props<T>
|
|
||||||
? "The 'promise' prop name is restricted for Async components. Please rename the 'promise' prop to something else."
|
|
||||||
: T
|
|
||||||
)
|
|
||||||
): (
|
): (
|
||||||
& Omit<T, keyof Component.Component.AsComponent<T>>
|
& Omit<T, keyof Component.Component.AsComponent<T>>
|
||||||
& Component.Component<
|
& Component.Component<
|
||||||
Component.Component.Props<T> & AsyncProps,
|
Component.Component.Props<T> & Async.Props,
|
||||||
Component.Component.Success<T>,
|
Component.Component.Success<T>,
|
||||||
Component.Component.Error<T>,
|
Component.Component.Error<T>,
|
||||||
Component.Component.Context<T>
|
Component.Component.Context<T>
|
||||||
>
|
>
|
||||||
& Async
|
& Async
|
||||||
) => Object.setPrototypeOf(
|
) => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, self, { propsEquivalence: defaultPropsEquivalence }),
|
Object.assign(function() {}, self),
|
||||||
Object.freeze(Object.setPrototypeOf(
|
Object.freeze(Object.setPrototypeOf(
|
||||||
Object.assign({}, AsyncPrototype),
|
Object.assign({}, AsyncProto),
|
||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies options to an Async component, returning a new Async component with the updated configuration.
|
|
||||||
*
|
|
||||||
* Supports both curried and uncurried application styles.
|
|
||||||
*
|
|
||||||
* @param self - The Async component to apply options to (in uncurried form)
|
|
||||||
* @param options - The options to apply to the component
|
|
||||||
* @returns An Async component with the applied options
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* // Curried
|
|
||||||
* const MyAsyncComponent = MyComponent.pipe(
|
|
||||||
* Async.async,
|
|
||||||
* Async.withOptions({ defaultFallback: <p>Loading...</p> }),
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* // Uncurried
|
|
||||||
* const MyAsyncComponent = Async.withOptions(
|
|
||||||
* Async.async(MyComponent),
|
|
||||||
* { defaultFallback: <p>Loading...</p> },
|
|
||||||
* )
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const withOptions: {
|
export const withOptions: {
|
||||||
<T extends Component.Component<any, any, any, any> & Async>(
|
<T extends Component.Component<any, any, any, any> & Async>(
|
||||||
options: Partial<AsyncOptions>
|
options: Partial<Async.Options>
|
||||||
): (self: T) => T
|
): (self: T) => T
|
||||||
<T extends Component.Component<any, any, any, any> & Async>(
|
<T extends Component.Component<any, any, any, any> & Async>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<AsyncOptions>,
|
options: Partial<Async.Options>,
|
||||||
): T
|
): T
|
||||||
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Async>(
|
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Async>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<AsyncOptions>,
|
options: Partial<Async.Options>,
|
||||||
): T => Object.setPrototypeOf(
|
): T => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, self, options),
|
Object.assign(function() {}, self, options),
|
||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */
|
/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */
|
||||||
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
||||||
import { Context, type Duration, Effect, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, identity, Layer, ManagedRuntime, Option, Pipeable, Predicate, Ref, Runtime, Scope, Tracer, type Utils } from "effect"
|
import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Tracer, type Utils } from "effect"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
|
import { Memoized } from "./index.js"
|
||||||
|
|
||||||
|
|
||||||
export const ComponentTypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/Component/Component")
|
||||||
export type ComponentTypeId = typeof ComponentTypeId
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an Effect-based React Component that integrates the Effect system with React.
|
|
||||||
*/
|
|
||||||
export interface Component<P extends {}, A extends React.ReactNode, E, R>
|
export interface Component<P extends {}, A extends React.ReactNode, E, R>
|
||||||
extends ComponentPrototype<P, A, R>, ComponentOptions {
|
extends
|
||||||
|
Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>,
|
||||||
|
Component.Options
|
||||||
|
{
|
||||||
new(_: never): Record<string, never>
|
new(_: never): Record<string, never>
|
||||||
readonly [ComponentTypeId]: ComponentTypeId
|
readonly [TypeId]: TypeId
|
||||||
readonly "~Props": P
|
readonly "~Props": P
|
||||||
readonly "~Success": A
|
readonly "~Success": A
|
||||||
readonly "~Error": E
|
readonly "~Error": E
|
||||||
readonly "~Context": R
|
readonly "~Context": R
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
readonly body: (props: P) => Effect.Effect<A, E, R>
|
readonly body: (props: P) => Effect.Effect<A, E, R>
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
makeFunctionComponent(
|
||||||
|
runtimeRef: React.Ref<Runtime.Runtime<Exclude<R, Scope.Scope>>>
|
||||||
|
): (props: P) => A
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace Component {
|
export declare namespace Component {
|
||||||
@@ -29,29 +36,41 @@ export declare namespace Component {
|
|||||||
export type Context<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer _A, infer _E, infer R>] ? R : never
|
export type Context<T extends Component<any, any, any, any>> = [T] extends [Component<infer _P, infer _A, infer _E, infer R>] ? R : never
|
||||||
|
|
||||||
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
|
export type AsComponent<T extends Component<any, any, any, any>> = Component<Props<T>, Success<T>, Error<T>, Context<T>>
|
||||||
|
|
||||||
|
export interface Options {
|
||||||
|
readonly displayName?: string
|
||||||
|
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
|
||||||
|
readonly finalizerExecutionDebounce: Duration.DurationInput
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ComponentPrototype<P extends {}, A extends React.ReactNode, R>
|
const ComponentProto = Object.freeze({
|
||||||
extends Pipeable.Pipeable {
|
...Effectable.CommitPrototype,
|
||||||
readonly [ComponentTypeId]: ComponentTypeId
|
[TypeId]: TypeId,
|
||||||
readonly use: Effect.Effect<(props: P) => A, never, Exclude<R, Scope.Scope>>
|
|
||||||
|
|
||||||
asFunctionComponent(
|
commit: Effect.fnUntraced(function* <P extends {}, A extends React.ReactNode, E, R>(
|
||||||
runtimeRef: React.Ref<Runtime.Runtime<Exclude<R, Scope.Scope>>>
|
this: Component<P, A, E, R>
|
||||||
): (props: P) => A
|
) {
|
||||||
|
// biome-ignore lint/style/noNonNullAssertion: React ref initialization
|
||||||
|
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
|
||||||
|
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
|
||||||
|
|
||||||
setFunctionComponentName(f: React.FC<P>): void
|
return yield* React.useState(() => Runtime.runSync(runtimeRef.current)(Effect.cachedFunction(
|
||||||
transformFunctionComponent(f: React.FC<P>): React.FC<P>
|
(_services: readonly any[]) => Effect.sync(() => {
|
||||||
}
|
const f: React.FC<P> = this.makeFunctionComponent(runtimeRef)
|
||||||
|
f.displayName = this.displayName ?? "Anonymous"
|
||||||
|
return Memoized.isMemoized(this)
|
||||||
|
? React.memo(f, this.propsAreEqual)
|
||||||
|
: f
|
||||||
|
}),
|
||||||
|
Equivalence.array(Equivalence.strict()),
|
||||||
|
)))[0](Array.from(
|
||||||
|
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
|
||||||
export const ComponentPrototype: ComponentPrototype<any, any, any> = Object.freeze({
|
makeFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
|
||||||
[ComponentTypeId]: ComponentTypeId,
|
|
||||||
...Pipeable.Prototype,
|
|
||||||
|
|
||||||
get use() { return use(this) },
|
|
||||||
|
|
||||||
asFunctionComponent<P extends {}, A extends React.ReactNode, E, R>(
|
|
||||||
this: Component<P, A, E, R>,
|
this: Component<P, A, E, R>,
|
||||||
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
|
runtimeRef: React.RefObject<Runtime.Runtime<Exclude<R, Scope.Scope>>>,
|
||||||
) {
|
) {
|
||||||
@@ -62,76 +81,17 @@ export const ComponentPrototype: ComponentPrototype<any, any, any> = Object.free
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
setFunctionComponentName<P extends {}, A extends React.ReactNode, E, R>(
|
|
||||||
this: Component<P, A, E, R>,
|
|
||||||
f: React.FC<P>,
|
|
||||||
) {
|
|
||||||
f.displayName = this.displayName ?? "Anonymous"
|
|
||||||
},
|
|
||||||
|
|
||||||
transformFunctionComponent: identity,
|
|
||||||
} as const)
|
} as const)
|
||||||
|
|
||||||
const use = Effect.fnUntraced(function* <P extends {}, A extends React.ReactNode, E, R>(
|
const defaultOptions: Component.Options = {
|
||||||
self: Component<P, A, E, R>
|
|
||||||
) {
|
|
||||||
// biome-ignore lint/style/noNonNullAssertion: React ref initialization
|
|
||||||
const runtimeRef = React.useRef<Runtime.Runtime<Exclude<R, Scope.Scope>>>(null!)
|
|
||||||
runtimeRef.current = yield* Effect.runtime<Exclude<R, Scope.Scope>>()
|
|
||||||
|
|
||||||
return yield* React.useState(() => Runtime.runSync(runtimeRef.current)(Effect.cachedFunction(
|
|
||||||
(_services: readonly any[]) => Effect.sync(() => {
|
|
||||||
const f: React.FC<P> = self.asFunctionComponent(runtimeRef)
|
|
||||||
self.setFunctionComponentName(f)
|
|
||||||
return self.transformFunctionComponent(f)
|
|
||||||
}),
|
|
||||||
Equivalence.array(Equivalence.strict()),
|
|
||||||
)))[0](Array.from(
|
|
||||||
Context.omit(...self.nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
|
|
||||||
))
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
export interface ComponentOptions {
|
|
||||||
/**
|
|
||||||
* Custom display name for the component in React DevTools and debugging utilities.
|
|
||||||
*/
|
|
||||||
readonly displayName?: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Context tags that should not trigger component remount when their values change.
|
|
||||||
*
|
|
||||||
* @default [Tracer.ParentSpan]
|
|
||||||
*/
|
|
||||||
readonly nonReactiveTags: readonly Context.Tag<any, any>[]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the execution strategy for finalizers when the component unmounts or its scope closes.
|
|
||||||
* Determines whether finalizers execute sequentially or in parallel.
|
|
||||||
*
|
|
||||||
* @default ExecutionStrategy.sequential
|
|
||||||
*/
|
|
||||||
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debounce duration before executing finalizers after component unmount.
|
|
||||||
* Prevents unnecessary cleanup work during rapid remount/unmount cycles,
|
|
||||||
* which is common in development and certain UI patterns.
|
|
||||||
*
|
|
||||||
* @default "100 millis"
|
|
||||||
*/
|
|
||||||
readonly finalizerExecutionDebounce: Duration.DurationInput
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultOptions: ComponentOptions = {
|
|
||||||
nonReactiveTags: [Tracer.ParentSpan],
|
|
||||||
finalizerExecutionStrategy: ExecutionStrategy.sequential,
|
finalizerExecutionStrategy: ExecutionStrategy.sequential,
|
||||||
finalizerExecutionDebounce: "100 millis",
|
finalizerExecutionDebounce: "100 millis",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nonReactiveTags = [Tracer.ParentSpan] as const
|
||||||
|
|
||||||
export const isComponent = (u: unknown): u is Component<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, ComponentTypeId)
|
|
||||||
|
export const isComponent = (u: unknown): u is Component<{}, React.ReactNode, unknown, unknown> => Predicate.hasProperty(u, TypeId)
|
||||||
|
|
||||||
export declare namespace make {
|
export declare namespace make {
|
||||||
export type Gen = {
|
export type Gen = {
|
||||||
@@ -358,53 +318,6 @@ export declare namespace make {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an Effect-FC Component using the same overloads and pipeline composition style as `Effect.fn`.
|
|
||||||
*
|
|
||||||
* This is the **recommended** approach for defining Effect-FC components. It provides comprehensive
|
|
||||||
* support for multiple component definition patterns:
|
|
||||||
*
|
|
||||||
* - **Generator syntax** (yield* style): Most ergonomic and readable approach for sequential operations
|
|
||||||
* - **Direct Effect return**: For simple components that return an Effect directly
|
|
||||||
* - **Chained transformation functions**: Enables Effect.fn-style pipelines for composable transformations
|
|
||||||
* - **Automatic tracing**: Optional tracing span creation with automatic `displayName` assignment
|
|
||||||
*
|
|
||||||
* When a `spanName` string is provided, the following occurs automatically:
|
|
||||||
* 1. A distributed tracing span is created with the specified name
|
|
||||||
* 2. The resulting React component receives `displayName = spanName` for DevTools visibility
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make("MyComponent")(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example As an opaque type using class syntax
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.make("MyComponent")(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* }) {}
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example Without name
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.make(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* }) {}
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example Using pipeline
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.make("MyComponent")(
|
|
||||||
* (props: { count: number }) => someEffect,
|
|
||||||
* Effect.map(value => <div>{value}</div>),
|
|
||||||
* ) {}
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const make: (
|
export const make: (
|
||||||
& make.Gen
|
& make.Gen
|
||||||
& make.NonGen
|
& make.NonGen
|
||||||
@@ -418,7 +331,7 @@ export const make: (
|
|||||||
Object.assign(function() {}, defaultOptions, {
|
Object.assign(function() {}, defaultOptions, {
|
||||||
body: Effect.fn(spanNameOrBody as any, ...pipeables),
|
body: Effect.fn(spanNameOrBody as any, ...pipeables),
|
||||||
}),
|
}),
|
||||||
ComponentPrototype,
|
ComponentProto,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -428,57 +341,11 @@ export const make: (
|
|||||||
body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []),
|
body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []),
|
||||||
displayName: spanNameOrBody,
|
displayName: spanNameOrBody,
|
||||||
}),
|
}),
|
||||||
ComponentPrototype,
|
ComponentProto,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an Effect-FC Component without automatic distributed tracing.
|
|
||||||
*
|
|
||||||
* This function provides the same API surface as `make`, but does not create automatic tracing spans.
|
|
||||||
* It follows the exact same overload structure as `Effect.fnUntraced`.
|
|
||||||
*
|
|
||||||
* Use this variant when you need:
|
|
||||||
* - Full manual control over tracing instrumentation
|
|
||||||
* - To reduce tracing overhead in deeply nested component hierarchies
|
|
||||||
* - To avoid span noise in performance-sensitive applications
|
|
||||||
*
|
|
||||||
* When a `spanName` string is provided, it is used **exclusively** as the React component's
|
|
||||||
* `displayName` for DevTools identification. No tracing span is created.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.makeUntraced("MyComponent")(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example As an opaque type using class syntax
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.makeUntraced("MyComponent")(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* }) {}
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example Without name
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.makeUntraced(function* (props: { count: number }) {
|
|
||||||
* const value = yield* someEffect
|
|
||||||
* return <div>{value}</div>
|
|
||||||
* }) {}
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example Using pipeline
|
|
||||||
* ```tsx
|
|
||||||
* class MyComponent extends Component.makeUntraced("MyComponent")(
|
|
||||||
* (props: { count: number }) => someEffect,
|
|
||||||
* Effect.map(value => <div>{value}</div>),
|
|
||||||
* ) {}
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const makeUntraced: (
|
export const makeUntraced: (
|
||||||
& make.Gen
|
& make.Gen
|
||||||
& make.NonGen
|
& make.NonGen
|
||||||
@@ -489,86 +356,33 @@ export const makeUntraced: (
|
|||||||
Object.assign(function() {}, defaultOptions, {
|
Object.assign(function() {}, defaultOptions, {
|
||||||
body: Effect.fnUntraced(spanNameOrBody as any, ...pipeables as []),
|
body: Effect.fnUntraced(spanNameOrBody as any, ...pipeables as []),
|
||||||
}),
|
}),
|
||||||
ComponentPrototype,
|
ComponentProto,
|
||||||
)
|
)
|
||||||
: (body: any, ...pipeables: any[]) => Object.setPrototypeOf(
|
: (body: any, ...pipeables: any[]) => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, defaultOptions, {
|
Object.assign(function() {}, defaultOptions, {
|
||||||
body: Effect.fnUntraced(body, ...pipeables as []),
|
body: Effect.fnUntraced(body, ...pipeables as []),
|
||||||
displayName: spanNameOrBody,
|
displayName: spanNameOrBody,
|
||||||
}),
|
}),
|
||||||
ComponentPrototype,
|
ComponentProto,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new component with modified configuration options while preserving all original behavior.
|
|
||||||
*
|
|
||||||
* This function allows you to customize component-level options such as finalizer execution strategy
|
|
||||||
* and debounce timing.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponentWithCustomOptions = MyComponent.pipe(
|
|
||||||
* Component.withOptions({
|
|
||||||
* finalizerExecutionStrategy: ExecutionStrategy.parallel,
|
|
||||||
* finalizerExecutionDebounce: "50 millis",
|
|
||||||
* })
|
|
||||||
* )
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const withOptions: {
|
export const withOptions: {
|
||||||
<T extends Component<any, any, any, any>>(
|
<T extends Component<any, any, any, any>>(
|
||||||
options: Partial<ComponentOptions>
|
options: Partial<Component.Options>
|
||||||
): (self: T) => T
|
): (self: T) => T
|
||||||
<T extends Component<any, any, any, any>>(
|
<T extends Component<any, any, any, any>>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<ComponentOptions>,
|
options: Partial<Component.Options>,
|
||||||
): T
|
): T
|
||||||
} = Function.dual(2, <T extends Component<any, any, any, any>>(
|
} = Function.dual(2, <T extends Component<any, any, any, any>>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<ComponentOptions>,
|
options: Partial<Component.Options>,
|
||||||
): T => Object.setPrototypeOf(
|
): T => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, self, options),
|
Object.assign(function() {}, self, options),
|
||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
))
|
))
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps an Effect-FC Component and converts it into a standard React function component,
|
|
||||||
* serving as an **entrypoint** into an Effect-FC component hierarchy.
|
|
||||||
*
|
|
||||||
* This is how Effect-FC components are integrated with the broader React ecosystem,
|
|
||||||
* particularly when:
|
|
||||||
* - Using client-side routers (TanStack Router, React Router, etc.)
|
|
||||||
* - Implementing lazy-loaded or code-split routes
|
|
||||||
* - Connecting to third-party libraries expecting standard React components
|
|
||||||
* - Creating component boundaries between Effect-FC and non-Effect-FC code
|
|
||||||
*
|
|
||||||
* The Effect runtime is obtained from the provided React Context.
|
|
||||||
*
|
|
||||||
* @param self - The Effect-FC Component to be rendered as a standard React component
|
|
||||||
* @param context - React Context providing the Effect Runtime for this component tree.
|
|
||||||
* Create this using the `ReactRuntime` module.
|
|
||||||
*
|
|
||||||
* @example Integration with TanStack Router
|
|
||||||
* ```tsx
|
|
||||||
* // Application root
|
|
||||||
* export const runtime = ReactRuntime.make(Layer.empty)
|
|
||||||
*
|
|
||||||
* function App() {
|
|
||||||
* return (
|
|
||||||
* <ReactRuntime.Provider runtime={runtime}>
|
|
||||||
* <RouterProvider router={router} />
|
|
||||||
* </ReactRuntime.Provider>
|
|
||||||
* )
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // Route definition
|
|
||||||
* export const Route = createFileRoute("/")({
|
|
||||||
* component: Component.withRuntime(HomePage, runtime.context)
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const withRuntime: {
|
export const withRuntime: {
|
||||||
<P extends {}, A extends React.ReactNode, E, R>(
|
<P extends {}, A extends React.ReactNode, E, R>(
|
||||||
context: React.Context<Runtime.Runtime<R>>,
|
context: React.Context<Runtime.Runtime<R>>,
|
||||||
@@ -582,18 +396,12 @@ export const withRuntime: {
|
|||||||
context: React.Context<Runtime.Runtime<R>>,
|
context: React.Context<Runtime.Runtime<R>>,
|
||||||
) => function WithRuntime(props: P) {
|
) => function WithRuntime(props: P) {
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
Runtime.runSync(React.useContext(context))(self.use),
|
Runtime.runSync(React.useContext(context))(self),
|
||||||
props,
|
props,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal Effect service that maintains a registry of scopes associated with React component instances.
|
|
||||||
*
|
|
||||||
* This service is used internally by the `useScope` hook to manage the lifecycle of component scopes,
|
|
||||||
* including tracking active scopes and coordinating their cleanup when components unmount or dependencies change.
|
|
||||||
*/
|
|
||||||
export class ScopeMap extends Effect.Service<ScopeMap>()("@effect-fc/Component/ScopeMap", {
|
export class ScopeMap extends Effect.Service<ScopeMap>()("@effect-fc/Component/ScopeMap", {
|
||||||
effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty<object, ScopeMap.Entry>()))
|
effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty<object, ScopeMap.Entry>()))
|
||||||
}) {}
|
}) {}
|
||||||
@@ -613,23 +421,6 @@ export declare namespace useScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that creates and manages a `Scope` for the current component instance.
|
|
||||||
*
|
|
||||||
* This hook establishes a new scope that is automatically closed when:
|
|
||||||
* - The component unmounts
|
|
||||||
* - The dependency array `deps` changes
|
|
||||||
*
|
|
||||||
* The scope provides a resource management boundary for any Effects executed within the component,
|
|
||||||
* ensuring proper cleanup of resources and execution of finalizers.
|
|
||||||
*
|
|
||||||
* @param deps - Dependency array following React.useEffect semantics. The scope is recreated
|
|
||||||
* whenever any dependency changes.
|
|
||||||
* @param options - Configuration for finalizer execution behavior, including execution strategy
|
|
||||||
* and debounce timing.
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces a `Scope` for resource management
|
|
||||||
*/
|
|
||||||
export const useScope = Effect.fnUntraced(function*(
|
export const useScope = Effect.fnUntraced(function*(
|
||||||
deps: React.DependencyList,
|
deps: React.DependencyList,
|
||||||
options?: useScope.Options,
|
options?: useScope.Options,
|
||||||
@@ -638,40 +429,43 @@ export const useScope = Effect.fnUntraced(function*(
|
|||||||
const runtimeRef = React.useRef<Runtime.Runtime<never>>(null!)
|
const runtimeRef = React.useRef<Runtime.Runtime<never>>(null!)
|
||||||
runtimeRef.current = yield* Effect.runtime()
|
runtimeRef.current = yield* Effect.runtime()
|
||||||
|
|
||||||
const { key, scope } = React.useMemo(() => Runtime.runSync(runtimeRef.current)(Effect.Do.pipe(
|
const scopeMap = yield* ScopeMap as unknown as Effect.Effect<ScopeMap>
|
||||||
Effect.bind("scopeMapRef", () => Effect.map(
|
|
||||||
ScopeMap as unknown as Effect.Effect<ScopeMap>,
|
const [key, scope] = React.useMemo(() => Runtime.runSync(runtimeRef.current)(Effect.andThen(
|
||||||
scopeMap => scopeMap.ref,
|
Effect.all([Effect.succeed({}), scopeMap.ref]),
|
||||||
)),
|
([key, map]) => Effect.andThen(
|
||||||
Effect.let("key", () => ({})),
|
Option.match(HashMap.get(map, key), {
|
||||||
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy)),
|
onSome: entry => Effect.succeed(entry.scope),
|
||||||
Effect.tap(({ scopeMapRef, key, scope }) =>
|
onNone: () => Effect.tap(
|
||||||
Ref.update(scopeMapRef, HashMap.set(key, {
|
Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy),
|
||||||
scope,
|
scope => Ref.update(scopeMap.ref, HashMap.set(key, {
|
||||||
closeFiber: Option.none(),
|
scope,
|
||||||
}))
|
closeFiber: Option.none(),
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
scope => [key, scope] as const,
|
||||||
),
|
),
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
|
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
|
||||||
)), deps)
|
)), deps)
|
||||||
|
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "key"
|
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "key"
|
||||||
React.useEffect(() => Runtime.runSync(runtimeRef.current)((ScopeMap as unknown as Effect.Effect<ScopeMap>).pipe(
|
React.useEffect(() => Runtime.runSync(runtimeRef.current)(scopeMap.ref.pipe(
|
||||||
Effect.map(scopeMap => scopeMap.ref),
|
Effect.andThen(HashMap.get(key)),
|
||||||
Effect.tap(ref => ref.pipe(
|
Effect.tap(entry => Option.match(entry.closeFiber, {
|
||||||
Effect.andThen(HashMap.get(key)),
|
onSome: fiber => Effect.andThen(
|
||||||
Effect.andThen(entry => Option.match(entry.closeFiber, {
|
Ref.update(scopeMap.ref, HashMap.set(key, { ...entry, closeFiber: Option.none() })),
|
||||||
onSome: Fiber.interruptFork,
|
Fiber.interruptFork(fiber),
|
||||||
onNone: () => Effect.void,
|
),
|
||||||
})),
|
onNone: () => Effect.void,
|
||||||
)),
|
})),
|
||||||
Effect.map(ref =>
|
Effect.map(({ scope }) =>
|
||||||
() => Runtime.runSync(runtimeRef.current)(Effect.andThen(
|
() => Runtime.runSync(runtimeRef.current)(Effect.andThen(
|
||||||
Effect.sleep(options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce).pipe(
|
Effect.forkDaemon(Effect.sleep(options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce).pipe(
|
||||||
Effect.andThen(Scope.close(scope, Exit.void)),
|
Effect.andThen(Scope.close(scope, Exit.void)),
|
||||||
Effect.onExit(() => Ref.update(ref, HashMap.remove(key))),
|
Effect.andThen(Ref.update(scopeMap.ref, HashMap.remove(key))),
|
||||||
Effect.forkDaemon,
|
)),
|
||||||
),
|
fiber => Ref.update(scopeMap.ref, HashMap.set(key, {
|
||||||
fiber => Ref.update(ref, HashMap.set(key, {
|
|
||||||
scope,
|
scope,
|
||||||
closeFiber: Option.some(fiber),
|
closeFiber: Option.some(fiber),
|
||||||
})),
|
})),
|
||||||
@@ -682,25 +476,6 @@ export const useScope = Effect.fnUntraced(function*(
|
|||||||
return scope
|
return scope
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that executes an Effect once when the component mounts and caches the result.
|
|
||||||
*
|
|
||||||
* This hook is useful for one-time initialization logic that should not be re-executed
|
|
||||||
* when the component re-renders. The Effect is executed exactly once during the component's
|
|
||||||
* initial mount, and the cached result is returned on all subsequent renders.
|
|
||||||
*
|
|
||||||
* @param f - A function that returns the Effect to execute on mount
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces the cached result of the Effect
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const initialData = yield* Component.useOnMount(() => getData)
|
|
||||||
* return <div>{initialData}</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useOnMount = Effect.fnUntraced(function* <A, E, R>(
|
export const useOnMount = Effect.fnUntraced(function* <A, E, R>(
|
||||||
f: () => Effect.Effect<A, E, R>
|
f: () => Effect.Effect<A, E, R>
|
||||||
): Effect.fn.Return<A, E, R> {
|
): Effect.fn.Return<A, E, R> {
|
||||||
@@ -712,35 +487,6 @@ export declare namespace useOnChange {
|
|||||||
export interface Options extends useScope.Options {}
|
export interface Options extends useScope.Options {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that executes an Effect whenever dependencies change and caches the result.
|
|
||||||
*
|
|
||||||
* This hook combines the dependency-tracking behavior of React.useEffect with Effect caching.
|
|
||||||
* The Effect is re-executed whenever any dependency in the `deps` array changes, and the result
|
|
||||||
* is cached until the next dependency change.
|
|
||||||
*
|
|
||||||
* A dedicated scope is created for each dependency change, ensuring proper resource cleanup:
|
|
||||||
* - The scope closes when dependencies change
|
|
||||||
* - The scope closes when the component unmounts
|
|
||||||
* - All finalizers are executed according to the configured execution strategy
|
|
||||||
*
|
|
||||||
* @param f - A function that returns the Effect to execute
|
|
||||||
* @param deps - Dependency array following React.useEffect semantics
|
|
||||||
* @param options - Configuration for scope and finalizer behavior
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces the cached result of the Effect
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function* (props: { userId: string }) {
|
|
||||||
* const userData = yield* Component.useOnChange(
|
|
||||||
* getUser(props.userId),
|
|
||||||
* [props.userId],
|
|
||||||
* )
|
|
||||||
* return <div>{userData.name}</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useOnChange = Effect.fnUntraced(function* <A, E, R>(
|
export const useOnChange = Effect.fnUntraced(function* <A, E, R>(
|
||||||
f: () => Effect.Effect<A, E, R>,
|
f: () => Effect.Effect<A, E, R>,
|
||||||
deps: React.DependencyList,
|
deps: React.DependencyList,
|
||||||
@@ -762,38 +508,6 @@ export declare namespace useReactEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that provides Effect-based semantics for React.useEffect.
|
|
||||||
*
|
|
||||||
* This hook bridges React's useEffect with the Effect system, allowing you to use Effects
|
|
||||||
* for React side effects while maintaining React's dependency tracking and lifecycle semantics.
|
|
||||||
*
|
|
||||||
* Unlike React.useEffect which uses imperative cleanup functions, this hook leverages the
|
|
||||||
* Effect Scope API for resource management. Cleanup logic is expressed declaratively through
|
|
||||||
* finalizers registered with the scope, providing better composability and error handling.
|
|
||||||
*
|
|
||||||
* @param f - A function that returns an Effect to execute as a side effect
|
|
||||||
* @param deps - Optional dependency array following React.useEffect semantics.
|
|
||||||
* If omitted, the effect runs after every render.
|
|
||||||
* @param options - Configuration for finalizer execution mode (sync or fork) and strategy
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces void
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function* (props: { id: string }) {
|
|
||||||
* yield* Component.useReactEffect(
|
|
||||||
* () => getNotificationStreamForUser(props.id).pipe(
|
|
||||||
* Stream.unwrap,
|
|
||||||
* Stream.runForEach(notification => Console.log(`Notification received: ${ notification }`),
|
|
||||||
* Effect.forkScoped,
|
|
||||||
* ),
|
|
||||||
* [props.id],
|
|
||||||
* )
|
|
||||||
* return <div>Subscribed to notifications for {props.id}</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useReactEffect = Effect.fnUntraced(function* <E, R>(
|
export const useReactEffect = Effect.fnUntraced(function* <E, R>(
|
||||||
f: () => Effect.Effect<void, E, R>,
|
f: () => Effect.Effect<void, E, R>,
|
||||||
deps?: React.DependencyList,
|
deps?: React.DependencyList,
|
||||||
@@ -830,45 +544,6 @@ export declare namespace useReactLayoutEffect {
|
|||||||
export interface Options extends useReactEffect.Options {}
|
export interface Options extends useReactEffect.Options {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that provides Effect-based semantics for React.useLayoutEffect.
|
|
||||||
*
|
|
||||||
* This hook is identical to `useReactEffect` but executes synchronously after DOM mutations
|
|
||||||
* but before the browser paints, following React.useLayoutEffect semantics.
|
|
||||||
*
|
|
||||||
* Use this hook when you need to:
|
|
||||||
* - Measure DOM elements (e.g., for layout calculations)
|
|
||||||
* - Synchronously update state based on DOM measurements
|
|
||||||
* - Avoid visual flicker from asynchronous updates
|
|
||||||
*
|
|
||||||
* Like `useReactEffect`, cleanup logic is handled through the Effect Scope API rather than
|
|
||||||
* imperative cleanup functions, providing declarative and composable resource management.
|
|
||||||
*
|
|
||||||
* @param f - A function that returns an Effect to execute as a layout side effect
|
|
||||||
* @param deps - Optional dependency array following React.useLayoutEffect semantics.
|
|
||||||
* If omitted, the effect runs after every render.
|
|
||||||
* @param options - Configuration for finalizer execution mode (sync or fork) and strategy
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces void
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const ref = React.useRef<HTMLDivElement>(null)
|
|
||||||
* yield* Component.useReactLayoutEffect(
|
|
||||||
* () => Effect.gen(function* () {
|
|
||||||
* const element = ref.current
|
|
||||||
* if (element) {
|
|
||||||
* const rect = element.getBoundingClientRect()
|
|
||||||
* yield* Console.log(`Element dimensions: ${ rect.width }x${ rect.height }`)
|
|
||||||
* }
|
|
||||||
* }),
|
|
||||||
* [],
|
|
||||||
* )
|
|
||||||
* return <div ref={ref}>Content</div>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useReactLayoutEffect = Effect.fnUntraced(function* <E, R>(
|
export const useReactLayoutEffect = Effect.fnUntraced(function* <E, R>(
|
||||||
f: () => Effect.Effect<void, E, R>,
|
f: () => Effect.Effect<void, E, R>,
|
||||||
deps?: React.DependencyList,
|
deps?: React.DependencyList,
|
||||||
@@ -879,84 +554,18 @@ export const useReactLayoutEffect = Effect.fnUntraced(function* <E, R>(
|
|||||||
React.useLayoutEffect(() => runReactEffect(runtime, f, options), deps)
|
React.useLayoutEffect(() => runReactEffect(runtime, f, options), deps)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that provides a synchronous function to execute Effects within the current runtime context.
|
|
||||||
*
|
|
||||||
* This hook returns a function that can execute Effects synchronously, blocking until completion.
|
|
||||||
* Use this when you need to run Effects from non-Effect code (e.g., event handlers, callbacks)
|
|
||||||
* within a component.
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces a function capable of synchronously executing Effects
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const runSync = yield* Component.useRunSync<SomeService>() // Specify required services
|
|
||||||
* const runSync = yield* Component.useRunSync() // Or no service requirements
|
|
||||||
*
|
|
||||||
* return <button onClick={() => runSync(someEffect)}>Click me</button>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useRunSync = <R = never>(): Effect.Effect<
|
export const useRunSync = <R = never>(): Effect.Effect<
|
||||||
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => A,
|
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => A,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | R
|
Scope.Scope | R
|
||||||
> => Effect.andThen(Effect.runtime(), Runtime.runSync)
|
> => Effect.andThen(Effect.runtime(), Runtime.runSync)
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that provides an asynchronous function to execute Effects within the current runtime context.
|
|
||||||
*
|
|
||||||
* This hook returns a function that executes Effects asynchronously, returning a Promise that resolves
|
|
||||||
* with the Effect's result. Use this when you need to run Effects from non-Effect code (e.g., event handlers,
|
|
||||||
* async callbacks) and want to handle the result asynchronously.
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces a function capable of asynchronously executing Effects
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const runPromise = yield* Component.useRunPromise<SomeService>() // Specify required services
|
|
||||||
* const runPromise = yield* Component.useRunPromise() // Or no service requirements
|
|
||||||
*
|
|
||||||
* return <button onClick={() => runPromise(someEffect)}>Click me</button>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useRunPromise = <R = never>(): Effect.Effect<
|
export const useRunPromise = <R = never>(): Effect.Effect<
|
||||||
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => Promise<A>,
|
<A, E = never>(effect: Effect.Effect<A, E, Scope.Scope | R>) => Promise<A>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | R
|
Scope.Scope | R
|
||||||
> => Effect.andThen(Effect.runtime(), context => Runtime.runPromise(context))
|
> => Effect.andThen(Effect.runtime(), context => Runtime.runPromise(context))
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that memoizes a function that returns an Effect, providing synchronous execution.
|
|
||||||
*
|
|
||||||
* This hook wraps a function that returns an Effect and returns a memoized version that:
|
|
||||||
* - Executes the Effect synchronously when called
|
|
||||||
* - Is memoized based on the provided dependency array
|
|
||||||
* - Maintains referential equality across renders when dependencies don't change
|
|
||||||
*
|
|
||||||
* Use this to create stable callback references for event handlers and other scenarios
|
|
||||||
* where you need to execute Effects synchronously from non-Effect code.
|
|
||||||
*
|
|
||||||
* @param f - A function that accepts arguments and returns an Effect
|
|
||||||
* @param deps - Dependency array. The memoized function is recreated when dependencies change.
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces a memoized function with the same signature as `f`
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function* (props: { onSave: (data: Data) => void }) {
|
|
||||||
* const handleSave = yield* Component.useCallbackSync(
|
|
||||||
* (data: Data) => Effect.sync(() => props.onSave(data)),
|
|
||||||
* [props.onSave],
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* return <button onClick={() => handleSave(myData)}>Save</button>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useCallbackSync = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
|
export const useCallbackSync = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
|
||||||
f: (...args: Args) => Effect.Effect<A, E, R>,
|
f: (...args: Args) => Effect.Effect<A, E, R>,
|
||||||
deps: React.DependencyList,
|
deps: React.DependencyList,
|
||||||
@@ -969,34 +578,6 @@ export const useCallbackSync = Effect.fnUntraced(function* <Args extends unknown
|
|||||||
return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps)
|
return React.useCallback((...args: Args) => Runtime.runSync(runtimeRef.current)(f(...args)), deps)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
|
||||||
* Effect hook that memoizes a function that returns an Effect, providing asynchronous execution.
|
|
||||||
*
|
|
||||||
* This hook wraps a function that returns an Effect and returns a memoized version that:
|
|
||||||
* - Executes the Effect asynchronously when called, returning a Promise
|
|
||||||
* - Is memoized based on the provided dependency array
|
|
||||||
* - Maintains referential equality across renders when dependencies don't change
|
|
||||||
*
|
|
||||||
* Use this to create stable callback references for async event handlers and other scenarios
|
|
||||||
* where you need to execute Effects asynchronously from non-Effect code.
|
|
||||||
*
|
|
||||||
* @param f - A function that accepts arguments and returns an Effect
|
|
||||||
* @param deps - Dependency array. The memoized function is recreated when dependencies change.
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces a memoized function that returns a Promise
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function* (props: { onSave: (data: Data) => void }) {
|
|
||||||
* const handleSave = yield* Component.useCallbackPromise(
|
|
||||||
* (data: Data) => Effect.promise(() => props.onSave(data)),
|
|
||||||
* [props.onSave],
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* return <button onClick={() => handleSave(myData)}>Save</button>
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const useCallbackPromise = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
|
export const useCallbackPromise = Effect.fnUntraced(function* <Args extends unknown[], A, E, R>(
|
||||||
f: (...args: Args) => Effect.Effect<A, E, R>,
|
f: (...args: Args) => Effect.Effect<A, E, R>,
|
||||||
deps: React.DependencyList,
|
deps: React.DependencyList,
|
||||||
@@ -1013,71 +594,10 @@ export declare namespace useContext {
|
|||||||
export interface Options extends useOnChange.Options {}
|
export interface Options extends useOnChange.Options {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export const useContext = <ROut, E, RIn>(
|
||||||
* Effect hook that constructs an Effect Layer and returns the resulting context.
|
|
||||||
*
|
|
||||||
* This hook creates a managed runtime from the provided layer and returns the context it produces.
|
|
||||||
* The layer is reconstructed whenever its value changes, so ensure the layer reference is stable
|
|
||||||
* (typically by memoizing it or defining it outside the component).
|
|
||||||
*
|
|
||||||
* The hook automatically manages the layer's lifecycle:
|
|
||||||
* - The layer is built when the component mounts or when the layer reference changes
|
|
||||||
* - Resources are properly released when the component unmounts or dependencies change
|
|
||||||
* - Finalizers are executed according to the configured execution strategy
|
|
||||||
*
|
|
||||||
* @param layer - The Effect Layer to construct. Should be a stable reference to avoid unnecessary
|
|
||||||
* reconstruction. Consider memoizing with React.useMemo if defined inline.
|
|
||||||
* @param options - Configuration for scope and finalizer behavior
|
|
||||||
*
|
|
||||||
* @returns An Effect that produces the context created by the layer
|
|
||||||
*
|
|
||||||
* @throws If the layer contains asynchronous effects, the component must be wrapped with `Async.async`
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* const MyLayer = Layer.succeed(MyService, new MyServiceImpl())
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const context = yield* Component.useContextFromLayer(MyLayer)
|
|
||||||
* const Sub = yield* SubComponent.use.pipe(
|
|
||||||
* Effect.provide(context)
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* return <Sub />
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example With memoized layer
|
|
||||||
* ```tsx
|
|
||||||
* const MyComponent = Component.make(function*(props: { id: string })) {
|
|
||||||
* const context = yield* Component.useContextFromLayer(
|
|
||||||
* React.useMemo(() => Layer.succeed(MyService, new MyServiceImpl(props.id)), [props.id])
|
|
||||||
* )
|
|
||||||
* const Sub = yield* SubComponent.use.pipe(
|
|
||||||
* Effect.provide(context)
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* return <Sub />
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example With async layer
|
|
||||||
* ```tsx
|
|
||||||
* const MyAsyncLayer = Layer.effect(MyService, someAsyncEffect)
|
|
||||||
* const MyComponent = Component.make(function*() {
|
|
||||||
* const context = yield* Component.useContextFromLayer(MyAsyncLayer)
|
|
||||||
* const Sub = yield* SubComponent.use.pipe(
|
|
||||||
* Effect.provide(context)
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* return <Sub />
|
|
||||||
* }).pipe(
|
|
||||||
* Async.async // Required to handle async layer effects
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
export const useContextFromLayer = <ROut, E, RIn>(
|
|
||||||
layer: Layer.Layer<ROut, E, RIn>,
|
layer: Layer.Layer<ROut, E, RIn>,
|
||||||
options?: useContext.Options,
|
options?: useContext.Options,
|
||||||
): Effect.Effect<Context.Context<ROut>, E, RIn | Scope.Scope> => useOnChange(() => Effect.context<RIn>().pipe(
|
): Effect.Effect<Context.Context<ROut>, E, Scope.Scope | RIn> => useOnChange(() => Effect.context<RIn>().pipe(
|
||||||
Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))),
|
Effect.map(context => ManagedRuntime.make(Layer.provide(layer, Layer.succeedContext(context)))),
|
||||||
Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)),
|
Effect.tap(runtime => Effect.addFinalizer(() => runtime.disposeEffect)),
|
||||||
Effect.andThen(runtime => runtime.runtimeEffect),
|
Effect.andThen(runtime => runtime.runtimeEffect),
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { type Cause, Context, Effect, Exit, Layer, Option, Pipeable, Predicate, PubSub, type Queue, type Scope, Supervisor } from "effect"
|
import { type Cause, Context, Effect, Exit, Layer, Option, Pipeable, Predicate, PubSub, type Queue, type Scope, Supervisor } from "effect"
|
||||||
|
|
||||||
|
|
||||||
export const ErrorObserverTypeId: unique symbol = Symbol.for("@effect-fc/ErrorObserver/ErrorObserver")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/ErrorObserver/ErrorObserver")
|
||||||
export type ErrorObserverTypeId = typeof ErrorObserverTypeId
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
export interface ErrorObserver<in out E = never> extends Pipeable.Pipeable {
|
export interface ErrorObserver<in out E = never> extends Pipeable.Pipeable {
|
||||||
readonly [ErrorObserverTypeId]: ErrorObserverTypeId
|
readonly [TypeId]: TypeId
|
||||||
handle<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
|
handle<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
|
||||||
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ErrorObserver = <E = never>(): Context.Tag<ErrorObserver, ErrorObserver<E>> => Context.GenericTag("@effect-fc/ErrorObserver/ErrorObserver")
|
export const ErrorObserver = <E = never>(): Context.Tag<ErrorObserver, ErrorObserver<E>> => Context.GenericTag("@effect-fc/ErrorObserver/ErrorObserver")
|
||||||
|
|
||||||
export class ErrorObserverImpl<in out E = never>
|
class ErrorObserverImpl<in out E = never>
|
||||||
extends Pipeable.Class() implements ErrorObserver<E> {
|
extends Pipeable.Class() implements ErrorObserver<E> {
|
||||||
readonly [ErrorObserverTypeId]: ErrorObserverTypeId = ErrorObserverTypeId
|
readonly [TypeId]: TypeId = TypeId
|
||||||
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -29,7 +29,7 @@ extends Pipeable.Class() implements ErrorObserver<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ErrorObserverSupervisorImpl extends Supervisor.AbstractSupervisor<void> {
|
class ErrorObserverSupervisorImpl extends Supervisor.AbstractSupervisor<void> {
|
||||||
readonly value = Effect.void
|
readonly value = Effect.void
|
||||||
constructor(readonly pubsub: PubSub.PubSub<Cause.Cause<never>>) {
|
constructor(readonly pubsub: PubSub.PubSub<Cause.Cause<never>>) {
|
||||||
super()
|
super()
|
||||||
@@ -43,7 +43,7 @@ export class ErrorObserverSupervisorImpl extends Supervisor.AbstractSupervisor<v
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const isErrorObserver = (u: unknown): u is ErrorObserver<unknown> => Predicate.hasProperty(u, ErrorObserverTypeId)
|
export const isErrorObserver = (u: unknown): u is ErrorObserver<unknown> => Predicate.hasProperty(u, TypeId)
|
||||||
|
|
||||||
export const layer: Layer.Layer<ErrorObserver> = Layer.unwrapEffect(Effect.map(
|
export const layer: Layer.Layer<ErrorObserver> = Layer.unwrapEffect(Effect.map(
|
||||||
PubSub.unbounded<Cause.Cause<never>>(),
|
PubSub.unbounded<Cause.Cause<never>>(),
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ extends Pipeable.Pipeable {
|
|||||||
field<const P extends PropertyPath.Paths<I>>(
|
field<const P extends PropertyPath.Paths<I>>(
|
||||||
path: P
|
path: P
|
||||||
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>>
|
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>>
|
||||||
|
|
||||||
readonly run: Effect.Effect<void>
|
|
||||||
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException>
|
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +68,7 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
Option.isSome(value) &&
|
Option.isSome(value) &&
|
||||||
Option.isNone(error) &&
|
Option.isNone(error) &&
|
||||||
Option.isNone(validationFiber) &&
|
Option.isNone(validationFiber) &&
|
||||||
!(Result.isRunning(result) || Result.hasRefreshingFlag(result))
|
!(Result.isRunning(result) || Result.isRefreshing(result))
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -91,49 +89,7 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly canSubmit: Subscribable.Subscribable<boolean>
|
readonly canSubmit: Subscribable.Subscribable<boolean, never, never>
|
||||||
|
|
||||||
get run(): Effect.Effect<void> {
|
|
||||||
return this.runSemaphore.withPermits(1)(Stream.runForEach(
|
|
||||||
this.encodedValue.changes.pipe(
|
|
||||||
Option.isSome(this.debounce) ? Stream.debounce(this.debounce.value) : identity
|
|
||||||
),
|
|
||||||
|
|
||||||
encodedValue => this.validationFiber.pipe(
|
|
||||||
Effect.andThen(Option.match({
|
|
||||||
onSome: Fiber.interrupt,
|
|
||||||
onNone: () => Effect.void,
|
|
||||||
})),
|
|
||||||
Effect.andThen(
|
|
||||||
Effect.forkScoped(Effect.onExit(
|
|
||||||
Schema.decode(this.schema, { errors: "all" })(encodedValue),
|
|
||||||
exit => Effect.andThen(
|
|
||||||
Exit.matchEffect(exit, {
|
|
||||||
onSuccess: v => Effect.andThen(
|
|
||||||
Ref.set(this.value, Option.some(v)),
|
|
||||||
Ref.set(this.error, Option.none()),
|
|
||||||
),
|
|
||||||
onFailure: c => Option.match(Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), {
|
|
||||||
onSome: e => Ref.set(this.error, Option.some(e)),
|
|
||||||
onNone: () => Effect.void,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Ref.set(this.validationFiber, Option.none()),
|
|
||||||
),
|
|
||||||
)).pipe(
|
|
||||||
Effect.tap(fiber => Ref.set(this.validationFiber, Option.some(fiber))),
|
|
||||||
Effect.andThen(Fiber.join),
|
|
||||||
Effect.andThen(value => this.autosubmit
|
|
||||||
? Effect.asVoid(Effect.forkScoped(this.submitValue(value)))
|
|
||||||
: Effect.void
|
|
||||||
),
|
|
||||||
Effect.forkScoped,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
get submit(): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException> {
|
get submit(): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException> {
|
||||||
return this.value.pipe(
|
return this.value.pipe(
|
||||||
@@ -141,7 +97,6 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
Effect.andThen(value => this.submitValue(value)),
|
Effect.andThen(value => this.submitValue(value)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
submitValue(value: A): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>> {
|
submitValue(value: A): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>> {
|
||||||
return Effect.whenEffect(
|
return Effect.whenEffect(
|
||||||
Effect.tap(
|
Effect.tap(
|
||||||
@@ -203,6 +158,51 @@ export const make = Effect.fnUntraced(function* <A, I = A, R = never, MA = void,
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const run = <A, I, R, MA, ME, MR, MP>(
|
||||||
|
self: Form<A, I, R, MA, ME, MR, MP>
|
||||||
|
): Effect.Effect<void> => {
|
||||||
|
const _self = self as FormImpl<A, I, R, MA, ME, MR, MP>
|
||||||
|
return _self.runSemaphore.withPermits(1)(Stream.runForEach(
|
||||||
|
_self.encodedValue.changes.pipe(
|
||||||
|
Option.isSome(_self.debounce) ? Stream.debounce(_self.debounce.value) : identity
|
||||||
|
),
|
||||||
|
|
||||||
|
encodedValue => _self.validationFiber.pipe(
|
||||||
|
Effect.andThen(Option.match({
|
||||||
|
onSome: Fiber.interrupt,
|
||||||
|
onNone: () => Effect.void,
|
||||||
|
})),
|
||||||
|
Effect.andThen(
|
||||||
|
Effect.forkScoped(Effect.onExit(
|
||||||
|
Schema.decode(_self.schema, { errors: "all" })(encodedValue),
|
||||||
|
exit => Effect.andThen(
|
||||||
|
Exit.matchEffect(exit, {
|
||||||
|
onSuccess: v => Effect.andThen(
|
||||||
|
Ref.set(_self.value, Option.some(v)),
|
||||||
|
Ref.set(_self.error, Option.none()),
|
||||||
|
),
|
||||||
|
onFailure: c => Option.match(Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), {
|
||||||
|
onSome: e => Ref.set(_self.error, Option.some(e)),
|
||||||
|
onNone: () => Effect.void,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Ref.set(_self.validationFiber, Option.none()),
|
||||||
|
),
|
||||||
|
)).pipe(
|
||||||
|
Effect.tap(fiber => Ref.set(_self.validationFiber, Option.some(fiber))),
|
||||||
|
Effect.andThen(Fiber.join),
|
||||||
|
Effect.andThen(value => _self.autosubmit
|
||||||
|
? Effect.asVoid(Effect.forkScoped(_self.submitValue(value)))
|
||||||
|
: Effect.void
|
||||||
|
),
|
||||||
|
Effect.forkScoped,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Effect.provide(_self.context),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
export declare namespace service {
|
export declare namespace service {
|
||||||
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
||||||
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
||||||
@@ -216,7 +216,7 @@ export const service = <A, I = A, R = never, MA = void, ME = never, MR = never,
|
|||||||
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP>
|
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP>
|
||||||
> => Effect.tap(
|
> => Effect.tap(
|
||||||
make(options),
|
make(options),
|
||||||
form => Effect.forkScoped(form.run),
|
form => Effect.forkScoped(run(form)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -271,21 +271,22 @@ export const makeFormField = <A, I, R, MA, ME, MR, MP, const P extends PropertyP
|
|||||||
self: Form<A, I, R, MA, ME, MR, MP>,
|
self: Form<A, I, R, MA, ME, MR, MP>,
|
||||||
path: P,
|
path: P,
|
||||||
): FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>> => {
|
): FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>> => {
|
||||||
|
const _self = self as FormImpl<A, I, R, MA, ME, MR, MP>
|
||||||
return new FormFieldImpl(
|
return new FormFieldImpl(
|
||||||
Subscribable.mapEffect(self.value, Option.match({
|
Subscribable.mapEffect(_self.value, Option.match({
|
||||||
onSome: v => Option.map(PropertyPath.get(v, path), Option.some),
|
onSome: v => Option.map(PropertyPath.get(v, path), Option.some),
|
||||||
onNone: () => Option.some(Option.none()),
|
onNone: () => Option.some(Option.none()),
|
||||||
})),
|
})),
|
||||||
SubscriptionSubRef.makeFromPath(self.encodedValue, path),
|
SubscriptionSubRef.makeFromPath(_self.encodedValue, path),
|
||||||
Subscribable.mapEffect(self.error, Option.match({
|
Subscribable.mapEffect(_self.error, Option.match({
|
||||||
onSome: flow(
|
onSome: flow(
|
||||||
ParseResult.ArrayFormatter.formatError,
|
ParseResult.ArrayFormatter.formatError,
|
||||||
Effect.map(Array.filter(issue => PropertyPath.equivalence(issue.path, path))),
|
Effect.map(Array.filter(issue => PropertyPath.equivalence(issue.path, path))),
|
||||||
),
|
),
|
||||||
onNone: () => Effect.succeed([]),
|
onNone: () => Effect.succeed([]),
|
||||||
})),
|
})),
|
||||||
Subscribable.map(self.validationFiber, Option.isSome),
|
Subscribable.map(_self.validationFiber, Option.isSome),
|
||||||
Subscribable.map(self.mutation.result, result => Result.isRunning(result) || Result.hasRefreshingFlag(result)),
|
Subscribable.map(_self.mutation.result, result => Result.isRunning(result) || Result.isRefreshing(result)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,111 +1,50 @@
|
|||||||
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
|
||||||
import { type Equivalence, Function, Predicate } from "effect"
|
import { type Equivalence, Function, Predicate } from "effect"
|
||||||
import * as React from "react"
|
|
||||||
import type * as Component from "./Component.js"
|
import type * as Component from "./Component.js"
|
||||||
|
|
||||||
|
|
||||||
export const MemoizedTypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/Memoized/Memoized")
|
||||||
export type MemoizedTypeId = typeof MemoizedTypeId
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
|
export interface Memoized<P> extends Memoized.Options<P> {
|
||||||
/**
|
readonly [TypeId]: TypeId
|
||||||
* A trait for `Component`'s that uses `React.memo` to optimize re-renders based on prop equality.
|
|
||||||
*
|
|
||||||
* @template P The props type of the component
|
|
||||||
*/
|
|
||||||
export interface Memoized<P> extends MemoizedPrototype, MemoizedOptions<P> {}
|
|
||||||
|
|
||||||
export interface MemoizedPrototype {
|
|
||||||
readonly [MemoizedTypeId]: MemoizedTypeId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export namespace Memoized {
|
||||||
* Configuration options for Memoized components.
|
export interface Options<P> {
|
||||||
*
|
readonly propsAreEqual?: Equivalence.Equivalence<P>
|
||||||
* @template P The props type of the component
|
}
|
||||||
*/
|
|
||||||
export interface MemoizedOptions<P> {
|
|
||||||
/**
|
|
||||||
* An optional equivalence function for comparing component props.
|
|
||||||
* If provided, this function is used by React.memo to determine if props have changed.
|
|
||||||
* Returns `true` if props are equivalent (no re-render), `false` if they differ (re-render).
|
|
||||||
*/
|
|
||||||
readonly propsEquivalence?: Equivalence.Equivalence<P>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const MemoizedPrototype: MemoizedPrototype = Object.freeze({
|
const MemoizedProto = Object.freeze({
|
||||||
[MemoizedTypeId]: MemoizedTypeId,
|
[TypeId]: TypeId
|
||||||
|
|
||||||
transformFunctionComponent<P extends {}>(
|
|
||||||
this: Memoized<P>,
|
|
||||||
f: React.FC<P>,
|
|
||||||
) {
|
|
||||||
return React.memo(f, this.propsEquivalence)
|
|
||||||
},
|
|
||||||
} as const)
|
} as const)
|
||||||
|
|
||||||
|
|
||||||
export const isMemoized = (u: unknown): u is Memoized<unknown> => Predicate.hasProperty(u, MemoizedTypeId)
|
export const isMemoized = (u: unknown): u is Memoized<unknown> => Predicate.hasProperty(u, TypeId)
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a Component into a `Memoized` component that optimizes re-renders using `React.memo`.
|
|
||||||
*
|
|
||||||
* @param self - The component to convert to a Memoized component
|
|
||||||
* @returns A new `Memoized` component with the same body, error, and context types as the input
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* const MyMemoizedComponent = MyComponent.pipe(
|
|
||||||
* Memoized.memoized,
|
|
||||||
* )
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const memoized = <T extends Component.Component<any, any, any, any>>(
|
export const memoized = <T extends Component.Component<any, any, any, any>>(
|
||||||
self: T
|
self: T
|
||||||
): T & Memoized<Component.Component.Props<T>> => Object.setPrototypeOf(
|
): T & Memoized<Component.Component.Props<T>> => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, self),
|
Object.assign(function() {}, self),
|
||||||
Object.freeze(Object.setPrototypeOf(
|
Object.freeze(Object.setPrototypeOf(
|
||||||
Object.assign({}, MemoizedPrototype),
|
Object.assign({}, MemoizedProto),
|
||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies options to a Memoized component, returning a new Memoized component with the updated configuration.
|
|
||||||
*
|
|
||||||
* Supports both curried and uncurried application styles.
|
|
||||||
*
|
|
||||||
* @param self - The Memoized component to apply options to (in uncurried form)
|
|
||||||
* @param options - The options to apply to the component
|
|
||||||
* @returns A Memoized component with the applied options
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* // Curried
|
|
||||||
* const MyMemoizedComponent = MyComponent.pipe(
|
|
||||||
* Memoized.memoized,
|
|
||||||
* Memoized.withOptions({ propsEquivalence: (a, b) => a.id === b.id }),
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* // Uncurried
|
|
||||||
* const MyMemoizedComponent = Memoized.withOptions(
|
|
||||||
* Memoized.memoized(MyComponent),
|
|
||||||
* { propsEquivalence: (a, b) => a.id === b.id },
|
|
||||||
* )
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export const withOptions: {
|
export const withOptions: {
|
||||||
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
||||||
options: Partial<MemoizedOptions<Component.Component.Props<T>>>
|
options: Partial<Memoized.Options<Component.Component.Props<T>>>
|
||||||
): (self: T) => T
|
): (self: T) => T
|
||||||
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
<T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<MemoizedOptions<Component.Component.Props<T>>>,
|
options: Partial<Memoized.Options<Component.Component.Props<T>>>,
|
||||||
): T
|
): T
|
||||||
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
} = Function.dual(2, <T extends Component.Component<any, any, any, any> & Memoized<any>>(
|
||||||
self: T,
|
self: T,
|
||||||
options: Partial<MemoizedOptions<Component.Component.Props<T>>>,
|
options: Partial<Memoized.Options<Component.Component.Props<T>>>,
|
||||||
): T => Object.setPrototypeOf(
|
): T => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, self, options),
|
Object.assign(function() {}, self, options),
|
||||||
Object.getPrototypeOf(self),
|
Object.getPrototypeOf(self),
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ extends Pipeable.Pipeable {
|
|||||||
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
||||||
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
||||||
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
||||||
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
|
|
||||||
|
|
||||||
mutate(key: K): Effect.Effect<Result.Final<A, E, P>>
|
mutate(key: K): Effect.Effect<Result.Final<A, E, P>>
|
||||||
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
|
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
|
||||||
@@ -31,30 +30,27 @@ extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
|
|||||||
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly context: Context.Context<Scope.Scope | R>,
|
readonly context: Context.Context<Scope.Scope | NoInfer<R>>,
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
||||||
readonly initialProgress: P,
|
readonly initialProgress: P,
|
||||||
|
|
||||||
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
|
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
|
||||||
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
|
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
|
||||||
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
||||||
readonly latestFinalResult: SubscriptionRef.SubscriptionRef<Option.Option<Result.Final<A, E, P>>>,
|
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
mutate(key: K): Effect.Effect<Result.Final<A, E, P>> {
|
mutate(key: K): Effect.Effect<Result.Final<A, E, P>> {
|
||||||
return SubscriptionRef.set(this.latestKey, Option.some(key)).pipe(
|
return SubscriptionRef.set(this.latestKey, Option.some(key)).pipe(
|
||||||
Effect.andThen(this.start(key)),
|
Effect.andThen(Effect.provide(this.start(key), this.context)),
|
||||||
Effect.andThen(sub => this.watch(sub)),
|
Effect.andThen(sub => this.watch(sub)),
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
|
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
|
||||||
return SubscriptionRef.set(this.latestKey, Option.some(key)).pipe(
|
return Effect.andThen(
|
||||||
Effect.andThen(this.start(key)),
|
SubscriptionRef.set(this.latestKey, Option.some(key)),
|
||||||
Effect.tap(sub => Effect.forkScoped(this.watch(sub))),
|
Effect.provide(this.start(key), this.context)
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +59,12 @@ extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
|
|||||||
never,
|
never,
|
||||||
Scope.Scope | R
|
Scope.Scope | R
|
||||||
> {
|
> {
|
||||||
return this.latestFinalResult.pipe(
|
return this.result.pipe(
|
||||||
Effect.andThen(initial => Result.unsafeForkEffect(
|
Effect.map(previous => Result.isFinal(previous)
|
||||||
|
? previous
|
||||||
|
: undefined
|
||||||
|
),
|
||||||
|
Effect.andThen(previous => Result.unsafeForkEffect(
|
||||||
Effect.onExit(this.f(key), () => Effect.andThen(
|
Effect.onExit(this.f(key), () => Effect.andThen(
|
||||||
Effect.all([Effect.fiberId, this.fiber]),
|
Effect.all([Effect.fiberId, this.fiber]),
|
||||||
([currentFiberId, fiber]) => Option.match(fiber, {
|
([currentFiberId, fiber]) => Option.match(fiber, {
|
||||||
@@ -72,12 +72,12 @@ extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
|
|||||||
? SubscriptionRef.set(this.fiber, Option.none())
|
? SubscriptionRef.set(this.fiber, Option.none())
|
||||||
: Effect.void,
|
: Effect.void,
|
||||||
onNone: () => Effect.void,
|
onNone: () => Effect.void,
|
||||||
}),
|
})
|
||||||
)),
|
)),
|
||||||
|
|
||||||
{
|
{
|
||||||
initial: Option.isSome(initial) ? Result.willFetch(initial.value) : Result.initial(),
|
|
||||||
initialProgress: this.initialProgress,
|
initialProgress: this.initialProgress,
|
||||||
|
previous,
|
||||||
} as Result.unsafeForkEffect.Options<A, E, P>,
|
} as Result.unsafeForkEffect.Options<A, E, P>,
|
||||||
)),
|
)),
|
||||||
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
|
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
|
||||||
@@ -88,14 +88,14 @@ extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
|
|||||||
watch(
|
watch(
|
||||||
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
|
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
|
||||||
): Effect.Effect<Result.Final<A, E, P>> {
|
): Effect.Effect<Result.Final<A, E, P>> {
|
||||||
return sub.get.pipe(
|
return Effect.andThen(
|
||||||
Effect.andThen(initial => Stream.runFoldEffect(
|
sub.get,
|
||||||
sub.changes,
|
initial => Stream.runFoldEffect(
|
||||||
|
Stream.filter(sub.changes, Predicate.not(Result.isInitial)),
|
||||||
initial,
|
initial,
|
||||||
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
|
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
|
||||||
) as Effect.Effect<Result.Final<A, E, P>>),
|
),
|
||||||
Effect.tap(result => SubscriptionRef.set(this.latestFinalResult, Option.some(result))),
|
) as Effect.Effect<Result.Final<A, E, P>>
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +123,5 @@ export const make = Effect.fnUntraced(function* <const K extends Mutation.AnyKey
|
|||||||
yield* SubscriptionRef.make(Option.none<K>()),
|
yield* SubscriptionRef.make(Option.none<K>()),
|
||||||
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
|
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
|
||||||
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
||||||
yield* SubscriptionRef.make(Option.none<Result.Final<A, E, P>>()),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type Cause, type Context, type Duration, Effect, Equal, Fiber, identity, Option, Pipeable, Predicate, type Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
import { type Cause, type Context, DateTime, type Duration, Effect, Exit, Fiber, HashMap, identity, Option, Pipeable, Predicate, type Scope, Stream, Subscribable, SubscriptionRef } from "effect"
|
||||||
import * as QueryClient from "./QueryClient.js"
|
import * as QueryClient from "./QueryClient.js"
|
||||||
import * as Result from "./Result.js"
|
import * as Result from "./Result.js"
|
||||||
|
|
||||||
@@ -6,54 +6,49 @@ import * as Result from "./Result.js"
|
|||||||
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
|
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
|
||||||
export type QueryTypeId = typeof QueryTypeId
|
export type QueryTypeId = typeof QueryTypeId
|
||||||
|
|
||||||
export interface Query<in out K extends Query.AnyKey, in out A, in out KE = never, in out KR = never, in out E = never, in out R = never, in out P = never>
|
export interface Query<in out K extends Query.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
|
||||||
extends Pipeable.Pipeable {
|
extends Pipeable.Pipeable {
|
||||||
readonly [QueryTypeId]: QueryTypeId
|
readonly [QueryTypeId]: QueryTypeId
|
||||||
|
|
||||||
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | KR | R>
|
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>
|
||||||
readonly key: Stream.Stream<K, KE, KR>
|
readonly key: Stream.Stream<K>
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>
|
readonly f: (key: K) => Effect.Effect<A, E, R>
|
||||||
readonly initialProgress: P
|
readonly initialProgress: P
|
||||||
|
|
||||||
readonly staleTime: Duration.DurationInput
|
readonly staleTime: Duration.DurationInput
|
||||||
readonly refreshOnWindowFocus: boolean
|
|
||||||
|
|
||||||
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
||||||
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
||||||
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
||||||
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
|
|
||||||
|
|
||||||
readonly run: Effect.Effect<void>
|
readonly run: Effect.Effect<void>
|
||||||
fetch(key: K): Effect.Effect<Result.Final<A, E, P>>
|
fetch(key: K): Effect.Effect<Result.Final<A, E, P>>
|
||||||
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
|
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
|
||||||
|
readonly refetch: Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException>
|
||||||
|
readonly refetchSubscribable: Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException>
|
||||||
readonly refresh: Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException>
|
readonly refresh: Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException>
|
||||||
readonly refreshSubscribable: Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException>
|
readonly refreshSubscribable: Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException>
|
||||||
|
|
||||||
readonly invalidateCache: Effect.Effect<void>
|
|
||||||
invalidateCacheEntry(key: K): Effect.Effect<void>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace Query {
|
export declare namespace Query {
|
||||||
export type AnyKey = readonly any[]
|
export type AnyKey = readonly any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryImpl<in out K extends Query.AnyKey, in out A, in out KE = never, in out KR = never, in out E = never, in out R = never, in out P = never>
|
export class QueryImpl<in out K extends Query.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
|
||||||
extends Pipeable.Class() implements Query<K, A, KE, KR, E, R, P> {
|
extends Pipeable.Class() implements Query<K, A, E, R, P> {
|
||||||
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
|
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | KR | R>,
|
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>,
|
||||||
readonly key: Stream.Stream<K, KE, KR>,
|
readonly key: Stream.Stream<K>,
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
||||||
readonly initialProgress: P,
|
readonly initialProgress: P,
|
||||||
|
|
||||||
readonly staleTime: Duration.DurationInput,
|
readonly staleTime: Duration.DurationInput,
|
||||||
readonly refreshOnWindowFocus: boolean,
|
|
||||||
|
|
||||||
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
|
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
|
||||||
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
|
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
|
||||||
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
||||||
readonly latestFinalResult: SubscriptionRef.SubscriptionRef<Option.Option<Result.Final<A, E, P>>>,
|
|
||||||
|
|
||||||
readonly runSemaphore: Effect.Semaphore,
|
readonly runSemaphore: Effect.Semaphore,
|
||||||
) {
|
) {
|
||||||
@@ -61,27 +56,16 @@ extends Pipeable.Class() implements Query<K, A, KE, KR, E, R, P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get run(): Effect.Effect<void> {
|
get run(): Effect.Effect<void> {
|
||||||
return Effect.all([
|
return Stream.runForEach(this.key, key => this.interrupt.pipe(
|
||||||
Stream.runForEach(this.key, key => this.fetchSubscribable(key)),
|
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
|
||||||
|
Effect.andThen(this.startCached(key, Result.initial(), false)),
|
||||||
Effect.promise(() => import("@effect/platform-browser")).pipe(
|
Effect.andThen(sub => Effect.forkScoped(this.watch(sub))),
|
||||||
Effect.andThen(({ BrowserStream }) => this.refreshOnWindowFocus
|
|
||||||
? Stream.runForEach(
|
|
||||||
BrowserStream.fromEventListenerWindow("focus"),
|
|
||||||
() => this.refreshSubscribable,
|
|
||||||
)
|
|
||||||
: Effect.void
|
|
||||||
),
|
|
||||||
Effect.catchAllDefect(() => Effect.void),
|
|
||||||
),
|
|
||||||
], { concurrency: "unbounded" }).pipe(
|
|
||||||
Effect.ignore,
|
|
||||||
this.runSemaphore.withPermits(1),
|
|
||||||
Effect.provide(this.context),
|
Effect.provide(this.context),
|
||||||
)
|
this.runSemaphore.withPermits(1),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
get interrupt(): Effect.Effect<void> {
|
get interrupt(): Effect.Effect<void, never, never> {
|
||||||
return Effect.andThen(this.fiber, Option.match({
|
return Effect.andThen(this.fiber, Option.match({
|
||||||
onSome: Fiber.interrupt,
|
onSome: Fiber.interrupt,
|
||||||
onNone: () => Effect.void,
|
onNone: () => Effect.void,
|
||||||
@@ -91,226 +75,181 @@ extends Pipeable.Class() implements Query<K, A, KE, KR, E, R, P> {
|
|||||||
fetch(key: K): Effect.Effect<Result.Final<A, E, P>> {
|
fetch(key: K): Effect.Effect<Result.Final<A, E, P>> {
|
||||||
return this.interrupt.pipe(
|
return this.interrupt.pipe(
|
||||||
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
|
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
|
||||||
Effect.andThen(this.latestFinalResult),
|
Effect.andThen(Effect.provide(this.startCached(key, Result.initial(), false), this.context)),
|
||||||
Effect.andThen(previous => this.startCached(key, Option.isSome(previous)
|
Effect.andThen(sub => this.watch(sub)),
|
||||||
? Result.willFetch(previous.value) as Result.Final<A, E, P>
|
|
||||||
: Result.initial()
|
|
||||||
)),
|
|
||||||
Effect.andThen(sub => this.watch(key, sub)),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
|
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
|
||||||
return this.interrupt.pipe(
|
return this.interrupt.pipe(
|
||||||
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
|
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))),
|
||||||
Effect.andThen(this.latestFinalResult),
|
Effect.andThen(Effect.provide(this.startCached(key, Result.initial(), false), this.context)),
|
||||||
Effect.andThen(previous => this.startCached(key, Option.isSome(previous)
|
)
|
||||||
? Result.willFetch(previous.value) as Result.Final<A, E, P>
|
}
|
||||||
: Result.initial()
|
get refetch(): Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException> {
|
||||||
)),
|
return this.interrupt.pipe(
|
||||||
Effect.tap(sub => Effect.forkScoped(this.watch(key, sub))),
|
Effect.andThen(this.latestKey),
|
||||||
Effect.provide(this.context),
|
Effect.andThen(identity),
|
||||||
|
Effect.andThen(key => Effect.provide(this.start(key, Result.initial(), false), this.context)),
|
||||||
|
Effect.andThen(sub => this.watch(sub)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
get refetchSubscribable(): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException> {
|
||||||
|
return this.interrupt.pipe(
|
||||||
|
Effect.andThen(this.latestKey),
|
||||||
|
Effect.andThen(identity),
|
||||||
|
Effect.andThen(key => Effect.provide(this.start(key, Result.initial(), false), this.context)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get refresh(): Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException> {
|
get refresh(): Effect.Effect<Result.Final<A, E, P>, Cause.NoSuchElementException> {
|
||||||
return this.interrupt.pipe(
|
return this.interrupt.pipe(
|
||||||
Effect.andThen(Effect.Do),
|
Effect.andThen(this.latestKey),
|
||||||
Effect.bind("latestKey", () => Effect.andThen(this.latestKey, identity)),
|
Effect.andThen(identity),
|
||||||
Effect.bind("latestFinalResult", () => this.latestFinalResult),
|
Effect.andThen(key => Effect.provide(this.start(key, Result.initial(), true), this.context)),
|
||||||
Effect.bind("subscribable", ({ latestKey, latestFinalResult }) =>
|
Effect.andThen(sub => this.watch(sub)),
|
||||||
this.startCached(latestKey, Option.isSome(latestFinalResult)
|
|
||||||
? Result.willRefresh(latestFinalResult.value) as Result.Final<A, E, P>
|
|
||||||
: Result.initial()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Effect.andThen(({ latestKey, subscribable }) => this.watch(latestKey, subscribable)),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
get refreshSubscribable(): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>, Cause.NoSuchElementException> {
|
||||||
get refreshSubscribable(): Effect.Effect<
|
|
||||||
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
|
||||||
Cause.NoSuchElementException
|
|
||||||
> {
|
|
||||||
return this.interrupt.pipe(
|
return this.interrupt.pipe(
|
||||||
Effect.andThen(Effect.Do),
|
Effect.andThen(this.latestKey),
|
||||||
Effect.bind("latestKey", () => Effect.andThen(this.latestKey, identity)),
|
Effect.andThen(identity),
|
||||||
Effect.bind("latestFinalResult", () => this.latestFinalResult),
|
Effect.andThen(key => Effect.provide(this.start(key, Result.initial(), true), this.context)),
|
||||||
Effect.bind("subscribable", ({ latestKey, latestFinalResult }) =>
|
|
||||||
this.startCached(latestKey, Option.isSome(latestFinalResult)
|
|
||||||
? Result.willRefresh(latestFinalResult.value) as Result.Final<A, E, P>
|
|
||||||
: Result.initial()
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Effect.tap(({ latestKey, subscribable }) => Effect.forkScoped(this.watch(latestKey, subscribable))),
|
|
||||||
Effect.map(({ subscribable }) => subscribable),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
startCached(
|
startCached(
|
||||||
key: K,
|
key: K,
|
||||||
initial: Result.Initial | Result.Final<A, E, P>,
|
initial: Result.Result<A, E, P>,
|
||||||
|
refresh: boolean,
|
||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | QueryClient.QueryClient | R
|
Scope.Scope | QueryClient.QueryClient | R
|
||||||
> {
|
> {
|
||||||
return Effect.andThen(this.getCacheEntry(key), Option.match({
|
return Effect.andThen(this.getCacheEntry(key), Option.match({
|
||||||
onSome: entry => Effect.andThen(
|
onSome: entry => QueryClient.isQueryClientCacheEntryStale(entry, this.staleTime)
|
||||||
QueryClient.isQueryClientCacheEntryStale(entry),
|
? Effect.map(
|
||||||
isStale => isStale
|
SubscriptionRef.set(this.result, entry.result as Result.Result<A, E, P>),
|
||||||
? this.start(key, Result.willRefresh(entry.result) as Result.Final<A, E, P>)
|
() => Subscribable.make({
|
||||||
: Effect.succeed(Subscribable.make({
|
|
||||||
get: Effect.succeed(entry.result as Result.Result<A, E, P>),
|
get: Effect.succeed(entry.result as Result.Result<A, E, P>),
|
||||||
get changes() { return Stream.make(entry.result as Result.Result<A, E, P>) },
|
get changes() { return Stream.empty },
|
||||||
})),
|
}),
|
||||||
),
|
)
|
||||||
onNone: () => this.start(key, initial),
|
: this.start(key, Result.optimistic(entry.result) as Result.Result<A, E, P>, false),
|
||||||
|
onNone: () => this.start(key, initial, refresh),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
start(
|
start(
|
||||||
key: K,
|
key: K,
|
||||||
initial: Result.Initial | Result.Final<A, E, P>,
|
initial: Result.Result<A, E, P>,
|
||||||
|
refresh: boolean,
|
||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | R
|
Scope.Scope | QueryClient.QueryClient | R
|
||||||
> {
|
> {
|
||||||
return Result.unsafeForkEffect(
|
return this.result.pipe(
|
||||||
Effect.onExit(this.f(key), () => Effect.andThen(
|
Effect.map(previous => Result.isFinal(previous) ? previous : undefined),
|
||||||
Effect.all([Effect.fiberId, this.fiber]),
|
Effect.andThen(previous => Result.unsafeForkEffect(
|
||||||
([currentFiberId, fiber]) => Option.match(fiber, {
|
Effect.onExit(this.f(key), exit => Effect.andThen(
|
||||||
onSome: v => Equal.equals(currentFiberId, v.id())
|
Exit.isSuccess(exit)
|
||||||
? SubscriptionRef.set(this.fiber, Option.none())
|
? this.updateCacheEntry(key, Result.succeed(exit.value))
|
||||||
: Effect.void,
|
: Effect.void,
|
||||||
onNone: () => Effect.void,
|
SubscriptionRef.set(this.fiber, Option.none()),
|
||||||
}),
|
)),
|
||||||
|
{
|
||||||
|
initial,
|
||||||
|
initialProgress: this.initialProgress,
|
||||||
|
refresh: refresh && previous,
|
||||||
|
previous,
|
||||||
|
} as Result.unsafeForkEffect.Options<A, E, P>,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
{
|
|
||||||
initial,
|
|
||||||
initialProgress: this.initialProgress,
|
|
||||||
} as Result.unsafeForkEffect.Options<A, E, P>,
|
|
||||||
).pipe(
|
|
||||||
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
|
Effect.tap(([, fiber]) => SubscriptionRef.set(this.fiber, Option.some(fiber))),
|
||||||
Effect.map(([sub]) => sub),
|
Effect.map(([sub]) => sub),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
key: K,
|
|
||||||
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
|
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
|
||||||
): Effect.Effect<Result.Final<A, E, P>, never, QueryClient.QueryClient> {
|
): Effect.Effect<Result.Final<A, E, P>> {
|
||||||
return sub.get.pipe(
|
return Effect.andThen(
|
||||||
Effect.andThen(initial => Stream.runFoldEffect(
|
sub.get,
|
||||||
sub.changes,
|
initial => Stream.runFoldEffect(
|
||||||
|
Stream.filter(sub.changes, Predicate.not(Result.isInitial)),
|
||||||
initial,
|
initial,
|
||||||
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
|
(_, result) => Effect.as(SubscriptionRef.set(this.result, result), result),
|
||||||
) as Effect.Effect<Result.Final<A, E, P>>),
|
|
||||||
Effect.tap(result => SubscriptionRef.set(this.latestFinalResult, Option.some(result))),
|
|
||||||
Effect.tap(result => Result.isSuccess(result)
|
|
||||||
? this.setCacheEntry(key, result)
|
|
||||||
: Effect.void
|
|
||||||
),
|
),
|
||||||
)
|
) as Effect.Effect<Result.Final<A, E, P>>
|
||||||
}
|
|
||||||
|
|
||||||
makeCacheKey(key: K): QueryClient.QueryClientCacheKey {
|
|
||||||
return new QueryClient.QueryClientCacheKey(key, this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCacheEntry(
|
getCacheEntry(
|
||||||
key: K
|
key: K
|
||||||
): Effect.Effect<Option.Option<QueryClient.QueryClientCacheEntry>, never, QueryClient.QueryClient> {
|
): Effect.Effect<Option.Option<QueryClient.QueryClientCacheEntry>, never, QueryClient.QueryClient> {
|
||||||
return Effect.andThen(
|
return QueryClient.QueryClient.pipe(
|
||||||
Effect.all([
|
Effect.andThen(client => client.cache),
|
||||||
Effect.succeed(this.makeCacheKey(key)),
|
Effect.map(HashMap.get(new QueryClient.QueryClientCacheKey(key, this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>))),
|
||||||
QueryClient.QueryClient,
|
|
||||||
]),
|
|
||||||
([key, client]) => client.getCacheEntry(key),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCacheEntry(
|
updateCacheEntry(
|
||||||
key: K,
|
key: K,
|
||||||
result: Result.Success<A>,
|
result: Result.Success<A>,
|
||||||
): Effect.Effect<QueryClient.QueryClientCacheEntry, never, QueryClient.QueryClient> {
|
): Effect.Effect<QueryClient.QueryClientCacheEntry, never, QueryClient.QueryClient> {
|
||||||
return Effect.andThen(
|
return Effect.Do.pipe(
|
||||||
Effect.all([
|
Effect.bind("client", () => QueryClient.QueryClient),
|
||||||
Effect.succeed(this.makeCacheKey(key)),
|
Effect.bind("now", () => DateTime.now),
|
||||||
QueryClient.QueryClient,
|
Effect.let("entry", ({ now }) => new QueryClient.QueryClientCacheEntry(result, now)),
|
||||||
]),
|
Effect.tap(({ client, entry }) => SubscriptionRef.update(
|
||||||
([key, client]) => client.setCacheEntry(key, result, this.staleTime),
|
client.cache,
|
||||||
)
|
HashMap.set(new QueryClient.QueryClientCacheKey(key, this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>), entry),
|
||||||
}
|
)),
|
||||||
|
Effect.map(({ entry }) => entry),
|
||||||
get invalidateCache(): Effect.Effect<void> {
|
|
||||||
return QueryClient.QueryClient.pipe(
|
|
||||||
Effect.andThen(client => client.invalidateCacheEntries(this.f as (key: Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>)),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidateCacheEntry(key: K): Effect.Effect<void> {
|
|
||||||
return Effect.all([
|
|
||||||
Effect.succeed(this.makeCacheKey(key)),
|
|
||||||
QueryClient.QueryClient,
|
|
||||||
]).pipe(
|
|
||||||
Effect.andThen(([key, client]) => client.invalidateCacheEntry(key)),
|
|
||||||
Effect.provide(this.context),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isQuery = (u: unknown): u is Query<readonly unknown[], unknown> => Predicate.hasProperty(u, QueryTypeId)
|
export const isQuery = (u: unknown): u is Query<readonly unknown[], unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, QueryTypeId)
|
||||||
|
|
||||||
export declare namespace make {
|
export declare namespace make {
|
||||||
export interface Options<K extends Query.AnyKey, A, KE = never, KR = never, E = never, R = never, P = never> {
|
export interface Options<K extends Query.AnyKey, A, E = never, R = never, P = never> {
|
||||||
readonly key: Stream.Stream<K, KE, KR>
|
readonly key: Stream.Stream<K>
|
||||||
readonly f: (key: NoInfer<K>) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
|
readonly f: (key: NoInfer<K>) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
|
||||||
readonly initialProgress?: P
|
readonly initialProgress?: P
|
||||||
readonly staleTime?: Duration.DurationInput
|
readonly staleTime?: Duration.DurationInput
|
||||||
readonly refreshOnWindowFocus?: boolean
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const make = Effect.fnUntraced(function* <K extends Query.AnyKey, A, KE = never, KR = never, E = never, R = never, P = never>(
|
export const make = Effect.fnUntraced(function* <K extends Query.AnyKey, A, E = never, R = never, P = never>(
|
||||||
options: make.Options<K, A, KE, KR, E, R, P>
|
options: make.Options<K, A, E, R, P>
|
||||||
): Effect.fn.Return<
|
): Effect.fn.Return<
|
||||||
Query<K, A, KE, KR, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | QueryClient.QueryClient | KR | Result.forkEffect.OutputContext<A, E, R, P>
|
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
|
||||||
> {
|
> {
|
||||||
const client = yield* QueryClient.QueryClient
|
const client = yield* QueryClient.QueryClient
|
||||||
|
|
||||||
return new QueryImpl<K, A, KE, KR, E, Result.forkEffect.OutputContext<A, E, R, P>, P>(
|
return new QueryImpl(
|
||||||
yield* Effect.context<Scope.Scope | QueryClient.QueryClient | KR | Result.forkEffect.OutputContext<A, E, R, P>>(),
|
yield* Effect.context<Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>>(),
|
||||||
options.key,
|
options.key,
|
||||||
options.f as any,
|
options.f as any,
|
||||||
options.initialProgress as P,
|
options.initialProgress as P,
|
||||||
|
|
||||||
options.staleTime ?? client.defaultStaleTime,
|
options.staleTime ?? client.defaultStaleTime,
|
||||||
options.refreshOnWindowFocus ?? client.defaultRefreshOnWindowFocus,
|
|
||||||
|
|
||||||
yield* SubscriptionRef.make(Option.none<K>()),
|
yield* SubscriptionRef.make(Option.none<K>()),
|
||||||
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
|
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
|
||||||
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
||||||
yield* SubscriptionRef.make(Option.none<Result.Final<A, E, P>>()),
|
|
||||||
|
|
||||||
yield* Effect.makeSemaphore(1),
|
yield* Effect.makeSemaphore(1),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const service = <K extends Query.AnyKey, A, KE = never, KR = never, E = never, R = never, P = never>(
|
export const service = <K extends Query.AnyKey, A, E = never, R = never, P = never>(
|
||||||
options: make.Options<K, A, KE, KR, E, R, P>
|
options: make.Options<K, A, E, R, P>
|
||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
Query<K, A, KE, KR, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | QueryClient.QueryClient | KR | Result.forkEffect.OutputContext<A, E, R, P>
|
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
|
||||||
> => Effect.tap(
|
> => Effect.tap(
|
||||||
make(options),
|
make(options),
|
||||||
query => Effect.forkScoped(query.run),
|
query => Effect.forkScoped(query.run),
|
||||||
|
|||||||
@@ -1,28 +1,16 @@
|
|||||||
import { DateTime, Duration, Effect, Equal, Equivalence, Hash, HashMap, type Option, Pipeable, Predicate, Schedule, type Scope, type Subscribable, SubscriptionRef } from "effect"
|
import { DateTime, Duration, Effect, Equal, Equivalence, Hash, HashMap, Pipeable, Predicate, type Scope, SubscriptionRef } from "effect"
|
||||||
import type * as Query from "./Query.js"
|
import type * as Query from "./Query.js"
|
||||||
import type * as Result from "./Result.js"
|
import type * as Result from "./Result.js"
|
||||||
|
|
||||||
|
|
||||||
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientService")
|
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientServiceTypeId")
|
||||||
export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
|
export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
|
||||||
|
|
||||||
export interface QueryClientService extends Pipeable.Pipeable {
|
export interface QueryClientService extends Pipeable.Pipeable {
|
||||||
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId
|
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId
|
||||||
|
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
|
||||||
readonly cache: Subscribable.Subscribable<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
|
readonly gcTime: Duration.DurationInput
|
||||||
readonly cacheGcTime: Duration.DurationInput
|
|
||||||
readonly defaultStaleTime: Duration.DurationInput
|
readonly defaultStaleTime: Duration.DurationInput
|
||||||
readonly defaultRefreshOnWindowFocus: boolean
|
|
||||||
|
|
||||||
readonly run: Effect.Effect<void>
|
|
||||||
getCacheEntry(key: QueryClientCacheKey): Effect.Effect<Option.Option<QueryClientCacheEntry>>
|
|
||||||
setCacheEntry(
|
|
||||||
key: QueryClientCacheKey,
|
|
||||||
result: Result.Success<unknown>,
|
|
||||||
staleTime: Duration.DurationInput,
|
|
||||||
): Effect.Effect<QueryClientCacheEntry>
|
|
||||||
invalidateCacheEntries(f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>): Effect.Effect<void>
|
|
||||||
invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect<void>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", {
|
export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", {
|
||||||
@@ -36,86 +24,41 @@ implements QueryClientService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>,
|
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>,
|
||||||
readonly cacheGcTime: Duration.DurationInput,
|
readonly gcTime: Duration.DurationInput,
|
||||||
readonly defaultStaleTime: Duration.DurationInput,
|
readonly defaultStaleTime: Duration.DurationInput,
|
||||||
readonly defaultRefreshOnWindowFocus: boolean,
|
|
||||||
readonly runSemaphore: Effect.Semaphore,
|
readonly runSemaphore: Effect.Semaphore,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
get run(): Effect.Effect<void> {
|
|
||||||
return this.runSemaphore.withPermits(1)(Effect.repeat(
|
|
||||||
Effect.andThen(
|
|
||||||
DateTime.now,
|
|
||||||
now => SubscriptionRef.update(this.cache, HashMap.filter(entry =>
|
|
||||||
Duration.lessThan(
|
|
||||||
DateTime.distanceDuration(entry.lastAccessedAt, now),
|
|
||||||
Duration.sum(entry.staleTime, this.cacheGcTime),
|
|
||||||
)
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
Schedule.spaced("30 second"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
getCacheEntry(key: QueryClientCacheKey): Effect.Effect<Option.Option<QueryClientCacheEntry>> {
|
|
||||||
return Effect.all([
|
|
||||||
Effect.andThen(this.cache, HashMap.get(key)),
|
|
||||||
DateTime.now,
|
|
||||||
]).pipe(
|
|
||||||
Effect.map(([entry, now]) => new QueryClientCacheEntry(entry.result, entry.staleTime, entry.createdAt, now)),
|
|
||||||
Effect.tap(entry => SubscriptionRef.update(this.cache, HashMap.set(key, entry))),
|
|
||||||
Effect.option,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
setCacheEntry(
|
|
||||||
key: QueryClientCacheKey,
|
|
||||||
result: Result.Success<unknown>,
|
|
||||||
staleTime: Duration.DurationInput,
|
|
||||||
): Effect.Effect<QueryClientCacheEntry> {
|
|
||||||
return DateTime.now.pipe(
|
|
||||||
Effect.map(now => new QueryClientCacheEntry(result, staleTime, now, now)),
|
|
||||||
Effect.tap(entry => SubscriptionRef.update(this.cache, HashMap.set(key, entry))),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidateCacheEntries(f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>): Effect.Effect<void> {
|
|
||||||
return SubscriptionRef.update(this.cache, HashMap.filter((_, key) => !Equivalence.strict()(key.f, f)))
|
|
||||||
}
|
|
||||||
invalidateCacheEntry(key: QueryClientCacheKey): Effect.Effect<void> {
|
|
||||||
return SubscriptionRef.update(this.cache, HashMap.remove(key))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isQueryClientService = (u: unknown): u is QueryClientService => Predicate.hasProperty(u, QueryClientServiceTypeId)
|
export const isQueryClientService = (u: unknown): u is QueryClientService => Predicate.hasProperty(u, QueryClientServiceTypeId)
|
||||||
|
|
||||||
export declare namespace make {
|
export declare namespace make {
|
||||||
export interface Options {
|
export interface Options {
|
||||||
readonly cacheGcTime?: Duration.DurationInput
|
readonly gcTime?: Duration.DurationInput
|
||||||
readonly defaultStaleTime?: Duration.DurationInput
|
readonly defaultStaleTime?: Duration.DurationInput
|
||||||
readonly defaultRefreshOnWindowFocus?: boolean
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const make = Effect.fnUntraced(function* (options: make.Options = {}): Effect.fn.Return<QueryClientService> {
|
export const make = Effect.fnUntraced(function* (options: make.Options = {}): Effect.fn.Return<QueryClientService> {
|
||||||
return new QueryClientServiceImpl(
|
return new QueryClientServiceImpl(
|
||||||
yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()),
|
yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()),
|
||||||
options.cacheGcTime ?? "5 minutes",
|
options.gcTime ?? "5 minutes",
|
||||||
options.defaultStaleTime ?? "0 minutes",
|
options.defaultStaleTime ?? "0 minutes",
|
||||||
options.defaultRefreshOnWindowFocus ?? true,
|
|
||||||
yield* Effect.makeSemaphore(1),
|
yield* Effect.makeSemaphore(1),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const run = (_self: QueryClientService): Effect.Effect<void> => Effect.void
|
||||||
|
|
||||||
export declare namespace service {
|
export declare namespace service {
|
||||||
export interface Options extends make.Options {}
|
export interface Options extends make.Options {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const service = (options?: service.Options): Effect.Effect<QueryClientService, never, Scope.Scope> => Effect.tap(
|
export const service = (options?: service.Options): Effect.Effect<QueryClientService, never, Scope.Scope> => Effect.tap(
|
||||||
make(options),
|
make(options),
|
||||||
client => Effect.forkScoped(client.run),
|
client => Effect.forkScoped(run(client)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -155,9 +98,7 @@ implements Pipeable.Pipeable {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly result: Result.Success<unknown>,
|
readonly result: Result.Success<unknown>,
|
||||||
readonly staleTime: Duration.DurationInput,
|
|
||||||
readonly createdAt: DateTime.DateTime,
|
readonly createdAt: DateTime.DateTime,
|
||||||
readonly lastAccessedAt: DateTime.DateTime,
|
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -166,8 +107,9 @@ implements Pipeable.Pipeable {
|
|||||||
export const isQueryClientCacheEntry = (u: unknown): u is QueryClientCacheEntry => Predicate.hasProperty(u, QueryClientCacheEntryTypeId)
|
export const isQueryClientCacheEntry = (u: unknown): u is QueryClientCacheEntry => Predicate.hasProperty(u, QueryClientCacheEntryTypeId)
|
||||||
|
|
||||||
export const isQueryClientCacheEntryStale = (
|
export const isQueryClientCacheEntryStale = (
|
||||||
self: QueryClientCacheEntry
|
self: QueryClientCacheEntry,
|
||||||
|
staleTime: Duration.DurationInput,
|
||||||
): Effect.Effect<boolean> => Effect.andThen(
|
): Effect.Effect<boolean> => Effect.andThen(
|
||||||
DateTime.now,
|
DateTime.now,
|
||||||
now => Duration.greaterThanOrEqualTo(DateTime.distanceDuration(self.createdAt, now), self.staleTime),
|
now => Duration.lessThan(DateTime.distanceDuration(self.createdAt, now), staleTime),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, Pipeable, Predicate, PubSub, pipe, Ref, type Scope, Stream, Subscribable } from "effect"
|
import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, Option, Pipeable, Predicate, PubSub, pipe, Ref, type Scope, Stream, Subscribable } from "effect"
|
||||||
|
|
||||||
|
|
||||||
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
|
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
|
||||||
export type ResultTypeId = typeof ResultTypeId
|
export type ResultTypeId = typeof ResultTypeId
|
||||||
|
|
||||||
export type Result<A, E = never, P = never> = (
|
export type Result<A, E = never, P = never> = (
|
||||||
| Initial
|
// biome-ignore lint/complexity/noBannedTypes: "{}" is relevant here
|
||||||
|
| (Initial & ({} | WillFetch))
|
||||||
| Running<P>
|
| Running<P>
|
||||||
| Final<A, E, P>
|
| Final<A, E, P>
|
||||||
)
|
)
|
||||||
|
|
||||||
// biome-ignore lint/complexity/noBannedTypes: "{}" is relevant here
|
export type Final<A, E = never, P = never> = (
|
||||||
export type Final<A, E = never, P = never> = (Success<A> | Failure<E>) & ({} | Flags<P>)
|
& (Success<A> | Failure<A, E>)
|
||||||
export type Flags<P = never> = WillFetch | WillRefresh | Refreshing<P>
|
// biome-ignore lint/complexity/noBannedTypes: "{}" is relevant here
|
||||||
|
& ({} | WillFetch | WillRefresh | Refreshing<P>)
|
||||||
|
)
|
||||||
|
|
||||||
export declare namespace Result {
|
export namespace Result {
|
||||||
export interface Prototype extends Pipeable.Pipeable, Equal.Equal {
|
export interface Prototype extends Pipeable.Pipeable, Equal.Equal {
|
||||||
readonly [ResultTypeId]: ResultTypeId
|
readonly [ResultTypeId]: ResultTypeId
|
||||||
}
|
}
|
||||||
@@ -24,10 +27,6 @@ export declare namespace Result {
|
|||||||
export type Progress<R extends Result<any, any, any>> = [R] extends [Result<infer _A, infer _E, infer P>] ? P : never
|
export type Progress<R extends Result<any, any, any>> = [R] extends [Result<infer _A, infer _E, infer P>] ? P : never
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace Flags {
|
|
||||||
export type Keys = keyof WillFetch & WillRefresh & Refreshing<any>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Initial extends Result.Prototype {
|
export interface Initial extends Result.Prototype {
|
||||||
readonly _tag: "Initial"
|
readonly _tag: "Initial"
|
||||||
}
|
}
|
||||||
@@ -42,21 +41,22 @@ export interface Success<A> extends Result.Prototype {
|
|||||||
readonly value: A
|
readonly value: A
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Failure<E = never> extends Result.Prototype {
|
export interface Failure<A, E = never> extends Result.Prototype {
|
||||||
readonly _tag: "Failure"
|
readonly _tag: "Failure"
|
||||||
readonly cause: Cause.Cause<E>
|
readonly cause: Cause.Cause<E>
|
||||||
|
readonly previousSuccess: Option.Option<Success<A>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WillFetch {
|
export interface WillFetch extends Result.Prototype {
|
||||||
readonly _flag: "WillFetch"
|
readonly willFetch: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WillRefresh {
|
export interface WillRefresh extends Result.Prototype {
|
||||||
readonly _flag: "WillRefresh"
|
readonly willRefresh: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Refreshing<P = never> {
|
export interface Refreshing<P = never> extends Result.Prototype {
|
||||||
readonly _flag: "Refreshing"
|
readonly refreshing: true
|
||||||
readonly progress: P
|
readonly progress: P
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,32 +66,41 @@ const ResultPrototype = Object.freeze({
|
|||||||
[ResultTypeId]: ResultTypeId,
|
[ResultTypeId]: ResultTypeId,
|
||||||
|
|
||||||
[Equal.symbol](this: Result<any, any, any>, that: Result<any, any, any>): boolean {
|
[Equal.symbol](this: Result<any, any, any>, that: Result<any, any, any>): boolean {
|
||||||
if (this._tag !== that._tag || (this as Flags)._flag !== (that as Flags)._flag)
|
if (this._tag !== that._tag)
|
||||||
return false
|
|
||||||
if (hasRefreshingFlag(this) && !Equal.equals(this.progress, (that as Refreshing<any>).progress))
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return Match.value(this).pipe(
|
return Match.value(this).pipe(
|
||||||
Match.tag("Initial", () => true),
|
Match.tag("Initial", () => true),
|
||||||
Match.tag("Running", self => Equal.equals(self.progress, (that as Running<any>).progress)),
|
Match.tag("Running", self => Equal.equals(self.progress, (that as Running<any>).progress)),
|
||||||
Match.tag("Success", self => Equal.equals(self.value, (that as Success<any>).value)),
|
Match.tag("Success", self =>
|
||||||
Match.tag("Failure", self => Equal.equals(self.cause, (that as Failure<any>).cause)),
|
Equal.equals(self.value, (that as Success<any>).value) &&
|
||||||
|
(isRefreshing(self) ? self.refreshing : false) === (isRefreshing(that) ? that.refreshing : false) &&
|
||||||
|
Equal.equals(isRefreshing(self) ? self.progress : undefined, isRefreshing(that) ? that.progress : undefined)
|
||||||
|
),
|
||||||
|
Match.tag("Failure", self =>
|
||||||
|
Equal.equals(self.cause, (that as Failure<any, any>).cause) &&
|
||||||
|
(isRefreshing(self) ? self.refreshing : false) === (isRefreshing(that) ? that.refreshing : false) &&
|
||||||
|
Equal.equals(isRefreshing(self) ? self.progress : undefined, isRefreshing(that) ? that.progress : undefined)
|
||||||
|
),
|
||||||
Match.exhaustive,
|
Match.exhaustive,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
[Hash.symbol](this: Result<any, any, any>): number {
|
[Hash.symbol](this: Result<any, any, any>): number {
|
||||||
return pipe(Hash.string(this._tag),
|
const tagHash = Hash.string(this._tag)
|
||||||
tagHash => Match.value(this).pipe(
|
|
||||||
Match.tag("Initial", () => tagHash),
|
return Match.value(this).pipe(
|
||||||
Match.tag("Running", self => Hash.combine(Hash.hash(self.progress))(tagHash)),
|
Match.tag("Initial", () => tagHash),
|
||||||
Match.tag("Success", self => Hash.combine(Hash.hash(self.value))(tagHash)),
|
Match.tag("Running", self => Hash.combine(Hash.hash(self.progress))(tagHash)),
|
||||||
Match.tag("Failure", self => Hash.combine(Hash.hash(self.cause))(tagHash)),
|
Match.tag("Success", self => pipe(tagHash,
|
||||||
Match.exhaustive,
|
Hash.combine(Hash.hash(self.value)),
|
||||||
),
|
Hash.combine(Hash.hash(isRefreshing(self) ? self.progress : undefined)),
|
||||||
Hash.combine(Hash.hash((this as Flags)._flag)),
|
)),
|
||||||
hash => hasRefreshingFlag(this)
|
Match.tag("Failure", self => pipe(tagHash,
|
||||||
? Hash.combine(Hash.hash(this.progress))(hash)
|
Hash.combine(Hash.hash(self.cause)),
|
||||||
: hash,
|
Hash.combine(Hash.hash(isRefreshing(self) ? self.progress : undefined)),
|
||||||
|
)),
|
||||||
|
Match.exhaustive,
|
||||||
Hash.cached(this),
|
Hash.cached(this),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -103,11 +112,10 @@ export const isFinal = (u: unknown): u is Final<unknown, unknown, unknown> => is
|
|||||||
export const isInitial = (u: unknown): u is Initial => isResult(u) && u._tag === "Initial"
|
export const isInitial = (u: unknown): u is Initial => isResult(u) && u._tag === "Initial"
|
||||||
export const isRunning = (u: unknown): u is Running<unknown> => isResult(u) && u._tag === "Running"
|
export const isRunning = (u: unknown): u is Running<unknown> => isResult(u) && u._tag === "Running"
|
||||||
export const isSuccess = (u: unknown): u is Success<unknown> => isResult(u) && u._tag === "Success"
|
export const isSuccess = (u: unknown): u is Success<unknown> => isResult(u) && u._tag === "Success"
|
||||||
export const isFailure = (u: unknown): u is Failure<unknown> => isResult(u) && u._tag === "Failure"
|
export const isFailure = (u: unknown): u is Failure<unknown, unknown> => isResult(u) && u._tag === "Failure"
|
||||||
export const hasFlag = (u: unknown): u is Flags => isResult(u) && Predicate.hasProperty(u, "_flag")
|
export const isWillFetch = (u: unknown): u is WillFetch => isResult(u) && Predicate.hasProperty(u, "willFetch")
|
||||||
export const hasWillFetchFlag = (u: unknown): u is WillFetch => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "WillFetch"
|
export const isWillRefresh = (u: unknown): u is WillRefresh => isResult(u) && Predicate.hasProperty(u, "willRefresh")
|
||||||
export const hasWillRefreshFlag = (u: unknown): u is WillRefresh => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "WillRefresh"
|
export const isRefreshing = (u: unknown): u is Refreshing<unknown> => isResult(u) && Predicate.hasProperty(u, "refreshing")
|
||||||
export const hasRefreshingFlag = (u: unknown): u is Refreshing<unknown> => isResult(u) && Predicate.hasProperty(u, "_flag") && u._flag === "Refreshing"
|
|
||||||
|
|
||||||
export const initial: {
|
export const initial: {
|
||||||
(): Initial
|
(): Initial
|
||||||
@@ -115,42 +123,48 @@ export const initial: {
|
|||||||
} = (): Initial => Object.setPrototypeOf({ _tag: "Initial" }, ResultPrototype)
|
} = (): Initial => Object.setPrototypeOf({ _tag: "Initial" }, ResultPrototype)
|
||||||
export const running = <P = never>(progress?: P): Running<P> => Object.setPrototypeOf({ _tag: "Running", progress }, ResultPrototype)
|
export const running = <P = never>(progress?: P): Running<P> => Object.setPrototypeOf({ _tag: "Running", progress }, ResultPrototype)
|
||||||
export const succeed = <A>(value: A): Success<A> => Object.setPrototypeOf({ _tag: "Success", value }, ResultPrototype)
|
export const succeed = <A>(value: A): Success<A> => Object.setPrototypeOf({ _tag: "Success", value }, ResultPrototype)
|
||||||
export const fail = <E>(cause: Cause.Cause<E> ): Failure<E> => Object.setPrototypeOf({ _tag: "Failure", cause }, ResultPrototype)
|
|
||||||
|
|
||||||
export const willFetch = <R extends Final<any, any, any>>(
|
export const fail = <E, A = never>(
|
||||||
|
cause: Cause.Cause<E>,
|
||||||
|
previousSuccess?: Success<NoInfer<A>>,
|
||||||
|
): Failure<A, E> => Object.setPrototypeOf({
|
||||||
|
_tag: "Failure",
|
||||||
|
cause,
|
||||||
|
previousSuccess: Option.fromNullable(previousSuccess),
|
||||||
|
}, ResultPrototype)
|
||||||
|
|
||||||
|
export const willFetch = <R extends Initial | Final<any, any, any>>(
|
||||||
result: R
|
result: R
|
||||||
): Omit<R, keyof Flags.Keys> & WillFetch => Object.setPrototypeOf(
|
): Omit<R, keyof WillFetch> & WillFetch => Object.setPrototypeOf(
|
||||||
Object.assign({}, result, { _flag: "WillFetch" }),
|
Object.assign({}, result, { willFetch: true }),
|
||||||
Object.getPrototypeOf(result),
|
Object.getPrototypeOf(result),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const willRefresh = <R extends Final<any, any, any>>(
|
export const willRefresh = <R extends Final<any, any, any>>(
|
||||||
result: R
|
result: R
|
||||||
): Omit<R, keyof Flags.Keys> & WillRefresh => Object.setPrototypeOf(
|
): Omit<R, keyof WillRefresh> & WillRefresh => Object.setPrototypeOf(
|
||||||
Object.assign({}, result, { _flag: "WillRefresh" }),
|
Object.assign({}, result, { willRefresh: true }),
|
||||||
Object.getPrototypeOf(result),
|
Object.getPrototypeOf(result),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const refreshing = <R extends Final<any, any, any>, P = never>(
|
export const refreshing = <R extends Final<any, any, any>, P = never>(
|
||||||
result: R,
|
result: R,
|
||||||
progress?: P,
|
progress?: P,
|
||||||
): Omit<R, keyof Flags.Keys> & Refreshing<P> => Object.setPrototypeOf(
|
): Omit<R, keyof Refreshing<Result.Progress<R>>> & Refreshing<P> => Object.setPrototypeOf(
|
||||||
Object.assign({}, result, { _flag: "Refreshing", progress }),
|
Object.assign({}, result, { refreshing: true, progress }),
|
||||||
Object.getPrototypeOf(result),
|
Object.getPrototypeOf(result),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const fromExit: {
|
export const fromExit = <A, E>(
|
||||||
<A, E>(exit: Exit.Success<A, E>): Success<A>
|
exit: Exit.Exit<A, E>,
|
||||||
<A, E>(exit: Exit.Failure<A, E>): Failure<E>
|
previousSuccess?: Success<NoInfer<A>>,
|
||||||
<A, E>(exit: Exit.Exit<A, E>): Success<A> | Failure<E>
|
): Success<A> | Failure<A, E> => exit._tag === "Success"
|
||||||
} = exit => (exit._tag === "Success" ? succeed(exit.value) : fail(exit.cause)) as any
|
? succeed(exit.value)
|
||||||
|
: fail(exit.cause, previousSuccess)
|
||||||
|
|
||||||
export const toExit: {
|
export const toExit = <A, E, P>(
|
||||||
<A>(self: Success<A>): Exit.Success<A, never>
|
self: Result<A, E, P>
|
||||||
<E>(self: Failure<E>): Exit.Failure<never, E>
|
): Exit.Exit<A, E | Cause.NoSuchElementException> => {
|
||||||
<A, E, P>(self: Final<A, E, P>): Exit.Exit<A, E>
|
|
||||||
<A, E, P>(self: Result<A, E, P>): Exit.Exit<A, E | Cause.NoSuchElementException>
|
|
||||||
} = <A, E, P>(self: Result<A, E, P>): any => {
|
|
||||||
switch (self._tag) {
|
switch (self._tag) {
|
||||||
case "Success":
|
case "Success":
|
||||||
return Exit.succeed(self.value)
|
return Exit.succeed(self.value)
|
||||||
@@ -189,17 +203,17 @@ export const makeProgressLayer = <A, E, P = never>(): Layer.Layer<
|
|||||||
const state = yield* State<A, E, P>()
|
const state = yield* State<A, E, P>()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
update: <FE, FR>(f: (previous: P) => Effect.Effect<P, FE, FR>) => Effect.Do.pipe(
|
update: <E, R>(f: (previous: P) => Effect.Effect<P, E, R>) => Effect.Do.pipe(
|
||||||
Effect.bind("previous", () => Effect.andThen(state.get, previous =>
|
Effect.bind("previous", () => Effect.andThen(state.get, previous =>
|
||||||
(isRunning(previous) || hasRefreshingFlag(previous))
|
isRunning(previous) || isRefreshing(previous)
|
||||||
? Effect.succeed(previous)
|
? Effect.succeed(previous)
|
||||||
: Effect.fail(new PreviousResultNotRunningNorRefreshing({ previous })),
|
: Effect.fail(new PreviousResultNotRunningNorRefreshing({ previous })),
|
||||||
)),
|
)),
|
||||||
Effect.bind("progress", ({ previous }) => f(previous.progress)),
|
Effect.bind("progress", ({ previous }) => f(previous.progress)),
|
||||||
Effect.let("next", ({ previous, progress }) => isRunning(previous)
|
Effect.let("next", ({ previous, progress }) => Object.setPrototypeOf(
|
||||||
? running(progress)
|
Object.assign({}, previous, { progress }),
|
||||||
: refreshing(previous, progress) as Final<A, E, P> & Refreshing<P>
|
Object.getPrototypeOf(previous),
|
||||||
),
|
)),
|
||||||
Effect.andThen(({ next }) => state.set(next)),
|
Effect.andThen(({ next }) => state.set(next)),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -209,10 +223,19 @@ export const makeProgressLayer = <A, E, P = never>(): Layer.Layer<
|
|||||||
export namespace unsafeForkEffect {
|
export namespace unsafeForkEffect {
|
||||||
export type OutputContext<A, E, R, P> = Exclude<R, State<A, E, P> | Progress<P> | Progress<never>>
|
export type OutputContext<A, E, R, P> = Exclude<R, State<A, E, P> | Progress<P> | Progress<never>>
|
||||||
|
|
||||||
export interface Options<A, E, P> {
|
export type Options<A, E, P> = {
|
||||||
readonly initial?: Initial | Final<A, E, P>
|
readonly initial?: Result<A, E, P>
|
||||||
readonly initialProgress?: P
|
readonly initialProgress?: P
|
||||||
}
|
readonly previous?: Final<A, E, P>
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
readonly refresh: true
|
||||||
|
readonly previous: Final<A, E, P>
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
readonly refresh?: false
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const unsafeForkEffect = <A, E, R, P = never>(
|
export const unsafeForkEffect = <A, E, R, P = never>(
|
||||||
@@ -226,30 +249,29 @@ export const unsafeForkEffect = <A, E, R, P = never>(
|
|||||||
Effect.bind("ref", () => Ref.make(options?.initial ?? initial<A, E, P>())),
|
Effect.bind("ref", () => Ref.make(options?.initial ?? initial<A, E, P>())),
|
||||||
Effect.bind("pubsub", () => PubSub.unbounded<Result<A, E, P>>()),
|
Effect.bind("pubsub", () => PubSub.unbounded<Result<A, E, P>>()),
|
||||||
Effect.bind("fiber", ({ ref, pubsub }) => Effect.forkScoped(State<A, E, P>().pipe(
|
Effect.bind("fiber", ({ ref, pubsub }) => Effect.forkScoped(State<A, E, P>().pipe(
|
||||||
Effect.andThen(state => state.set(
|
Effect.andThen(state => state.set(options?.refresh
|
||||||
(isFinal(options?.initial) && hasWillRefreshFlag(options?.initial))
|
? refreshing(options.previous, options?.initialProgress) as Result<A, E, P>
|
||||||
? refreshing(options.initial, options?.initialProgress) as Result<A, E, P>
|
: running(options?.initialProgress)
|
||||||
: running(options?.initialProgress)
|
|
||||||
).pipe(
|
).pipe(
|
||||||
Effect.andThen(effect),
|
Effect.andThen(effect),
|
||||||
Effect.onExit(exit => Effect.andThen(
|
Effect.onExit(exit => Effect.andThen(
|
||||||
state.set(fromExit(exit)),
|
state.set(fromExit(exit, (options?.previous && isSuccess(options.previous)) ? options.previous : undefined)),
|
||||||
Effect.forkScoped(PubSub.shutdown(pubsub)),
|
Effect.forkScoped(PubSub.shutdown(pubsub)),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
Effect.provide(Layer.empty.pipe(
|
Effect.provide(Layer.empty.pipe(
|
||||||
Layer.provideMerge(makeProgressLayer<A, E, P>()),
|
Layer.provideMerge(makeProgressLayer<A, E, P>()),
|
||||||
Layer.provideMerge(Layer.succeed(State<A, E, P>(), {
|
Layer.provideMerge(Layer.succeed(State<A, E, P>(), {
|
||||||
get: Ref.get(ref),
|
get: ref,
|
||||||
set: v => Effect.andThen(Ref.set(ref, v), PubSub.publish(pubsub, v))
|
set: v => Effect.andThen(Ref.set(ref, v), PubSub.publish(pubsub, v))
|
||||||
})),
|
})),
|
||||||
)),
|
)),
|
||||||
))),
|
))),
|
||||||
Effect.map(({ ref, pubsub, fiber }) => [
|
Effect.map(({ ref, pubsub, fiber }) => [
|
||||||
Subscribable.make({
|
Subscribable.make({
|
||||||
get: Ref.get(ref),
|
get: ref,
|
||||||
changes: Stream.unwrapScoped(Effect.map(
|
changes: Stream.unwrapScoped(Effect.map(
|
||||||
Effect.all([Ref.get(ref), Stream.fromPubSub(pubsub, { scoped: true })]),
|
Effect.all([ref, Stream.fromPubSub(pubsub, { scoped: true })]),
|
||||||
([latest, stream]) => Stream.concat(Stream.make(latest), stream),
|
([latest, stream]) => Stream.concat(Stream.make(latest), stream),
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
@@ -264,7 +286,7 @@ export const unsafeForkEffect = <A, E, R, P = never>(
|
|||||||
export namespace forkEffect {
|
export namespace forkEffect {
|
||||||
export type InputContext<R, P> = R extends Progress<infer X> ? [X] extends [P] ? R : never : R
|
export type InputContext<R, P> = R extends Progress<infer X> ? [X] extends [P] ? R : never : R
|
||||||
export type OutputContext<A, E, R, P> = unsafeForkEffect.OutputContext<A, E, R, P>
|
export type OutputContext<A, E, R, P> = unsafeForkEffect.OutputContext<A, E, R, P>
|
||||||
export interface Options<A, E, P> extends unsafeForkEffect.Options<A, E, P> {}
|
export type Options<A, E, P> = unsafeForkEffect.Options<A, E, P>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const forkEffect: {
|
export const forkEffect: {
|
||||||
|
|||||||
@@ -13,30 +13,30 @@
|
|||||||
"clean:modules": "rm -rf node_modules"
|
"clean:modules": "rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tanstack/react-router": "^1.154.12",
|
"@tanstack/react-router": "^1.139.12",
|
||||||
"@tanstack/react-router-devtools": "^1.154.12",
|
"@tanstack/react-router-devtools": "^1.139.12",
|
||||||
"@tanstack/router-plugin": "^1.154.12",
|
"@tanstack/router-plugin": "^1.139.12",
|
||||||
"@types/react": "^19.2.9",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.2",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
"globals": "^17.0.0",
|
"globals": "^16.5.0",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.0",
|
||||||
"type-fest": "^5.4.1",
|
"type-fest": "^5.2.0",
|
||||||
"vite": "^8.0.0"
|
"vite": "^7.2.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform": "^0.94.2",
|
"@effect/platform": "^0.94.0",
|
||||||
"@effect/platform-browser": "^0.74.0",
|
"@effect/platform-browser": "^0.74.0",
|
||||||
"@radix-ui/themes": "^3.2.1",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
"@typed/id": "^0.17.2",
|
"@typed/id": "^0.17.2",
|
||||||
"effect": "^3.19.15",
|
"effect": "^3.19.8",
|
||||||
"effect-fc": "workspace:*",
|
"effect-fc": "workspace:*",
|
||||||
"react-icons": "^5.5.0"
|
"react-icons": "^5.5.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@types/react": "^19.2.9",
|
"@types/react": "^19.2.7",
|
||||||
"effect": "^3.19.15",
|
"effect": "^3.19.8",
|
||||||
"react": "^19.2.3"
|
"react": "^19.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ extends Omit<TextField.RootProps, "optional" | "defaultValue">, Form.useOptional
|
|||||||
export type TextFieldFormInputProps = Props | OptionalProps
|
export type TextFieldFormInputProps = Props | OptionalProps
|
||||||
|
|
||||||
|
|
||||||
export class TextFieldFormInputView extends Component.make("TextFieldFormInputView")(function*(props: TextFieldFormInputProps) {
|
export class TextFieldFormInput extends Component.makeUntraced("TextFieldFormInput")(function*(props: TextFieldFormInputProps) {
|
||||||
const input: (
|
const input: (
|
||||||
| { readonly optional: true } & Form.useOptionalInput.Success<string>
|
| { readonly optional: true } & Form.useOptionalInput.Result<string>
|
||||||
| { readonly optional: false } & Form.useInput.Success<string>
|
| { readonly optional: false } & Form.useInput.Result<string>
|
||||||
) = props.optional
|
) = props.optional
|
||||||
// biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported
|
// biome-ignore lint/correctness/useHookAtTopLevel: "optional" reactivity not supported
|
||||||
? { optional: true, ...yield* Form.useOptionalInput(props.field, props) }
|
? { optional: true, ...yield* Form.useOptionalInput(props.field, props) }
|
||||||
@@ -13,10 +13,10 @@ import { Route as ResultRouteImport } from './routes/result'
|
|||||||
import { Route as QueryRouteImport } from './routes/query'
|
import { Route as QueryRouteImport } from './routes/query'
|
||||||
import { Route as FormRouteImport } from './routes/form'
|
import { Route as FormRouteImport } from './routes/form'
|
||||||
import { Route as BlankRouteImport } from './routes/blank'
|
import { Route as BlankRouteImport } from './routes/blank'
|
||||||
import { Route as AsyncRouteImport } from './routes/async'
|
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as DevMemoRouteImport } from './routes/dev/memo'
|
import { Route as DevMemoRouteImport } from './routes/dev/memo'
|
||||||
import { Route as DevContextRouteImport } from './routes/dev/context'
|
import { Route as DevContextRouteImport } from './routes/dev/context'
|
||||||
|
import { Route as DevAsyncRenderingRouteImport } from './routes/dev/async-rendering'
|
||||||
|
|
||||||
const ResultRoute = ResultRouteImport.update({
|
const ResultRoute = ResultRouteImport.update({
|
||||||
id: '/result',
|
id: '/result',
|
||||||
@@ -38,11 +38,6 @@ const BlankRoute = BlankRouteImport.update({
|
|||||||
path: '/blank',
|
path: '/blank',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const AsyncRoute = AsyncRouteImport.update({
|
|
||||||
id: '/async',
|
|
||||||
path: '/async',
|
|
||||||
getParentRoute: () => rootRouteImport,
|
|
||||||
} as any)
|
|
||||||
const IndexRoute = IndexRouteImport.update({
|
const IndexRoute = IndexRouteImport.update({
|
||||||
id: '/',
|
id: '/',
|
||||||
path: '/',
|
path: '/',
|
||||||
@@ -58,35 +53,40 @@ const DevContextRoute = DevContextRouteImport.update({
|
|||||||
path: '/dev/context',
|
path: '/dev/context',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const DevAsyncRenderingRoute = DevAsyncRenderingRouteImport.update({
|
||||||
|
id: '/dev/async-rendering',
|
||||||
|
path: '/dev/async-rendering',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/async': typeof AsyncRoute
|
|
||||||
'/blank': typeof BlankRoute
|
'/blank': typeof BlankRoute
|
||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
'/result': typeof ResultRoute
|
||||||
|
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||||
'/dev/context': typeof DevContextRoute
|
'/dev/context': typeof DevContextRoute
|
||||||
'/dev/memo': typeof DevMemoRoute
|
'/dev/memo': typeof DevMemoRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/async': typeof AsyncRoute
|
|
||||||
'/blank': typeof BlankRoute
|
'/blank': typeof BlankRoute
|
||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
'/result': typeof ResultRoute
|
||||||
|
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||||
'/dev/context': typeof DevContextRoute
|
'/dev/context': typeof DevContextRoute
|
||||||
'/dev/memo': typeof DevMemoRoute
|
'/dev/memo': typeof DevMemoRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/async': typeof AsyncRoute
|
|
||||||
'/blank': typeof BlankRoute
|
'/blank': typeof BlankRoute
|
||||||
'/form': typeof FormRoute
|
'/form': typeof FormRoute
|
||||||
'/query': typeof QueryRoute
|
'/query': typeof QueryRoute
|
||||||
'/result': typeof ResultRoute
|
'/result': typeof ResultRoute
|
||||||
|
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||||
'/dev/context': typeof DevContextRoute
|
'/dev/context': typeof DevContextRoute
|
||||||
'/dev/memo': typeof DevMemoRoute
|
'/dev/memo': typeof DevMemoRoute
|
||||||
}
|
}
|
||||||
@@ -94,42 +94,42 @@ export interface FileRouteTypes {
|
|||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths:
|
fullPaths:
|
||||||
| '/'
|
| '/'
|
||||||
| '/async'
|
|
||||||
| '/blank'
|
| '/blank'
|
||||||
| '/form'
|
| '/form'
|
||||||
| '/query'
|
| '/query'
|
||||||
| '/result'
|
| '/result'
|
||||||
|
| '/dev/async-rendering'
|
||||||
| '/dev/context'
|
| '/dev/context'
|
||||||
| '/dev/memo'
|
| '/dev/memo'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
| '/async'
|
|
||||||
| '/blank'
|
| '/blank'
|
||||||
| '/form'
|
| '/form'
|
||||||
| '/query'
|
| '/query'
|
||||||
| '/result'
|
| '/result'
|
||||||
|
| '/dev/async-rendering'
|
||||||
| '/dev/context'
|
| '/dev/context'
|
||||||
| '/dev/memo'
|
| '/dev/memo'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
| '/async'
|
|
||||||
| '/blank'
|
| '/blank'
|
||||||
| '/form'
|
| '/form'
|
||||||
| '/query'
|
| '/query'
|
||||||
| '/result'
|
| '/result'
|
||||||
|
| '/dev/async-rendering'
|
||||||
| '/dev/context'
|
| '/dev/context'
|
||||||
| '/dev/memo'
|
| '/dev/memo'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
AsyncRoute: typeof AsyncRoute
|
|
||||||
BlankRoute: typeof BlankRoute
|
BlankRoute: typeof BlankRoute
|
||||||
FormRoute: typeof FormRoute
|
FormRoute: typeof FormRoute
|
||||||
QueryRoute: typeof QueryRoute
|
QueryRoute: typeof QueryRoute
|
||||||
ResultRoute: typeof ResultRoute
|
ResultRoute: typeof ResultRoute
|
||||||
|
DevAsyncRenderingRoute: typeof DevAsyncRenderingRoute
|
||||||
DevContextRoute: typeof DevContextRoute
|
DevContextRoute: typeof DevContextRoute
|
||||||
DevMemoRoute: typeof DevMemoRoute
|
DevMemoRoute: typeof DevMemoRoute
|
||||||
}
|
}
|
||||||
@@ -164,13 +164,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof BlankRouteImport
|
preLoaderRoute: typeof BlankRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/async': {
|
|
||||||
id: '/async'
|
|
||||||
path: '/async'
|
|
||||||
fullPath: '/async'
|
|
||||||
preLoaderRoute: typeof AsyncRouteImport
|
|
||||||
parentRoute: typeof rootRouteImport
|
|
||||||
}
|
|
||||||
'/': {
|
'/': {
|
||||||
id: '/'
|
id: '/'
|
||||||
path: '/'
|
path: '/'
|
||||||
@@ -192,16 +185,23 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof DevContextRouteImport
|
preLoaderRoute: typeof DevContextRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/dev/async-rendering': {
|
||||||
|
id: '/dev/async-rendering'
|
||||||
|
path: '/dev/async-rendering'
|
||||||
|
fullPath: '/dev/async-rendering'
|
||||||
|
preLoaderRoute: typeof DevAsyncRenderingRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
AsyncRoute: AsyncRoute,
|
|
||||||
BlankRoute: BlankRoute,
|
BlankRoute: BlankRoute,
|
||||||
FormRoute: FormRoute,
|
FormRoute: FormRoute,
|
||||||
QueryRoute: QueryRoute,
|
QueryRoute: QueryRoute,
|
||||||
ResultRoute: ResultRoute,
|
ResultRoute: ResultRoute,
|
||||||
|
DevAsyncRenderingRoute: DevAsyncRenderingRoute,
|
||||||
DevContextRoute: DevContextRoute,
|
DevContextRoute: DevContextRoute,
|
||||||
DevMemoRoute: DevMemoRoute,
|
DevMemoRoute: DevMemoRoute,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import { HttpClient } from "@effect/platform"
|
|
||||||
import { Container, Flex, Heading, Slider, Text, TextField } from "@radix-ui/themes"
|
|
||||||
import { createFileRoute } from "@tanstack/react-router"
|
|
||||||
import { Array, Effect, flow, Option, Schema } from "effect"
|
|
||||||
import { Async, Component, Memoized } from "effect-fc"
|
|
||||||
import * as React from "react"
|
|
||||||
import { runtime } from "@/runtime"
|
|
||||||
|
|
||||||
|
|
||||||
const Post = Schema.Struct({
|
|
||||||
userId: Schema.Int,
|
|
||||||
id: Schema.Int,
|
|
||||||
title: Schema.String,
|
|
||||||
body: Schema.String,
|
|
||||||
})
|
|
||||||
|
|
||||||
interface AsyncFetchPostViewProps {
|
|
||||||
readonly id: number
|
|
||||||
}
|
|
||||||
|
|
||||||
class AsyncFetchPostView extends Component.make("AsyncFetchPostView")(function*(props: AsyncFetchPostViewProps) {
|
|
||||||
const post = yield* Component.useOnChange(() => HttpClient.HttpClient.pipe(
|
|
||||||
Effect.tap(Effect.sleep("500 millis")),
|
|
||||||
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ props.id }`)),
|
|
||||||
Effect.andThen(response => response.json),
|
|
||||||
Effect.andThen(Schema.decodeUnknown(Post)),
|
|
||||||
), [props.id])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Heading>{post.title}</Heading>
|
|
||||||
<Text>{post.body}</Text>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}).pipe(
|
|
||||||
Async.async,
|
|
||||||
Async.withOptions({ defaultFallback: <Text>Default fallback</Text> }),
|
|
||||||
Memoized.memoized,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
|
|
||||||
const AsyncRouteComponent = Component.make("AsyncRouteView")(function*() {
|
|
||||||
const [text, setText] = React.useState("Typing here should not trigger a refetch of the post")
|
|
||||||
const [id, setId] = React.useState(1)
|
|
||||||
|
|
||||||
const AsyncFetchPost = yield* AsyncFetchPostView.use
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<Flex direction="column" align="stretch" gap="2">
|
|
||||||
<TextField.Root
|
|
||||||
value={text}
|
|
||||||
onChange={e => setText(e.currentTarget.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Slider
|
|
||||||
value={[id]}
|
|
||||||
onValueChange={flow(Array.head, Option.getOrThrow, setId)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AsyncFetchPost id={id} fallback={<Text>Loading post...</Text>} />
|
|
||||||
</Flex>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}).pipe(
|
|
||||||
Component.withRuntime(runtime.context)
|
|
||||||
)
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/async")({
|
|
||||||
component: AsyncRouteComponent,
|
|
||||||
})
|
|
||||||
78
packages/example/src/routes/dev/async-rendering.tsx
Normal file
78
packages/example/src/routes/dev/async-rendering.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { Flex, Text, TextField } from "@radix-ui/themes"
|
||||||
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
|
import { GetRandomValues, makeUuid4 } from "@typed/id"
|
||||||
|
import { Effect } from "effect"
|
||||||
|
import { Async, Component, Memoized } from "effect-fc"
|
||||||
|
import * as React from "react"
|
||||||
|
import { runtime } from "@/runtime"
|
||||||
|
|
||||||
|
|
||||||
|
// Generator version
|
||||||
|
const RouteComponent = Component.makeUntraced(function* AsyncRendering() {
|
||||||
|
const MemoizedAsyncComponentFC = yield* MemoizedAsyncComponent
|
||||||
|
const AsyncComponentFC = yield* AsyncComponent
|
||||||
|
const [input, setInput] = React.useState("")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" align="stretch" gap="2">
|
||||||
|
<TextField.Root
|
||||||
|
value={input}
|
||||||
|
onChange={e => setInput(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MemoizedAsyncComponentFC fallback={React.useMemo(() => <p>Loading memoized...</p>, [])} />
|
||||||
|
<AsyncComponentFC />
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}).pipe(
|
||||||
|
Component.withRuntime(runtime.context)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pipeline version
|
||||||
|
// const RouteComponent = Component.make("RouteComponent")(() => Effect.Do,
|
||||||
|
// Effect.bind("VMemoizedAsyncComponent", () => Component.useFC(MemoizedAsyncComponent)),
|
||||||
|
// Effect.bind("VAsyncComponent", () => Component.useFC(AsyncComponent)),
|
||||||
|
// Effect.let("input", () => React.useState("")),
|
||||||
|
|
||||||
|
// Effect.map(({ input: [input, setInput], VAsyncComponent, VMemoizedAsyncComponent }) =>
|
||||||
|
// <Flex direction="column" align="stretch" gap="2">
|
||||||
|
// <TextField.Root
|
||||||
|
// value={input}
|
||||||
|
// onChange={e => setInput(e.target.value)}
|
||||||
|
// />
|
||||||
|
|
||||||
|
// <VMemoizedAsyncComponent />
|
||||||
|
// <VAsyncComponent />
|
||||||
|
// </Flex>
|
||||||
|
// ),
|
||||||
|
// ).pipe(
|
||||||
|
// Component.withRuntime(runtime.context)
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncComponent extends Component.makeUntraced("AsyncComponent")(function*() {
|
||||||
|
const SubComponentFC = yield* SubComponent
|
||||||
|
|
||||||
|
yield* Effect.sleep("500 millis") // Async operation
|
||||||
|
// Cannot use React hooks after the async operation
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" align="stretch">
|
||||||
|
<Text>Rendered!</Text>
|
||||||
|
<SubComponentFC />
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}).pipe(
|
||||||
|
Async.async,
|
||||||
|
Async.withOptions({ defaultFallback: <p>Loading...</p> }),
|
||||||
|
) {}
|
||||||
|
class MemoizedAsyncComponent extends Memoized.memoized(AsyncComponent) {}
|
||||||
|
|
||||||
|
class SubComponent extends Component.makeUntraced("SubComponent")(function*() {
|
||||||
|
const [state] = React.useState(yield* Component.useOnMount(() => Effect.provide(makeUuid4, GetRandomValues.CryptoRandom)))
|
||||||
|
return <Text>{state}</Text>
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/dev/async-rendering")({
|
||||||
|
component: RouteComponent
|
||||||
|
})
|
||||||
@@ -23,7 +23,7 @@ const SubComponent = Component.makeUntraced("SubComponent")(function*() {
|
|||||||
const ContextView = Component.makeUntraced("ContextView")(function*() {
|
const ContextView = Component.makeUntraced("ContextView")(function*() {
|
||||||
const [serviceValue, setServiceValue] = React.useState("test")
|
const [serviceValue, setServiceValue] = React.useState("test")
|
||||||
const SubServiceLayer = React.useMemo(() => SubService.Default(serviceValue), [serviceValue])
|
const SubServiceLayer = React.useMemo(() => SubService.Default(serviceValue), [serviceValue])
|
||||||
const SubComponentFC = yield* Effect.provide(SubComponent.use, yield* Component.useContextFromLayer(SubServiceLayer))
|
const SubComponentFC = yield* Effect.provide(SubComponent, yield* Component.useContext(SubServiceLayer))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ const RouteComponent = Component.makeUntraced("RouteComponent")(function*() {
|
|||||||
onChange={e => setValue(e.target.value)}
|
onChange={e => setValue(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{yield* Effect.map(SubComponent.use, FC => <FC />)}
|
{yield* Effect.map(SubComponent, FC => <FC />)}
|
||||||
{yield* Effect.map(MemoizedSubComponent.use, FC => <FC />)}
|
{yield* Effect.map(MemoizedSubComponent, FC => <FC />)}
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
}).pipe(
|
}).pipe(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Button, Container, Flex, Text } from "@radix-ui/themes"
|
|||||||
import { createFileRoute } from "@tanstack/react-router"
|
import { createFileRoute } from "@tanstack/react-router"
|
||||||
import { Console, Effect, Match, Option, ParseResult, Schema } from "effect"
|
import { Console, Effect, Match, Option, ParseResult, Schema } from "effect"
|
||||||
import { Component, Form, Subscribable } from "effect-fc"
|
import { Component, Form, Subscribable } from "effect-fc"
|
||||||
import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView"
|
import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput"
|
||||||
import { DateTimeUtcFromZonedInput } from "@/lib/schema"
|
import { DateTimeUtcFromZonedInput } from "@/lib/schema"
|
||||||
import { runtime } from "@/runtime"
|
import { runtime } from "@/runtime"
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ const RegisterFormSubmitSchema = Schema.Struct({
|
|||||||
birth: Schema.OptionFromSelf(Schema.DateTimeUtcFromSelf),
|
birth: Schema.OptionFromSelf(Schema.DateTimeUtcFromSelf),
|
||||||
})
|
})
|
||||||
|
|
||||||
class RegisterFormService extends Effect.Service<RegisterFormService>()("RegisterFormService", {
|
class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
|
||||||
scoped: Form.service({
|
scoped: Form.service({
|
||||||
schema: RegisterFormSchema.pipe(
|
schema: RegisterFormSchema.pipe(
|
||||||
Schema.compose(
|
Schema.compose(
|
||||||
@@ -62,15 +62,15 @@ class RegisterFormService extends Effect.Service<RegisterFormService>()("Registe
|
|||||||
})
|
})
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
class RegisterFormView extends Component.makeUntraced("RegisterFormView")(function*() {
|
||||||
const form = yield* RegisterFormService
|
const form = yield* RegisterForm
|
||||||
const [canSubmit, submitResult] = yield* Subscribable.useSubscribables([
|
const [canSubmit, submitResult] = yield* Subscribable.useSubscribables([
|
||||||
form.canSubmit,
|
form.canSubmit,
|
||||||
form.mutation.result,
|
form.mutation.result,
|
||||||
])
|
])
|
||||||
|
|
||||||
const runPromise = yield* Component.useRunPromise()
|
const runPromise = yield* Component.useRunPromise()
|
||||||
const TextFieldFormInput = yield* TextFieldFormInputView.use
|
const TextFieldFormInputFC = yield* TextFieldFormInput
|
||||||
|
|
||||||
yield* Component.useOnMount(() => Effect.gen(function*() {
|
yield* Component.useOnMount(() => Effect.gen(function*() {
|
||||||
yield* Effect.addFinalizer(() => Console.log("RegisterFormView unmounted"))
|
yield* Effect.addFinalizer(() => Console.log("RegisterFormView unmounted"))
|
||||||
@@ -85,15 +85,15 @@ class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
|||||||
void runPromise(form.submit)
|
void runPromise(form.submit)
|
||||||
}}>
|
}}>
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<TextFieldFormInput
|
<TextFieldFormInputFC
|
||||||
field={yield* form.field(["email"])}
|
field={yield* form.field(["email"])}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextFieldFormInput
|
<TextFieldFormInputFC
|
||||||
field={yield* form.field(["password"])}
|
field={yield* form.field(["password"])}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextFieldFormInput
|
<TextFieldFormInputFC
|
||||||
optional
|
optional
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
field={yield* form.field(["birth"])}
|
field={yield* form.field(["birth"])}
|
||||||
@@ -115,13 +115,13 @@ class RegisterFormView extends Component.make("RegisterFormView")(function*() {
|
|||||||
)
|
)
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
const RegisterPage = Component.make("RegisterPageView")(function*() {
|
const RegisterPage = Component.makeUntraced("RegisterPage")(function*() {
|
||||||
const RegisterForm = yield* Effect.provide(
|
const RegisterFormViewFC = yield* Effect.provide(
|
||||||
RegisterFormView.use,
|
RegisterFormView,
|
||||||
yield* Component.useContextFromLayer(RegisterFormService.Default),
|
yield* Component.useContext(RegisterForm.Default),
|
||||||
)
|
)
|
||||||
|
|
||||||
return <RegisterForm />
|
return <RegisterFormViewFC />
|
||||||
}).pipe(
|
}).pipe(
|
||||||
Component.withRuntime(runtime.context)
|
Component.withRuntime(runtime.context)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import { createFileRoute } from "@tanstack/react-router"
|
|||||||
import { Effect } from "effect"
|
import { Effect } from "effect"
|
||||||
import { Component } from "effect-fc"
|
import { Component } from "effect-fc"
|
||||||
import { runtime } from "@/runtime"
|
import { runtime } from "@/runtime"
|
||||||
import { TodosState } from "@/todo/TodosState"
|
import { Todos } from "@/todo/Todos"
|
||||||
import { TodosView } from "@/todo/TodosView"
|
import { TodosState } from "@/todo/TodosState.service"
|
||||||
|
|
||||||
|
|
||||||
const TodosStateLive = TodosState.Default("todos")
|
const TodosStateLive = TodosState.Default("todos")
|
||||||
|
|
||||||
const Index = Component.make("IndexView")(function*() {
|
const Index = Component.makeUntraced("Index")(function*() {
|
||||||
const Todos = yield* Effect.provide(
|
const TodosFC = yield* Effect.provide(
|
||||||
TodosView.use,
|
Todos,
|
||||||
yield* Component.useContextFromLayer(TodosStateLive),
|
yield* Component.useContext(TodosStateLive),
|
||||||
)
|
)
|
||||||
|
|
||||||
return <Todos />
|
return <TodosFC />
|
||||||
}).pipe(
|
}).pipe(
|
||||||
Component.withRuntime(runtime.context)
|
Component.withRuntime(runtime.context)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,22 +13,21 @@ const Post = Schema.Struct({
|
|||||||
body: Schema.String,
|
body: Schema.String,
|
||||||
})
|
})
|
||||||
|
|
||||||
const ResultView = Component.make("ResultView")(function*() {
|
const ResultView = Component.makeUntraced("Result")(function*() {
|
||||||
const runPromise = yield* Component.useRunPromise()
|
const runPromise = yield* Component.useRunPromise()
|
||||||
|
|
||||||
const [idRef, query, mutation] = yield* Component.useOnMount(() => Effect.gen(function*() {
|
const [idRef, query, mutation] = yield* Component.useOnMount(() => Effect.gen(function*() {
|
||||||
const idRef = yield* SubscriptionRef.make(1)
|
const idRef = yield* SubscriptionRef.make(1)
|
||||||
const key = Stream.map(idRef.changes, id => [id] as const)
|
const key = Stream.zipLatest(Stream.make("posts" as const), idRef.changes)
|
||||||
|
|
||||||
const query = yield* Query.service({
|
const query = yield* Query.service({
|
||||||
key,
|
key,
|
||||||
f: ([id]) => HttpClient.HttpClient.pipe(
|
f: ([, id]) => HttpClient.HttpClient.pipe(
|
||||||
Effect.tap(Effect.sleep("500 millis")),
|
Effect.tap(Effect.sleep("500 millis")),
|
||||||
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
|
Effect.andThen(client => client.get(`https://jsonplaceholder.typicode.com/posts/${ id }`)),
|
||||||
Effect.andThen(response => response.json),
|
Effect.andThen(response => response.json),
|
||||||
Effect.andThen(Schema.decodeUnknown(Post)),
|
Effect.andThen(Schema.decodeUnknown(Post)),
|
||||||
),
|
),
|
||||||
staleTime: "10 seconds",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const mutation = yield* Mutation.make({
|
const mutation = yield* Mutation.make({
|
||||||
@@ -75,7 +74,7 @@ const ResultView = Component.make("ResultView")(function*() {
|
|||||||
Match.tag("Success", result => <>
|
Match.tag("Success", result => <>
|
||||||
<Heading>{result.value.title}</Heading>
|
<Heading>{result.value.title}</Heading>
|
||||||
<Text>{result.value.body}</Text>
|
<Text>{result.value.body}</Text>
|
||||||
{Result.hasRefreshingFlag(result) && <Text>Refreshing...</Text>}
|
{Result.isRefreshing(result) && <Text>Refreshing...</Text>}
|
||||||
</>),
|
</>),
|
||||||
Match.tag("Failure", result =>
|
Match.tag("Failure", result =>
|
||||||
<Text>An error has occured: {result.cause.toString()}</Text>
|
<Text>An error has occured: {result.cause.toString()}</Text>
|
||||||
@@ -86,7 +85,7 @@ const ResultView = Component.make("ResultView")(function*() {
|
|||||||
|
|
||||||
<Flex direction="row" justify="center" align="center" gap="1">
|
<Flex direction="row" justify="center" align="center" gap="1">
|
||||||
<Button onClick={() => runPromise(query.refresh)}>Refresh</Button>
|
<Button onClick={() => runPromise(query.refresh)}>Refresh</Button>
|
||||||
<Button onClick={() => runPromise(query.invalidateCache)}>Invalidate cache</Button>
|
<Button onClick={() => runPromise(query.refetch)}>Refetch</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -95,7 +94,7 @@ const ResultView = Component.make("ResultView")(function*() {
|
|||||||
Match.tag("Success", result => <>
|
Match.tag("Success", result => <>
|
||||||
<Heading>{result.value.title}</Heading>
|
<Heading>{result.value.title}</Heading>
|
||||||
<Text>{result.value.body}</Text>
|
<Text>{result.value.body}</Text>
|
||||||
{Result.hasRefreshingFlag(result) && <Text>Refreshing...</Text>}
|
{Result.isRefreshing(result) && <Text>Refreshing...</Text>}
|
||||||
</>),
|
</>),
|
||||||
Match.tag("Failure", result =>
|
Match.tag("Failure", result =>
|
||||||
<Text>An error has occured: {result.cause.toString()}</Text>
|
<Text>An error has occured: {result.cause.toString()}</Text>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { Component, Form, Subscribable } from "effect-fc"
|
|||||||
import { FaArrowDown, FaArrowUp } from "react-icons/fa"
|
import { FaArrowDown, FaArrowUp } from "react-icons/fa"
|
||||||
import { FaDeleteLeft } from "react-icons/fa6"
|
import { FaDeleteLeft } from "react-icons/fa6"
|
||||||
import * as Domain from "@/domain"
|
import * as Domain from "@/domain"
|
||||||
import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView"
|
import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput"
|
||||||
import { DateTimeUtcFromZonedInput } from "@/lib/schema"
|
import { DateTimeUtcFromZonedInput } from "@/lib/schema"
|
||||||
import { TodosState } from "./TodosState"
|
import { TodosState } from "./TodosState.service"
|
||||||
|
|
||||||
|
|
||||||
const TodoFormSchema = Schema.compose(Schema.Struct({
|
const TodoFormSchema = Schema.compose(Schema.Struct({
|
||||||
@@ -30,7 +30,7 @@ export type TodoProps = (
|
|||||||
| { readonly _tag: "edit", readonly id: string }
|
| { readonly _tag: "edit", readonly id: string }
|
||||||
)
|
)
|
||||||
|
|
||||||
export class TodoView extends Component.make("TodoView")(function*(props: TodoProps) {
|
export class Todo extends Component.makeUntraced("Todo")(function*(props: TodoProps) {
|
||||||
const state = yield* TodosState
|
const state = yield* TodosState
|
||||||
|
|
||||||
const [
|
const [
|
||||||
@@ -83,17 +83,17 @@ export class TodoView extends Component.make("TodoView")(function*(props: TodoPr
|
|||||||
|
|
||||||
const runSync = yield* Component.useRunSync()
|
const runSync = yield* Component.useRunSync()
|
||||||
const runPromise = yield* Component.useRunPromise<DateTime.CurrentTimeZone>()
|
const runPromise = yield* Component.useRunPromise<DateTime.CurrentTimeZone>()
|
||||||
const TextFieldFormInput = yield* TextFieldFormInputView.use
|
const TextFieldFormInputFC = yield* TextFieldFormInput
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" align="center" gap="2">
|
<Flex direction="row" align="center" gap="2">
|
||||||
<Box flexGrow="1">
|
<Box flexGrow="1">
|
||||||
<Flex direction="column" align="stretch" gap="2">
|
<Flex direction="column" align="stretch" gap="2">
|
||||||
<TextFieldFormInput field={contentField} />
|
<TextFieldFormInputFC field={contentField} />
|
||||||
|
|
||||||
<Flex direction="row" justify="center" align="center" gap="2">
|
<Flex direction="row" justify="center" align="center" gap="2">
|
||||||
<TextFieldFormInput
|
<TextFieldFormInputFC
|
||||||
optional
|
optional
|
||||||
field={completedAtField}
|
field={completedAtField}
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Container, Flex, Heading } from "@radix-ui/themes"
|
import { Container, Flex, Heading } from "@radix-ui/themes"
|
||||||
import { Chunk, Console, Effect } from "effect"
|
import { Chunk, Console, Effect } from "effect"
|
||||||
import { Component, Subscribable } from "effect-fc"
|
import { Component, Subscribable } from "effect-fc"
|
||||||
import { TodosState } from "./TodosState"
|
import { Todo } from "./Todo"
|
||||||
import { TodoView } from "./TodoView"
|
import { TodosState } from "./TodosState.service"
|
||||||
|
|
||||||
|
|
||||||
export class TodosView extends Component.make("TodosView")(function*() {
|
export class Todos extends Component.makeUntraced("Todos")(function*() {
|
||||||
const state = yield* TodosState
|
const state = yield* TodosState
|
||||||
const [todos] = yield* Subscribable.useSubscribables([state.ref])
|
const [todos] = yield* Subscribable.useSubscribables([state.ref])
|
||||||
|
|
||||||
@@ -14,17 +14,17 @@ export class TodosView extends Component.make("TodosView")(function*() {
|
|||||||
Effect.addFinalizer(() => Console.log("Todos unmounted")),
|
Effect.addFinalizer(() => Console.log("Todos unmounted")),
|
||||||
))
|
))
|
||||||
|
|
||||||
const Todo = yield* TodoView.use
|
const TodoFC = yield* Todo
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Heading align="center">Todos</Heading>
|
<Heading align="center">Todos</Heading>
|
||||||
|
|
||||||
<Flex direction="column" align="stretch" gap="2" mt="2">
|
<Flex direction="column" align="stretch" gap="2" mt="2">
|
||||||
<Todo _tag="new" />
|
<TodoFC _tag="new" />
|
||||||
|
|
||||||
{Chunk.map(todos, todo =>
|
{Chunk.map(todos, todo =>
|
||||||
<Todo key={todo.id} _tag="edit" id={todo.id} />
|
<TodoFC key={todo.id} _tag="edit" id={todo.id} />
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Container>
|
</Container>
|
||||||
Reference in New Issue
Block a user