From 1b1a1961bced88452a594d90ccb13fa2641566ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 17 Feb 2025 00:16:41 +0100 Subject: [PATCH 001/101] Dependencies upgrade --- .npmrc | 1 + bun.lockb | Bin 153528 -> 167960 bytes packages/example/package.json | 32 +++++++++++++------------- packages/example/src/routes/tests.tsx | 18 +++++++-------- packages/reffuse/package.json | 4 ++-- 5 files changed, 28 insertions(+), 27 deletions(-) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7bd7ffe --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@thilawyn:registry=https://git.valverde.cloud/api/packages/thilawyn/npm/ diff --git a/bun.lockb b/bun.lockb index fa0518b996a55f809b137efb772d51e4a8a05f45..f1328ff7c71c6a2e2778df70f333aec4ab26b55a 100755 GIT binary patch delta 47462 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 diff --git a/packages/example/package.json b/packages/example/package.json index ee4ebd4..b78aa7f 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -11,32 +11,32 @@ "preview": "vite preview" }, "devDependencies": { - "@eslint/js": "^9.18.0", - "@tanstack/react-router": "^1.97.3", - "@tanstack/router-devtools": "^1.97.3", - "@tanstack/router-plugin": "^1.97.3", + "@eslint/js": "^9.20.0", + "@tanstack/react-router": "^1.105.0", + "@tanstack/router-devtools": "^1.105.0", + "@tanstack/router-plugin": "^1.105.0", "@thilawyn/thilaschema": "^0.1.4", - "@types/react": "^19.0.7", + "@types/react": "^19.0.9", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "effect": "^3.12.5", - "eslint": "^9.18.0", + "effect": "^3.13.1", + "eslint": "^9.20.1", "eslint-plugin-react-hooks": "^5.1.0", - "eslint-plugin-react-refresh": "^0.4.18", - "globals": "^15.14.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", "react": "^19.0.0", "react-dom": "^19.0.0", "reffuse": "workspace:*", - "typescript-eslint": "^8.21.0", - "vite": "^6.0.11" + "typescript-eslint": "^8.24.0", + "vite": "^6.1.0" }, "dependencies": { - "@effect/platform": "^0.74.0", - "@effect/platform-browser": "^0.53.0", - "@radix-ui/themes": "^3.1.6", + "@effect/platform": "^0.77.1", + "@effect/platform-browser": "^0.56.1", + "@radix-ui/themes": "^3.2.0", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", - "lucide-react": "^0.473.0", - "mobx": "^6.13.5" + "lucide-react": "^0.475.0", + "mobx": "^6.13.6" } } diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index a019c4b..28117f0 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -1,6 +1,5 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { GetRandomValues, makeUuid4 } from "@typed/id" import { Console, Effect } from "effect" @@ -9,15 +8,16 @@ export const Route = createFileRoute("/tests")({ }) function RouteComponent() { - // R.useMemo(Effect.addFinalizer(() => Console.log("Cleanup!")).pipe( - // Effect.map(() => "test") - // )) + // const value = R.useMemoScoped(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + // Effect.andThen(makeUuid4), + // Effect.provide(GetRandomValues.CryptoRandom), + // ), []) + // console.log(value) - const value = R.useMemoScoped(Effect.addFinalizer(() => Console.log("cleanup")).pipe( - Effect.andThen(makeUuid4), - Effect.provide(GetRandomValues.CryptoRandom), - ), []) - console.log(value) + R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + Effect.andThen(Console.log("ouient")), + Effect.delay("1 second"), + )) return

Hello "/tests"!
} diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index d729b00..925e4a7 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -30,8 +30,8 @@ }, "devDependencies": { "@typed/lazy-ref": "^0.3.3", - "@types/react": "^19.0.7", - "effect": "^3.12.5", + "@types/react": "^19.0.9", + "effect": "^3.13.1", "react": "^19.0.0" } } -- 2.49.1 From a7a0951b6168e3e03f84e9746b892a1d7d0d5ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 01:08:26 +0100 Subject: [PATCH 002/101] Dependencies fix --- bun.lock | 803 ++++++++++++++++++ bun.lockb | Bin 167960 -> 0 bytes package.json | 4 +- packages/example/package.json | 19 +- packages/example/src/routes/time.tsx | 4 +- packages/example/src/todos/views/VNewTodo.tsx | 4 +- packages/reffuse/package.json | 5 +- packages/reffuse/src/Reffuse.ts | 41 +- 8 files changed, 839 insertions(+), 41 deletions(-) create mode 100644 bun.lock delete mode 100755 bun.lockb diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..bf4b7fe --- /dev/null +++ b/bun.lock @@ -0,0 +1,803 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "devDependencies": { + "npm-check-updates": "^17.1.14", + "npm-sort": "^0.0.4", + "typescript": "^5.7.3", + }, + }, + "packages/example": { + "name": "@reffuse/example", + "version": "0.0.0", + "dependencies": { + "@effect/platform": "~0.77.1", + "@effect/platform-browser": "~0.56.1", + "@radix-ui/themes": "^3.2.0", + "@typed/id": "^0.17.1", + "@typed/lazy-ref": "^0.3.3", + "effect": "~3.13.1", + "lucide-react": "^0.475.0", + "mobx": "^6.13.6", + "reffuse": "workspace:*", + }, + "devDependencies": { + "@eslint/js": "^9.20.0", + "@tanstack/react-router": "^1.105.0", + "@tanstack/router-devtools": "^1.105.0", + "@tanstack/router-plugin": "^1.105.0", + "@thilawyn/thilaschema": "^0.1.4", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.20.1", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "typescript-eslint": "^8.24.1", + "vite": "^6.1.0", + }, + }, + "packages/reffuse": { + "name": "reffuse", + "version": "0.1.1", + "devDependencies": { + "@types/react": "^19.0.10", + "effect": "~3.13.1", + "react": "^19.0.0", + }, + }, + }, + "packages": { + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + + "@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], + + "@babel/compat-data": ["@babel/compat-data@7.26.8", "", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="], + + "@babel/core": ["@babel/core@7.26.9", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.9", "@babel/types": "^7.26.9", "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-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw=="], + + "@babel/generator": ["@babel/generator@7.26.9", "", { "dependencies": { "@babel/parser": "^7.26.9", "@babel/types": "^7.26.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.26.5", "", { "dependencies": { "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.26.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.25.9", "", {}, "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw=="], + + "@babel/helpers": ["@babel/helpers@7.26.9", "", { "dependencies": { "@babel/template": "^7.26.9", "@babel/types": "^7.26.9" } }, "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA=="], + + "@babel/parser": ["@babel/parser@7.26.9", "", { "dependencies": { "@babel/types": "^7.26.9" }, "bin": "./bin/babel-parser.js" }, "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="], + + "@babel/template": ["@babel/template@7.26.9", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.26.9", "@babel/types": "^7.26.9" } }, "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA=="], + + "@babel/traverse": ["@babel/traverse@7.26.9", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.9", "@babel/parser": "^7.26.9", "@babel/template": "^7.26.9", "@babel/types": "^7.26.9", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg=="], + + "@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="], + + "@effect/platform": ["@effect/platform@0.77.1", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.13.1" } }, "sha512-3oHbKiOLN7AIjyucZW+kH5ebG1PhEEBrsdd+HWbDQbAG0gVZfgOUmXR9cyM6M9L+9oVPgOW5mIgcEi6RvD02Cw=="], + + "@effect/platform-browser": ["@effect/platform-browser@0.56.1", "", { "dependencies": { "multipasta": "^0.2.5" }, "peerDependencies": { "@effect/platform": "^0.77.1", "effect": "^3.13.1" } }, "sha512-LKuLblMHuHKsv9ZdN8j44zzY4ftQaGh5jsOWqTtoHIDSS8beUOcp2a5JnsRT310N4Ym7e14cKWfqgdAXm+J0dw=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.24.2", "", { "os": "android", "cpu": "x64" }, "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.24.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.24.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.24.2", "", { "os": "none", "cpu": "x64" }, "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.24.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.24.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.24.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + + "@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="], + + "@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="], + + "@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="], + + "@floating-ui/core": ["@floating-ui/core@1.6.9", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.6.13", "", { "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.9" } }, "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.2", "", { "dependencies": { "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.9", "", {}, "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@radix-ui/colors": ["@radix-ui/colors@3.0.0", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="], + + "@radix-ui/number": ["@radix-ui/number@1.1.0", "", {}, "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="], + + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.2", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.1.2" }, "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-+rnMO0SEfzkcHr93RshkQVpOA26MtGOv4pcS9QUnLg4F8+GDmCJ8c2FEPhPz5e7arf31EzbTqJxFbzg3qen14g=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collapsible": "1.1.3", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A=="], + + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dialog": "1.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2" }, "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-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "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-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg=="], + + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "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-TaJxYoCpxJ7vfEkv2PTNox/6zzmpKXT6ewvCuf2tTOIVN45/Jahhlld29Yw4pciOXS2Xq91/rSGEdmEnUWZCqA=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.3", "", { "dependencies": { "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, "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-Paen00T4P8L8gd9bNsRMw7Cbaz85oxiv+hzomsRZgFm2byltPFDtfcoqlWJ8GyZlIBWgLssJlzLCnKU0G0302g=="], + + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "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-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw=="], + + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, "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-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2" }, "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-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="], + + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-menu": "2.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "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-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="], + + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-menu": "2.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "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-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA=="], + + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-label": "2.1.2", "@radix-ui/react-primitive": "2.0.2" }, "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-Owj1MjLq6/Rp85bgzYI+zRK5APLiWDtXDM63Z39FW15bNdehrcS+FjQgLGQYswFzipYu4GAA+t5w/VqvvNZ3ag=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.0", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA=="], + + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "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-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw=="], + + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg=="], + + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-menu": "2.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-FHq7+3DlXwh/7FOM4i0G4bC4vPjiq89VEEvNF4VMLchGnaUuUbE5uKXMUCjdKaOghEEMeiKa5XCa2Pk4kteWmg=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2" }, "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-myMHHQUZ3ZLTi8W381/Vu43Ia0NqakkQZ2vzynMmTUtQQ9kNkjzhOwkZC9TAM5R07OZUVIQyHC06f/9JZJpvvA=="], + + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.2", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-rect": "1.1.0", "@radix-ui/react-use-size": "1.1.0", "@radix-ui/rect": "1.1.0" }, "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-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "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-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.0" }, "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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.2" }, "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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="], + + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.2", "", { "dependencies": { "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2" }, "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-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA=="], + + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.2.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "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-xtCsqt8Rp09FK50ItqEqTJ7Sxanz8EM8dnkVIhJrc/wkMMomSmXHvYbhv3E7Zx4oXh98aaLt9W679SUYXg4IDA=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw=="], + + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.3", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, "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-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ=="], + + "@radix-ui/react-select": ["@radix-ui/react-select@2.1.6", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.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-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg=="], + + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "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-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ=="], + + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.2.3", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "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-nNrLAWLjGESnhqBqcCNW4w2nn7LxudyMzeB6VgdyAnFLC6kfQgnAjSL2v6UkQTnDctJBlxrmxfplWS4iYjdUTw=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="], + + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "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-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ=="], + + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng=="], + + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2" }, "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-gN4dpuIVKEgpLn1z5FhzT9mYRUitbfZq9XqN/7kkBMUgFTzTG8x/KszWJugJXHcwxckY8xcKDZPz7kG3o6DsUA=="], + + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ=="], + + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-toggle": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "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-JBm6s6aVG/nwuY5eadhU2zDi/IwYS0sDM5ZWb4nymv/hn3hZdkw+gENn0LP4iY1yCd7+bgJaCwueMYJIU3vk4A=="], + + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-separator": "1.1.2", "@radix-ui/react-toggle-group": "1.1.2" }, "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-wT20eQ7ScFk+kBMDmHp+lMk18cgxhu35b2Bn5deUcPxiVwfn5vuZgi7NGcHu8ocdkinahmp4FaSZysKDyRVPWQ=="], + + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2" }, "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-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="], + + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og=="], + + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.0", "", { "dependencies": { "@radix-ui/rect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.0", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw=="], + + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "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-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.0", "", {}, "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="], + + "@radix-ui/themes": ["@radix-ui/themes@3.2.0", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.2", "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-cG/47tfHN9FW1ZoAigd3oUeJaIm591vGtQ97PrhfwS22IJgWhE5h6D0w2m+NVbKRVo8qIWCG+hiWN04MlLoW4A=="], + + "@reffuse/example": ["@reffuse/example@workspace:packages/example"], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="], + + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="], + + "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + + "@tanstack/history": ["@tanstack/history@1.99.13", "", {}, "sha512-JMd7USmnp8zV8BRGIjALqzPxazvKtQ7PGXQC7n39HpbqdsmfV2ePCzieO84IvN+mwsTrXErpbjI4BfKCa+ZNCg=="], + + "@tanstack/react-router": ["@tanstack/react-router@1.105.0", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "^1.104.1", "jsesc": "^3.1.0", "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-k4Umuy7rna/hhfHkmbq9dCmj9Hp8D0V6dPNCrCXceJb0gQWGxl1KWLXFbw8Ywe/sNyzIzPrMwrMit++MXHo8iw=="], + + "@tanstack/react-store": ["@tanstack/react-store@0.7.0", "", { "dependencies": { "@tanstack/store": "0.7.0", "use-sync-external-store": "^1.4.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-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng=="], + + "@tanstack/router-core": ["@tanstack/router-core@1.104.1", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/store": "^0.7.0" } }, "sha512-8nP/V5paP+S/17rlw+B2F12R2bB9PixU/+qnD2QdCjK1ajnG4qA0pVN3VSTQe2oCKND6GPZpm2ikmQWumwss9Q=="], + + "@tanstack/router-devtools": ["@tanstack/router-devtools@1.105.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/react-router": "^1.105.0", "csstype": "^3.0.10", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["csstype"] }, "sha512-X583hyUyhL30g5ax1J/lbgb3DYpgsiSUv0ERaF5Gg0PoxPYJSybmw79xwFbrTBDxXCXxfg4AFCAEcmkAQemPWA=="], + + "@tanstack/router-generator": ["@tanstack/router-generator@1.105.0", "", { "dependencies": { "@tanstack/virtual-file-routes": "^1.99.0", "prettier": "^3.5.0", "tsx": "^4.19.2", "zod": "^3.24.1" }, "peerDependencies": { "@tanstack/react-router": "^1.105.0" }, "optionalPeers": ["@tanstack/react-router"] }, "sha512-P5e4S7XcaECWKDdR4Zs/FpY4Z127zGv1FcmKEzsFRSGJZm7lHshWayYJIjwkeJ+Ier2IkVN+VRaFWC5GKv0jIg=="], + + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.105.0", "", { "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-generator": "^1.105.0", "@tanstack/router-utils": "^1.102.2", "@tanstack/virtual-file-routes": "^1.99.0", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/babel__traverse": "^7.20.6", "babel-dead-code-elimination": "^1.0.9", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.1" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.105.0", "vite": ">=5.0.0 || >=6.0.0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "webpack"] }, "sha512-iGwKZIyl8+os4PA9v57BlTtKVnQ5mCvxYT4p5TR/Q8zW1KBs4fC5F7EhL1BgH8fY12IL4ByuuJ+porzp+mfmJQ=="], + + "@tanstack/router-utils": ["@tanstack/router-utils@1.102.2", "", { "dependencies": { "@babel/generator": "^7.26.8", "@babel/parser": "^7.26.8", "ansis": "^3.11.0", "diff": "^7.0.0" } }, "sha512-Uwl2nbrxhCzviaHHBLNPhSC/OMpZLdOTxTJndUSsXTzWUP4IoQcVmngaIsxi9iriE3ArC1VXuanUAkfGmimNOQ=="], + + "@tanstack/store": ["@tanstack/store@0.7.0", "", {}, "sha512-CNIhdoUsmD2NolYuaIs8VfWM467RK6oIBAW4nPEKZhg1smZ+/CwtCdpURgp7nxSqOaV9oKkzdWD80+bC66F/Jg=="], + + "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.99.0", "", {}, "sha512-XvX8bfdo4CYiCW+ItVdBfCorh3PwQFqYqd7ll+XKWiWOJpqUGIG7VlziVavARZpUySiY2VBlHadiUYS7jhgjRg=="], + + "@thilawyn/thilaschema": ["@thilawyn/thilaschema@0.1.4", "https://git.valverde.cloud/api/packages/Thilawyn/npm/%40thilawyn%2Fthilaschema/-/0.1.4/thilaschema-0.1.4.tgz", { "dependencies": { "remeda": "^2.17.0", "type-fest": "^4.26.1" } }, "sha512-o+lFjnRrD8N7kJtToKl+OYvVnOwaCGr1X9yMSX/8Y1n4KopOOGFSA9xqmx+MpMe3okp2Hq3Xu1aGHzFsZWxc2A=="], + + "@typed/id": ["@typed/id@0.17.1", "", { "dependencies": { "effect": "^3.11.9" } }, "sha512-+nypUUw6PJWePD1aF1CHY4995hDF3VA9c8EBtp1M+pTnyLBZQIkgKbOKamimnl4U+ZV5I3qC+3q1Y4hpmxT+zw=="], + + "@typed/lazy-ref": ["@typed/lazy-ref@0.3.3", "", { "dependencies": { "effect": "^3.11.9" } }, "sha512-qJoy01/RFYwWBaWhQBzL3Ow20Q+CPybJ/KJnGNKzyDpRUFcEvd3YSQMqZjRdBZmG2wnEpjedAnlCx9ApvKJIlA=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.6.8", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.20.6", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg=="], + + "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/react": ["@types/react@19.0.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g=="], + + "@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.24.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/type-utils": "8.24.1", "@typescript-eslint/utils": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.24.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/types": "8.24.1", "@typescript-eslint/typescript-estree": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1" } }, "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.24.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.24.1", "@typescript-eslint/utils": "8.24.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.24.1", "", {}, "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.24.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/types": "8.24.1", "@typescript-eslint/typescript-estree": "8.24.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="], + + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ansis": ["ansis@3.15.0", "", {}, "sha512-zIcWDJ+Kwqxfdnogx66Gxzr0kVmCcRAdat9nlY2IHsshqTN4fBH6tMeRMPA/2w0rpBayIJvjQAaa2/4RDrNqwg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-hidden": ["aria-hidden@1.2.4", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A=="], + + "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.9", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-JLIhax/xullfInZjtu13UJjaLHDeTzt3vOeomaSUdO/nAMEL/pWC/laKrSvWylXMnVWyL5bpmG9njqBZlUQOdg=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001700", "", {}, "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "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=="], + + "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + + "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], + + "effect": ["effect@3.13.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-YbA45m51eZapqy/ptZvIIZi+XBj13fPCzbiDRLgxZTEUhKuf4xLzuuSsKc61Y3SIscMM2o+VPht2ty+bVEQHQQ=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.102", "", {}, "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q=="], + + "esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.20.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.1.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw=="], + + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.19", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ=="], + + "eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], + + "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="], + + "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-my-way-ts": ["find-my-way-ts@0.1.5", "", {}, "sha512-4GOTMrpGQVzsCH2ruUn2vmwzV/02zF4q+ybhCIrw/Rkt3L8KWcycdC6aJMctJzwN4fXD4SD5F/4B9Sksh5rE0A=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + + "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], + + "goober": ["goober@2.1.16", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g=="], + + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "lucide-react": ["lucide-react@0.475.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "mobx": ["mobx@6.13.6", "", {}, "sha512-r19KNV0uBN4b+ER8Z0gA4y+MzDYIQ2SvOmn3fUrqPnWXdQfakd9yfbPBDBF/p5I+bd3N5Rk1fHONIvMay+bJGA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "multipasta": ["multipasta@0.2.5", "", {}, "sha512-c8eMDb1WwZcE02WVjHoOmUVk7fnKU/RmUcosHACglrWAuPQsEJv+E8430sXj6jNc1jHw0zrS16aCjQh4BcEb4A=="], + + "nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "npm-check-updates": ["npm-check-updates@17.1.14", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-dr4bXIxETubLI1tFGeock5hN8yVjahvaVpx+lPO4/O2md3zJuxB7FgH3MIoTvQSCgsgkIRpe0skti01IEAA5tA=="], + + "npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "postcss": ["postcss@8.5.2", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.5.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "radix-ui": ["radix-ui@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-accessible-icon": "1.1.2", "@radix-ui/react-accordion": "1.2.3", "@radix-ui/react-alert-dialog": "1.1.6", "@radix-ui/react-aspect-ratio": "1.1.2", "@radix-ui/react-avatar": "1.1.3", "@radix-ui/react-checkbox": "1.1.4", "@radix-ui/react-collapsible": "1.1.3", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-context-menu": "2.2.6", "@radix-ui/react-dialog": "1.1.6", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-dropdown-menu": "2.1.6", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-form": "0.1.2", "@radix-ui/react-hover-card": "1.1.6", "@radix-ui/react-label": "2.1.2", "@radix-ui/react-menu": "2.1.6", "@radix-ui/react-menubar": "1.1.6", "@radix-ui/react-navigation-menu": "1.2.5", "@radix-ui/react-popover": "1.1.6", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-progress": "1.1.2", "@radix-ui/react-radio-group": "1.2.3", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-scroll-area": "1.2.3", "@radix-ui/react-select": "2.1.6", "@radix-ui/react-separator": "1.1.2", "@radix-ui/react-slider": "1.2.3", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-switch": "1.1.3", "@radix-ui/react-tabs": "1.1.3", "@radix-ui/react-toast": "1.2.6", "@radix-ui/react-toggle": "1.1.2", "@radix-ui/react-toggle-group": "1.1.2", "@radix-ui/react-toolbar": "1.1.2", "@radix-ui/react-tooltip": "1.1.8", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-size": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2" }, "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-W8L6soM1vQnIXVvVa31AkQhoZBDPwVoNHhT13R3aB9Qq7ARYIUS9DLaCopRBsbTdZm1NEEPx3rnq659CiNOBDw=="], + + "react": ["react@19.0.0", "", {}, "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="], + + "react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="], + + "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], + + "react-remove-scroll": ["react-remove-scroll@2.6.3", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "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-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "reffuse": ["reffuse@workspace:packages/reffuse"], + + "remeda": ["remeda@2.20.2", "", { "dependencies": { "type-fest": "^4.33.0" } }, "sha512-38pfm5aUq6mUkNYbt7TdY2WEk9mSqRVV+6UsoTjabwmbu8obLbh8sYYSX2WQ3W4u6EYp3XxUKqIiwGFZu+OY9g=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], + + "rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + + "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "ts-api-utils": ["ts-api-utils@2.0.1", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsx": ["tsx@4.19.2", "", { "dependencies": { "esbuild": "~0.23.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-fest": ["type-fest@4.35.0", "", {}, "sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A=="], + + "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], + + "typescript-eslint": ["typescript-eslint@8.24.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.24.1", "@typescript-eslint/parser": "8.24.1", "@typescript-eslint/utils": "8.24.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA=="], + + "unplugin": ["unplugin@2.2.0", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw=="], + + "update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "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-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "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-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + + "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="], + + "vite": ["vite@6.1.0", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.5.1", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ=="], + + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], + + "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="], + + "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "tsx/esbuild": ["esbuild@0.23.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.23.1", "@esbuild/android-arm": "0.23.1", "@esbuild/android-arm64": "0.23.1", "@esbuild/android-x64": "0.23.1", "@esbuild/darwin-arm64": "0.23.1", "@esbuild/darwin-x64": "0.23.1", "@esbuild/freebsd-arm64": "0.23.1", "@esbuild/freebsd-x64": "0.23.1", "@esbuild/linux-arm": "0.23.1", "@esbuild/linux-arm64": "0.23.1", "@esbuild/linux-ia32": "0.23.1", "@esbuild/linux-loong64": "0.23.1", "@esbuild/linux-mips64el": "0.23.1", "@esbuild/linux-ppc64": "0.23.1", "@esbuild/linux-riscv64": "0.23.1", "@esbuild/linux-s390x": "0.23.1", "@esbuild/linux-x64": "0.23.1", "@esbuild/netbsd-x64": "0.23.1", "@esbuild/openbsd-arm64": "0.23.1", "@esbuild/openbsd-x64": "0.23.1", "@esbuild/sunos-x64": "0.23.1", "@esbuild/win32-arm64": "0.23.1", "@esbuild/win32-ia32": "0.23.1", "@esbuild/win32-x64": "0.23.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.23.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ=="], + + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.23.1", "", { "os": "android", "cpu": "arm" }, "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ=="], + + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.23.1", "", { "os": "android", "cpu": "arm64" }, "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw=="], + + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.23.1", "", { "os": "android", "cpu": "x64" }, "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg=="], + + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.23.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q=="], + + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.23.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw=="], + + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.23.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA=="], + + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.23.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g=="], + + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.23.1", "", { "os": "linux", "cpu": "arm" }, "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ=="], + + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.23.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g=="], + + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.23.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ=="], + + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw=="], + + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q=="], + + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.23.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw=="], + + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA=="], + + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.23.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw=="], + + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.23.1", "", { "os": "linux", "cpu": "x64" }, "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ=="], + + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.23.1", "", { "os": "none", "cpu": "x64" }, "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA=="], + + "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.23.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q=="], + + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.23.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA=="], + + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.23.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA=="], + + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.23.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A=="], + + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.23.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ=="], + + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.23.1", "", { "os": "win32", "cpu": "x64" }, "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg=="], + } +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index f1328ff7c71c6a2e2778df70f333aec4ab26b55a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167960 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 Le@)JRi^u;1()8zj diff --git a/package.json b/package.json index 6c1b407..692bb61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,8 @@ { "private": true, - "workspaces": ["./packages/*"], + "workspaces": [ + "./packages/*" + ], "scripts": { "lint:tsc": "bun run --filter '*' lint:tsc", "clean:cache": "rm -f tsconfig.tsbuildinfo", diff --git a/packages/example/package.json b/packages/example/package.json index b78aa7f..2bb12a0 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -16,27 +16,30 @@ "@tanstack/router-devtools": "^1.105.0", "@tanstack/router-plugin": "^1.105.0", "@thilawyn/thilaschema": "^0.1.4", - "@types/react": "^19.0.9", - "@types/react-dom": "^19.0.3", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "effect": "^3.13.1", "eslint": "^9.20.1", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^15.15.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "reffuse": "workspace:*", - "typescript-eslint": "^8.24.0", + "typescript-eslint": "^8.24.1", "vite": "^6.1.0" }, "dependencies": { - "@effect/platform": "^0.77.1", - "@effect/platform-browser": "^0.56.1", + "@effect/platform": "~0.77.1", + "@effect/platform-browser": "~0.56.1", "@radix-ui/themes": "^3.2.0", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", + "effect": "~3.13.1", "lucide-react": "^0.475.0", - "mobx": "^6.13.6" + "mobx": "^6.13.6", + "reffuse": "workspace:*" + }, + "overrides": { + "effect": "~3.13.1" } } diff --git a/packages/example/src/routes/time.tsx b/packages/example/src/routes/time.tsx index 702a5ad..3a60060 100644 --- a/packages/example/src/routes/time.tsx +++ b/packages/example/src/routes/time.tsx @@ -1,6 +1,6 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { DateTime, Ref, Schedule, Stream } from "effect" +import { DateTime, Effect, Ref, Schedule, Stream, SubscriptionRef } from "effect" const timeEverySecond = Stream.repeatEffectWithSchedule( @@ -15,7 +15,7 @@ export const Route = createFileRoute("/time")({ function Time() { - const timeRef = R.useRefFromEffect(DateTime.now) + const timeRef = R.useMemo(DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make))) R.useFork(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v)), [timeRef]) const [time] = R.useRefState(timeRef) diff --git a/packages/example/src/todos/views/VNewTodo.tsx b/packages/example/src/todos/views/VNewTodo.tsx index fee4f16..eeb20f2 100644 --- a/packages/example/src/todos/views/VNewTodo.tsx +++ b/packages/example/src/todos/views/VNewTodo.tsx @@ -1,6 +1,6 @@ import { Todo } from "@/domain" import { Box, Button, Card, Flex, TextArea } from "@radix-ui/themes" -import { Effect, Option } from "effect" +import { Effect, Option, SubscriptionRef } from "effect" import { R } from "../reffuse" import { TodosState } from "../services" @@ -17,7 +17,7 @@ export function VNewTodo() { }, true)) ) - const todoRef = R.useRefFromEffect(createEmptyTodo) + const todoRef = R.useMemo(createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make))) const [todo, setTodo] = R.useRefState(todoRef) diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index 925e4a7..8b27899 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -29,9 +29,8 @@ "clean:node": "rm -rf node_modules" }, "devDependencies": { - "@typed/lazy-ref": "^0.3.3", - "@types/react": "^19.0.9", - "effect": "^3.13.1", + "@types/react": "^19.0.10", + "effect": "~3.13.1", "react": "^19.0.0" } } diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 9b1f114..897c5f1 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,4 +1,3 @@ -import * as LazyRef from "@typed/lazy-ref" import { Context, Effect, ExecutionStrategy, Exit, Fiber, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import React from "react" import * as ReffuseContext from "./ReffuseContext.js" @@ -115,12 +114,12 @@ export class Reffuse { const [value, setValue] = React.useState(initialValue) React.useEffect(() => { - const closeInitialScope = Scope.close(initialScope, Exit.void).pipe( + const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), Effect.when(() => !initialScopeClosed.current), ) - const [scope, value] = closeInitialScope.pipe( + const [scope, value] = closeInitialScopeIfNeeded.pipe( Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( Effect.flatMap(scope => effect.pipe( Effect.provideService(Scope.Scope, scope), @@ -332,14 +331,6 @@ export class Reffuse { ) } - useRefFromEffect(effect: Effect.Effect): SubscriptionRef.SubscriptionRef { - return this.useMemo( - effect.pipe(Effect.flatMap(SubscriptionRef.make)), - [], - { doNotReExecuteOnRuntimeOrContextChange: false }, // Do not recreate the ref when the context changes - ) - } - /** * Binds the state of a `SubscriptionRef` to the state of the React component. * @@ -373,24 +364,24 @@ export class Reffuse { * * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. */ - useLazyRefState(ref: LazyRef.LazyRef): [A, React.Dispatch>] { - const runSync = this.useRunSync() + // useLazyRefState(ref: LazyRef.LazyRef): [A, React.Dispatch>] { + // const runSync = this.useRunSync() - const initialState = React.useMemo(() => runSync(ref), []) - const [reactStateValue, setReactStateValue] = React.useState(initialState) + // const initialState = React.useMemo(() => runSync(ref), []) + // const [reactStateValue, setReactStateValue] = React.useState(initialState) - this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => - setReactStateValue(v) - )), [ref]) + // this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + // setReactStateValue(v) + // )), [ref]) - const setValue = React.useCallback((setStateAction: React.SetStateAction) => - runSync(LazyRef.update(ref, prevState => - SetStateAction.value(setStateAction, prevState) - )), - [ref]) + // const setValue = React.useCallback((setStateAction: React.SetStateAction) => + // runSync(LazyRef.update(ref, prevState => + // SetStateAction.value(setStateAction, prevState) + // )), + // [ref]) - return [reactStateValue, setValue] - } + // return [reactStateValue, setValue] + // } } -- 2.49.1 From bebbc1d7de2e3860f0dc7e32c5a594f56d5781ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 02:23:40 +0100 Subject: [PATCH 003/101] Promise tests --- packages/example/src/routes/tests.tsx | 29 ++++++++++++++++--- packages/example/src/todos/views/VNewTodo.tsx | 17 ++++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index 28117f0..8282be1 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -1,6 +1,8 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" +import { GetRandomValues, makeUuid4 } from "@typed/id" import { Console, Effect } from "effect" +import { useEffect, useState } from "react" export const Route = createFileRoute("/tests")({ @@ -14,10 +16,29 @@ function RouteComponent() { // ), []) // console.log(value) - R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( - Effect.andThen(Console.log("ouient")), - Effect.delay("1 second"), - )) + // R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + // Effect.andThen(Console.log("ouient")), + // Effect.delay("1 second"), + // )) + + const runPromise = R.useRunPromise() + const [promise, setPromise] = useState | null>(null) + const [, setValue] = useState("") + + useEffect(() => { + makeUuid4.pipe( + Effect.provide(GetRandomValues.CryptoRandom), + Effect.tap(id => Effect.sync(() => setValue(id))), + Effect.andThen(Console.log), + Effect.delay("1 second"), + + runPromise, + setPromise, + ) + }, [runPromise]) + + console.log(promise) + return
Hello "/tests"!
} diff --git a/packages/example/src/todos/views/VNewTodo.tsx b/packages/example/src/todos/views/VNewTodo.tsx index eeb20f2..ccb4346 100644 --- a/packages/example/src/todos/views/VNewTodo.tsx +++ b/packages/example/src/todos/views/VNewTodo.tsx @@ -5,18 +5,19 @@ import { R } from "../reffuse" import { TodosState } from "../services" +const createEmptyTodo = Todo.generateUniqueID.pipe( + Effect.map(id => Todo.Todo.make({ + id, + content: "", + completedAt: Option.none(), + }, true)) +) + + export function VNewTodo() { const runSync = R.useRunSync() - const createEmptyTodo = Todo.generateUniqueID.pipe( - Effect.map(id => Todo.Todo.make({ - id, - content: "", - completedAt: Option.none(), - }, true)) - ) - const todoRef = R.useMemo(createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make))) const [todo, setTodo] = R.useRefState(todoRef) -- 2.49.1 From e83e86f8f16db6ce589e014ce8f49a816532b9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 02:56:05 +0100 Subject: [PATCH 004/101] Promise tests --- packages/example/src/routeTree.gen.ts | 29 ++++++++++++++++++++--- packages/example/src/routes/__root.tsx | 1 + packages/example/src/routes/promise.tsx | 31 +++++++++++++++++++++++++ packages/example/src/routes/tests.tsx | 20 +++++++--------- 4 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 packages/example/src/routes/promise.tsx diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index 92e0a99..b1e3d9c 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -13,6 +13,7 @@ import { Route as rootRoute } from './routes/__root' import { Route as TimeImport } from './routes/time' import { Route as TestsImport } from './routes/tests' +import { Route as PromiseImport } from './routes/promise' import { Route as CountImport } from './routes/count' import { Route as BlankImport } from './routes/blank' import { Route as IndexImport } from './routes/index' @@ -31,6 +32,12 @@ const TestsRoute = TestsImport.update({ getParentRoute: () => rootRoute, } as any) +const PromiseRoute = PromiseImport.update({ + id: '/promise', + path: '/promise', + getParentRoute: () => rootRoute, +} as any) + const CountRoute = CountImport.update({ id: '/count', path: '/count', @@ -74,6 +81,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof CountImport parentRoute: typeof rootRoute } + '/promise': { + id: '/promise' + path: '/promise' + fullPath: '/promise' + preLoaderRoute: typeof PromiseImport + parentRoute: typeof rootRoute + } '/tests': { id: '/tests' path: '/tests' @@ -97,6 +111,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute } @@ -105,6 +120,7 @@ export interface FileRoutesByTo { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute } @@ -114,16 +130,17 @@ export interface FileRoutesById { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/blank' | '/count' | '/tests' | '/time' + fullPaths: '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' fileRoutesByTo: FileRoutesByTo - to: '/' | '/blank' | '/count' | '/tests' | '/time' - id: '__root__' | '/' | '/blank' | '/count' | '/tests' | '/time' + to: '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' + id: '__root__' | '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' fileRoutesById: FileRoutesById } @@ -131,6 +148,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlankRoute: typeof BlankRoute CountRoute: typeof CountRoute + PromiseRoute: typeof PromiseRoute TestsRoute: typeof TestsRoute TimeRoute: typeof TimeRoute } @@ -139,6 +157,7 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlankRoute: BlankRoute, CountRoute: CountRoute, + PromiseRoute: PromiseRoute, TestsRoute: TestsRoute, TimeRoute: TimeRoute, } @@ -156,6 +175,7 @@ export const routeTree = rootRoute "/", "/blank", "/count", + "/promise", "/tests", "/time" ] @@ -169,6 +189,9 @@ export const routeTree = rootRoute "/count": { "filePath": "count.tsx" }, + "/promise": { + "filePath": "promise.tsx" + }, "/tests": { "filePath": "tests.tsx" }, diff --git a/packages/example/src/routes/__root.tsx b/packages/example/src/routes/__root.tsx index b9e5fa0..e5a9b44 100644 --- a/packages/example/src/routes/__root.tsx +++ b/packages/example/src/routes/__root.tsx @@ -19,6 +19,7 @@ function Root() { Time Count Tests + Promise Blank diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx new file mode 100644 index 0000000..edb3e4f --- /dev/null +++ b/packages/example/src/routes/promise.tsx @@ -0,0 +1,31 @@ +import { R } from "@/reffuse" +import { HttpClient } from "@effect/platform" +import { createFileRoute } from "@tanstack/react-router" +import { Console, Effect } from "effect" +import { use, useMemo } from "react" + + +export const Route = createFileRoute("/promise")({ + component: RouteComponent +}) + +function RouteComponent() { + + const runPromise = R.useRunPromise() + + const promise = useMemo(() => HttpClient.HttpClient.pipe( + Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), + HttpClient.withTracerPropagation(false), + Effect.flatMap(res => res.json), + Effect.tap(Console.log), + + Effect.scoped, + runPromise, + ), [runPromise]) + + const value = use(promise) + + + return
Hello "/tests"!
+ +} diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index 8282be1..6961e11 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -2,7 +2,7 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" import { GetRandomValues, makeUuid4 } from "@typed/id" import { Console, Effect } from "effect" -import { useEffect, useState } from "react" +import { useMemo, useState } from "react" export const Route = createFileRoute("/tests")({ @@ -22,20 +22,16 @@ function RouteComponent() { // )) const runPromise = R.useRunPromise() - const [promise, setPromise] = useState | null>(null) const [, setValue] = useState("") - useEffect(() => { - makeUuid4.pipe( - Effect.provide(GetRandomValues.CryptoRandom), - Effect.tap(id => Effect.sync(() => setValue(id))), - Effect.andThen(Console.log), - Effect.delay("1 second"), + const promise = useMemo(() => makeUuid4.pipe( + Effect.provide(GetRandomValues.CryptoRandom), + Effect.tap(id => Effect.sync(() => setValue(id))), + Effect.andThen(Console.log), + Effect.delay("1 second"), - runPromise, - setPromise, - ) - }, [runPromise]) + runPromise, + ), [runPromise]) console.log(promise) -- 2.49.1 From 734c84824c8c2e95e4c91fc6d1d403269b2420a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 04:30:10 +0100 Subject: [PATCH 005/101] Implement Pipeable --- packages/reffuse/src/Reffuse.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 897c5f1..4ec7386 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,4 +1,4 @@ -import { Context, Effect, ExecutionStrategy, Exit, Fiber, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import { Context, Effect, ExecutionStrategy, Exit, Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" @@ -386,6 +386,13 @@ export class Reffuse { } +export interface Reffuse extends Pipeable.Pipeable {} + +Reffuse.prototype.pipe = function pipe() { + return Pipeable.pipeArguments(this, arguments) +} + + export interface RenderOptions { /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ readonly doNotReExecuteOnRuntimeOrContextChange?: boolean -- 2.49.1 From 933b061b5d0bbb2654643b60848516bfefa440cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 05:18:34 +0100 Subject: [PATCH 006/101] Promise tests --- packages/example/src/routes/promise.tsx | 34 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index edb3e4f..9d69d62 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -1,8 +1,9 @@ import { R } from "@/reffuse" import { HttpClient } from "@effect/platform" +import { Text } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import { Console, Effect } from "effect" -import { use, useMemo } from "react" +import { Suspense, use, useEffect, useMemo } from "react" export const Route = createFileRoute("/promise")({ @@ -10,19 +11,32 @@ export const Route = createFileRoute("/promise")({ }) function RouteComponent() { + return ( + Loading...}> + + + ) +} - const runPromise = R.useRunPromise() +function AsyncComponent() { - const promise = useMemo(() => HttpClient.HttpClient.pipe( - Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), - HttpClient.withTracerPropagation(false), - Effect.flatMap(res => res.json), - Effect.tap(Console.log), + // const runPromise = R.useRunPromise() - Effect.scoped, - runPromise, - ), [runPromise]) + // const promise = useMemo(() => HttpClient.HttpClient.pipe( + // Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), + // HttpClient.withTracerPropagation(false), + // Effect.flatMap(res => res.json), + // Effect.tap(Console.log), + // Effect.scoped, + // runPromise, + // ), [runPromise]) + + const promise = useMemo(() => new Promise((resolve => { + setTimeout(() => { resolve("prout") }, 500) + })), []) + + console.log("React.use invoked with:", promise); const value = use(promise) -- 2.49.1 From bfcc0978824c742ee56481b617564f7a1c2d1825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 15:25:46 +0100 Subject: [PATCH 007/101] usePromise --- packages/example/src/routes/promise.tsx | 46 +++++++-------- packages/reffuse/src/Reffuse.ts | 76 +++++++++++++++---------- 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index 9d69d62..da200db 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -2,44 +2,36 @@ import { R } from "@/reffuse" import { HttpClient } from "@effect/platform" import { Text } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" -import { Console, Effect } from "effect" -import { Suspense, use, useEffect, useMemo } from "react" +import { Effect, Schema } from "effect" +import { Suspense, use } from "react" export const Route = createFileRoute("/promise")({ component: RouteComponent }) + +const Result = Schema.Tuple(Schema.String) +type Result = typeof Result.Type + function RouteComponent() { + const promise = R.usePromise(HttpClient.HttpClient.pipe( + Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), + HttpClient.withTracerPropagation(false), + Effect.flatMap(res => res.json), + Effect.flatMap(Schema.decodeUnknown(Result)), + + Effect.scoped, + )) + return ( Loading...}> - + ) } -function AsyncComponent() { - - // const runPromise = R.useRunPromise() - - // const promise = useMemo(() => HttpClient.HttpClient.pipe( - // Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), - // HttpClient.withTracerPropagation(false), - // Effect.flatMap(res => res.json), - // Effect.tap(Console.log), - - // Effect.scoped, - // runPromise, - // ), [runPromise]) - - const promise = useMemo(() => new Promise((resolve => { - setTimeout(() => { resolve("prout") }, 500) - })), []) - - console.log("React.use invoked with:", promise); - const value = use(promise) - - - return
Hello "/tests"!
- +function AsyncComponent({ promise }: { readonly promise: Promise }) { + const [uuid] = use(promise) + return {uuid} } diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 4ec7386..cc1755f 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -284,43 +284,57 @@ export class Reffuse { ]) } - // useSuspense( - // effect: Effect.Effect, - // deps?: React.DependencyList, - // options?: { readonly signal?: AbortSignal } & RenderOptions, - // ): A { - // const runPromise = this.useRunPromise() + usePromise( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & RenderOptions, + ): Promise
{ + const runPromise = this.useRunPromise() - // const promise = React.useMemo(() => runPromise(effect, options), [ - // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], - // ...(deps ?? []), - // ]) - // return React.use(promise) - // } + return React.useMemo(() => runPromise(effect, options), [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], + ...(deps ?? []), + ]) + } - // useSuspenseScoped( - // effect: Effect.Effect, - // deps?: React.DependencyList, - // options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, - // ): A { - // const runSync = this.useRunSync() - // const runPromise = this.useRunPromise() + usePromiseScoped( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + ): Promise { + const runSync = this.useRunSync() + const runPromise = this.useRunPromise() - // const initialPromise = React.useMemo(() => runPromise(Effect.scoped(effect)), []) - // const [promise, setPromise] = React.useState(initialPromise) + // Calculate an initial version of the value so that it can be accessed during the first render + const initialScope = React.useMemo(() => runSync(Scope.make(options?.finalizerExecutionStrategy)), []) + const initialValue = React.useMemo(() => runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options), []) - // React.useEffect(() => { - // const scope = runSync(Scope.make()) - // setPromise(runPromise(Effect.provideService(effect, Scope.Scope, scope), options)) + // Keep track of the state of the initial scope + const initialScopeClosed = React.useRef(false) - // return () => { runPromise(Scope.close(scope, Exit.void)) } - // }, [ - // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], - // ...(deps ?? []), - // ]) + const [value, setValue] = React.useState(initialValue) - // return React.use(promise) - // } + React.useEffect(() => { + const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( + Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), + Effect.when(() => !initialScopeClosed.current), + ) + + const scope = closeInitialScopeIfNeeded.pipe( + Effect.andThen(Scope.make(options?.finalizerExecutionStrategy)), + runSync, + ) + + setValue(runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options)) + + return () => { runSync(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + ...(deps ?? []), + ]) + + return value + } useRef(value: A): SubscriptionRef.SubscriptionRef { -- 2.49.1 From e71239b90304664994c1024ae0d35c7130e16af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 22:28:49 +0100 Subject: [PATCH 008/101] usePromiseScoped --- packages/example/src/routes/promise.tsx | 4 +- packages/example/src/routes/tests.tsx | 22 ++------- packages/reffuse/src/Reffuse.ts | 61 +++++++------------------ packages/reffuse/src/ReffuseContext.tsx | 1 + 4 files changed, 21 insertions(+), 67 deletions(-) diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index da200db..d5c9b57 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -15,13 +15,11 @@ const Result = Schema.Tuple(Schema.String) type Result = typeof Result.Type function RouteComponent() { - const promise = R.usePromise(HttpClient.HttpClient.pipe( + const promise = R.usePromiseScoped(HttpClient.HttpClient.pipe( Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), - - Effect.scoped, )) return ( diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index 6961e11..82b6919 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -1,8 +1,6 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { GetRandomValues, makeUuid4 } from "@typed/id" import { Console, Effect } from "effect" -import { useMemo, useState } from "react" export const Route = createFileRoute("/tests")({ @@ -16,24 +14,10 @@ function RouteComponent() { // ), []) // console.log(value) - // R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( - // Effect.andThen(Console.log("ouient")), - // Effect.delay("1 second"), - // )) - - const runPromise = R.useRunPromise() - const [, setValue] = useState("") - - const promise = useMemo(() => makeUuid4.pipe( - Effect.provide(GetRandomValues.CryptoRandom), - Effect.tap(id => Effect.sync(() => setValue(id))), - Effect.andThen(Console.log), + R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + Effect.andThen(Console.log("ouient")), Effect.delay("1 second"), - - runPromise, - ), [runPromise]) - - console.log(promise) + )) return
Hello "/tests"!
diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index cc1755f..f3d56ec 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -5,6 +5,7 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as SetStateAction from "./SetStateAction.js" +// MAYBE: make it an Effect and match the R parameter? export class Reffuse { constructor( @@ -305,29 +306,25 @@ export class Reffuse { const runSync = this.useRunSync() const runPromise = this.useRunPromise() - // Calculate an initial version of the value so that it can be accessed during the first render - const initialScope = React.useMemo(() => runSync(Scope.make(options?.finalizerExecutionStrategy)), []) - const initialValue = React.useMemo(() => runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options), []) - - // Keep track of the state of the initial scope - const initialScopeClosed = React.useRef(false) - - const [value, setValue] = React.useState(initialValue) + const [value, setValue] = React.useState(new Promise
(() => {})) React.useEffect(() => { - const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( - Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), - Effect.when(() => !initialScopeClosed.current), - ) + const controller = new AbortController() + const signal = AbortSignal.any([ + controller.signal, + ...options?.signal ? [options.signal] : [], + ]) - const scope = closeInitialScopeIfNeeded.pipe( - Effect.andThen(Scope.make(options?.finalizerExecutionStrategy)), - runSync, - ) + const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) + setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { + ...options, + signal, + })) - setValue(runPromise(Effect.provideService(effect, Scope.Scope, initialScope), options)) - - return () => { runSync(Scope.close(scope, Exit.void)) } + return () => { + controller.abort() + runSync(Scope.close(scope, Exit.void)) + } }, [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], ...(deps ?? []), @@ -371,32 +368,6 @@ export class Reffuse { return [reactStateValue, setValue] } - /** - * Binds the state of a `LazyRef` from the `@typed/lazy-ref` package to the state of the React component. - * - * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes. - * - * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. - */ - // useLazyRefState(ref: LazyRef.LazyRef): [A, React.Dispatch>] { - // const runSync = this.useRunSync() - - // const initialState = React.useMemo(() => runSync(ref), []) - // const [reactStateValue, setReactStateValue] = React.useState(initialState) - - // this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => - // setReactStateValue(v) - // )), [ref]) - - // const setValue = React.useCallback((setStateAction: React.SetStateAction) => - // runSync(LazyRef.update(ref, prevState => - // SetStateAction.value(setStateAction, prevState) - // )), - // [ref]) - - // return [reactStateValue, setValue] - // } - } diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index dbca682..a7b49a5 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -3,6 +3,7 @@ import React from "react" import * as ReffuseRuntime from "./ReffuseRuntime.js" +// TODO: merge this with the Provider, just like React 19 contexts export class ReffuseContext { readonly Context = React.createContext>(null!) -- 2.49.1 From 809f512d115cff83b1b73eb0d87f10e1cef3ddde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 22:33:49 +0100 Subject: [PATCH 009/101] Fix --- packages/reffuse/src/Reffuse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index f3d56ec..79dc033 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -338,7 +338,7 @@ export class Reffuse { return this.useMemo( SubscriptionRef.make(value), [], - { doNotReExecuteOnRuntimeOrContextChange: false }, // Do not recreate the ref when the context changes + { doNotReExecuteOnRuntimeOrContextChange: true }, // Do not recreate the ref when the context changes ) } -- 2.49.1 From 6c843562ab98f0ee174558a1131cec4e08f8209c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 18 Feb 2025 23:47:32 +0100 Subject: [PATCH 010/101] usePromiseScoped fork implementation --- packages/reffuse/src/Reffuse.ts | 72 ++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 79dc033..6eb0753 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -301,38 +301,80 @@ export class Reffuse { usePromiseScoped( effect: Effect.Effect, deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, ): Promise { const runSync = this.useRunSync() - const runPromise = this.useRunPromise() + const runFork = this.useRunFork() - const [value, setValue] = React.useState(new Promise(() => {})) + const [value, setValue] = React.useState(Promise.withResolvers().promise) React.useEffect(() => { - const controller = new AbortController() - const signal = AbortSignal.any([ - controller.signal, - ...options?.signal ? [options.signal] : [], - ]) + const { promise, resolve, reject } = Promise.withResolvers() + setValue(promise) const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) - setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { - ...options, - signal, - })) + + const fiber = effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.match({ + onSuccess: resolve, + onFailure: reject, + }), + + // TODO: use scope from RunForkOptions? + effect => runFork(effect, options), + ) return () => { - controller.abort() - runSync(Scope.close(scope, Exit.void)) + Fiber.interrupt(fiber).pipe( + Effect.andThen(Scope.close(scope, Exit.void)), + Effect.andThen(Effect.sync(() => { reject() })), // TODO: Relevant? + runFork, + ) } }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], ...(deps ?? []), ]) return value } + // usePromiseScoped( + // effect: Effect.Effect, + // deps?: React.DependencyList, + // options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + // ): Promise { + // const runSync = this.useRunSync() + // const runPromise = this.useRunPromise() + + // const [value, setValue] = React.useState(new Promise(() => {})) + + // React.useEffect(() => { + // const controller = new AbortController() + // const signal = AbortSignal.any([ + // controller.signal, + // ...options?.signal ? [options.signal] : [], + // ]) + + // const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) + // setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { + // ...options, + // signal, + // })) + + // return () => { + // controller.abort() + // runSync(Scope.close(scope, Exit.void)) + // } + // }, [ + // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + // ...(deps ?? []), + // ]) + + // return value + // } + useRef(value: A): SubscriptionRef.SubscriptionRef { return this.useMemo( -- 2.49.1 From 9e7b30fbb4ded295824d3046e2d16f78bd2b2cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 19 Feb 2025 23:24:15 +0100 Subject: [PATCH 011/101] useFork refactoring --- packages/example/src/routes/promise.tsx | 5 +++-- packages/example/src/routes/time.tsx | 8 +++++-- packages/reffuse/src/Reffuse.ts | 28 ++++++++++++------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index d5c9b57..9577aca 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -2,7 +2,7 @@ import { R } from "@/reffuse" import { HttpClient } from "@effect/platform" import { Text } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" -import { Effect, Schema } from "effect" +import { Console, Effect, Schema } from "effect" import { Suspense, use } from "react" @@ -15,7 +15,8 @@ const Result = Schema.Tuple(Schema.String) type Result = typeof Result.Type function RouteComponent() { - const promise = R.usePromiseScoped(HttpClient.HttpClient.pipe( + const promise = R.usePromiseScoped(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + Effect.andThen(HttpClient.HttpClient), Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), diff --git a/packages/example/src/routes/time.tsx b/packages/example/src/routes/time.tsx index 3a60060..7332f6b 100644 --- a/packages/example/src/routes/time.tsx +++ b/packages/example/src/routes/time.tsx @@ -1,6 +1,6 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { DateTime, Effect, Ref, Schedule, Stream, SubscriptionRef } from "effect" +import { Console, DateTime, Effect, Ref, Schedule, Stream, SubscriptionRef } from "effect" const timeEverySecond = Stream.repeatEffectWithSchedule( @@ -16,7 +16,11 @@ export const Route = createFileRoute("/time")({ function Time() { const timeRef = R.useMemo(DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make))) - R.useFork(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v)), [timeRef]) + + R.useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + Effect.andThen(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v))) + ), [timeRef]) + const [time] = R.useRefState(timeRef) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 6eb0753..08700cb 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -270,15 +270,13 @@ export class Reffuse { const runFork = this.useRunFork() return React.useEffect(() => { - const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) - const fiber = runFork(Effect.provideService(effect, Scope.Scope, scope), options) + const scope = runSync(options?.scope + ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) + : Scope.make(options?.finalizerExecutionStrategy) + ) + runFork(Effect.provideService(effect, Scope.Scope, scope), { ...options, scope }) - return () => { - Fiber.interrupt(fiber).pipe( - Effect.andThen(Scope.close(scope, Exit.void)), - runFork, - ) - } + return () => { runFork(Scope.close(scope, Exit.void)) } }, [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], ...(deps ?? []), @@ -322,15 +320,17 @@ export class Reffuse { }), // TODO: use scope from RunForkOptions? - effect => runFork(effect, options), + effect => runFork(effect, { ...options, scope }), ) return () => { - Fiber.interrupt(fiber).pipe( - Effect.andThen(Scope.close(scope, Exit.void)), - Effect.andThen(Effect.sync(() => { reject() })), // TODO: Relevant? - runFork, - ) + // Fiber.interrupt(fiber).pipe( + // Effect.andThen(Scope.close(scope, Exit.void)), + // // \/ TODO: should interrupted promises reject? + // // Effect.andThen(Effect.sync(() => { reject() })), + // runFork, + // ) + runFork(Scope.close(scope, Exit.void)) } }, [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], -- 2.49.1 From 65810a6d7947739d94b94c28adbc60141807652a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 19 Feb 2025 23:44:02 +0100 Subject: [PATCH 012/101] usePromise --- packages/example/src/routes/promise.tsx | 5 +- packages/reffuse/src/Reffuse.ts | 72 +++++-------------------- 2 files changed, 15 insertions(+), 62 deletions(-) diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index 9577aca..58c1452 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -15,9 +15,8 @@ const Result = Schema.Tuple(Schema.String) type Result = typeof Result.Type function RouteComponent() { - const promise = R.usePromiseScoped(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( - Effect.andThen(HttpClient.HttpClient), - Effect.flatMap(client => client.get("https://www.uuidtools.com/api/generate/v4")), + const promise = R.usePromise(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 08700cb..50ee1a3 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -284,19 +284,6 @@ export class Reffuse { } usePromise( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & RenderOptions, - ): Promise { - const runPromise = this.useRunPromise() - - return React.useMemo(() => runPromise(effect, options), [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], - ...(deps ?? []), - ]) - } - - usePromiseScoped( effect: Effect.Effect, deps?: React.DependencyList, options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, @@ -310,27 +297,29 @@ export class Reffuse { const { promise, resolve, reject } = Promise.withResolvers() setValue(promise) - const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) + const scope = runSync(options?.scope + ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) + : Scope.make(options?.finalizerExecutionStrategy) + ) - const fiber = effect.pipe( + const cleanup = () => { runFork(Scope.close(scope, Exit.void)) } + if (options?.signal) + options.signal.addEventListener("abort", cleanup) + + effect.pipe( Effect.provideService(Scope.Scope, scope), Effect.match({ onSuccess: resolve, onFailure: reject, }), - - // TODO: use scope from RunForkOptions? effect => runFork(effect, { ...options, scope }), ) return () => { - // Fiber.interrupt(fiber).pipe( - // Effect.andThen(Scope.close(scope, Exit.void)), - // // \/ TODO: should interrupted promises reject? - // // Effect.andThen(Effect.sync(() => { reject() })), - // runFork, - // ) - runFork(Scope.close(scope, Exit.void)) + if (options?.signal) + options.signal.removeEventListener("abort", cleanup) + + cleanup() } }, [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], @@ -340,41 +329,6 @@ export class Reffuse { return value } - // usePromiseScoped( - // effect: Effect.Effect, - // deps?: React.DependencyList, - // options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, - // ): Promise { - // const runSync = this.useRunSync() - // const runPromise = this.useRunPromise() - - // const [value, setValue] = React.useState(new Promise(() => {})) - - // React.useEffect(() => { - // const controller = new AbortController() - // const signal = AbortSignal.any([ - // controller.signal, - // ...options?.signal ? [options.signal] : [], - // ]) - - // const scope = runSync(Scope.make(options?.finalizerExecutionStrategy)) - // setValue(runPromise(Effect.provideService(effect, Scope.Scope, scope), { - // ...options, - // signal, - // })) - - // return () => { - // controller.abort() - // runSync(Scope.close(scope, Exit.void)) - // } - // }, [ - // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], - // ...(deps ?? []), - // ]) - - // return value - // } - useRef(value: A): SubscriptionRef.SubscriptionRef { return this.useMemo( -- 2.49.1 From 36d5414d10dcdf4fb5caac7ad495524964817a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 19 Feb 2025 23:59:34 +0100 Subject: [PATCH 013/101] Fix --- packages/reffuse/src/Reffuse.ts | 2 +- packages/reffuse/src/ReffuseContext.tsx | 2 +- packages/reffuse/src/ReffuseRuntime.tsx | 2 +- packages/reffuse/src/SetStateAction.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 50ee1a3..39f781c 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,5 +1,5 @@ import { Context, Effect, ExecutionStrategy, Exit, Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" -import React from "react" +import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as SetStateAction from "./SetStateAction.js" diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index a7b49a5..c914a61 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -1,5 +1,5 @@ import { Array, Context, Effect, Layer, Runtime } from "effect" -import React from "react" +import * as React from "react" import * as ReffuseRuntime from "./ReffuseRuntime.js" diff --git a/packages/reffuse/src/ReffuseRuntime.tsx b/packages/reffuse/src/ReffuseRuntime.tsx index d693f6b..3a6c75e 100644 --- a/packages/reffuse/src/ReffuseRuntime.tsx +++ b/packages/reffuse/src/ReffuseRuntime.tsx @@ -1,5 +1,5 @@ import { Runtime } from "effect" -import React from "react" +import * as React from "react" export const Context = React.createContext>(null!) diff --git a/packages/reffuse/src/SetStateAction.ts b/packages/reffuse/src/SetStateAction.ts index f456407..10a596b 100644 --- a/packages/reffuse/src/SetStateAction.ts +++ b/packages/reffuse/src/SetStateAction.ts @@ -1,5 +1,5 @@ import { Function } from "effect" -import type React from "react" +import type * as React from "react" export const value: { -- 2.49.1 From fffbd01b5e99f588b5d94a217931f36ce0f73ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 20 Feb 2025 00:21:43 +0100 Subject: [PATCH 014/101] Pipeable API tests --- packages/reffuse/src/Reffuse.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 39f781c..1a45971 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -384,7 +384,17 @@ export interface ScopeOptions { } -export const make = >( - ...contexts: [...{ [K in keyof T]: ReffuseContext.ReffuseContext }] -): Reffuse => - new Reffuse(contexts) +// export const make = >( +// ...contexts: [...{ [K in keyof T]: ReffuseContext.ReffuseContext }] +// ): Reffuse => +// new Reffuse(contexts) + +export const make = (): Reffuse => new Reffuse([]) + +export const withContexts = >( + ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] +) => + , R1>(self: T & Reffuse): ( + Reffuse & Exclude> + ) => + new Reffuse([...self.contexts, ...contexts as any]) as any -- 2.49.1 From b636a709f3ead60083fe3d84efc1312a5f031371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 20 Feb 2025 00:39:15 +0100 Subject: [PATCH 015/101] Tests --- packages/reffuse/src/Reffuse.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 1a45971..89ebeb3 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -384,17 +384,17 @@ export interface ScopeOptions { } -// export const make = >( -// ...contexts: [...{ [K in keyof T]: ReffuseContext.ReffuseContext }] -// ): Reffuse => -// new Reffuse(contexts) +export const make = >( + ...contexts: [...{ [K in keyof T]: ReffuseContext.ReffuseContext }] +): Reffuse => + new Reffuse(contexts) -export const make = (): Reffuse => new Reffuse([]) +// export const make = (): Reffuse => new Reffuse([]) -export const withContexts = >( - ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] -) => - , R1>(self: T & Reffuse): ( - Reffuse & Exclude> - ) => - new Reffuse([...self.contexts, ...contexts as any]) as any +// export const withContexts = >( +// ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] +// ) => +// , R1>(self: T & Reffuse): ( +// Reffuse & Exclude> +// ) => +// new Reffuse([...self.contexts, ...contexts as any]) as any -- 2.49.1 From a71640d493e6fb06901d1a973a1ee55ffab29a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 20 Feb 2025 00:41:37 +0100 Subject: [PATCH 016/101] Cleanup --- packages/reffuse/src/Reffuse.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 89ebeb3..5f899f5 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -5,7 +5,6 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as SetStateAction from "./SetStateAction.js" -// MAYBE: make it an Effect and match the R parameter? export class Reffuse { constructor( -- 2.49.1 From febeaa05d0d2d15f60e57424a243bc5af31770fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 20 Feb 2025 14:12:56 +0100 Subject: [PATCH 017/101] ReffuseExtension --- packages/reffuse/src/ReffuseExtension.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/reffuse/src/ReffuseExtension.ts diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts new file mode 100644 index 0000000..4dbe515 --- /dev/null +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -0,0 +1 @@ +export const make = () => undefined -- 2.49.1 From c0097bbe8128a49aec21da6fd4703a18e7034362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 20 Feb 2025 14:57:46 +0100 Subject: [PATCH 018/101] Extension tests --- packages/reffuse/src/ReffuseExtension.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 4dbe515..84f6396 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1 +1,19 @@ -export const make = () => undefined +import type { Effect } from "effect" +import * as ReffuseContext from "./ReffuseContext.js" + + +interface ReffuseTest { + readonly contexts: readonly ReffuseContext.ReffuseContext[] + + useEffect(effect: Effect.Effect): void +} + +const ReffuseTestProto = { + useEffect(this: ReffuseTest, effect: Effect.Effect) {} +} + +const make = (): ReffuseTest => { + const self = Object.create(ReffuseTestProto) + self.contexts = [] + return self +} -- 2.49.1 From 256638bc06ff15709f5ff1b70409e62efac7130e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 21 Feb 2025 04:22:48 +0100 Subject: [PATCH 019/101] ReffuseHelper --- packages/reffuse/src/ReffuseExtension.ts | 21 +++------ packages/reffuse/src/ReffuseHelper.ts | 57 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 packages/reffuse/src/ReffuseHelper.ts diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 84f6396..6d0648c 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,19 +1,10 @@ import type { Effect } from "effect" import * as ReffuseContext from "./ReffuseContext.js" +import * as Reffuse from "./Reffuse.js" +import type { Simplify } from "effect/Types" -interface ReffuseTest { - readonly contexts: readonly ReffuseContext.ReffuseContext[] - - useEffect(effect: Effect.Effect): void -} - -const ReffuseTestProto = { - useEffect(this: ReffuseTest, effect: Effect.Effect) {} -} - -const make = (): ReffuseTest => { - const self = Object.create(ReffuseTestProto) - self.contexts = [] - return self -} +const make = (extension: T) => + (base: R) => { + const class_ = class extends base {} + } diff --git a/packages/reffuse/src/ReffuseHelper.ts b/packages/reffuse/src/ReffuseHelper.ts new file mode 100644 index 0000000..d41f572 --- /dev/null +++ b/packages/reffuse/src/ReffuseHelper.ts @@ -0,0 +1,57 @@ +import type { Context, Effect, ExecutionStrategy, Fiber, Pipeable, Runtime, Scope, SubscriptionRef } from "effect" +import type * as React from "react" + + +export interface ReffuseHelper extends Pipeable.Pipeable { + useContext(): Context.Context + + useRunSync(): (effect: Effect.Effect) => A + useRunPromise(): (effect: Effect.Effect, options?: { + readonly signal?: AbortSignal + }) => Promise + useRunFork(): (effect: Effect.Effect, options?: Runtime.RunForkOptions) => Fiber.RuntimeFiber + useRunCallback(): (effect: Effect.Effect, options?: Runtime.RunCallbackOptions) => Runtime.Cancel + + useMemo( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions, + ): A + + useMemoScoped( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): A + + useLayoutEffect( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): void + + useFork( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): void + + usePromise( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): Promise + + useRef(value: A): SubscriptionRef.SubscriptionRef + useRefState(ref: SubscriptionRef.SubscriptionRef): readonly [A, React.Dispatch>] +} + + +export interface RenderOptions { + /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ + readonly doNotReExecuteOnRuntimeOrContextChange?: boolean +} + +export interface ScopeOptions { + readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy +} -- 2.49.1 From 8252b6cbdf8ec37807e46f2cefc07c69f84cd7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 21 Feb 2025 05:22:19 +0100 Subject: [PATCH 020/101] Extension work --- packages/reffuse/src/ReffuseExtension.ts | 28 +++++++++++++++++++----- packages/reffuse/src/types.ts | 21 ++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 packages/reffuse/src/types.ts diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 6d0648c..28987cb 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,10 +1,28 @@ -import type { Effect } from "effect" -import * as ReffuseContext from "./ReffuseContext.js" import * as Reffuse from "./Reffuse.js" -import type { Simplify } from "effect/Types" +import type { Merge, StaticType } from "./types.js" -const make = (extension: T) => - (base: R) => { +const make = (extension: Ext) => + < + BaseClass extends typeof Reffuse.Reffuse, + R, + >( + base: BaseClass & typeof Reffuse.Reffuse + ): ( + { new(): Merge, Ext> } & + StaticType + ) => { const class_ = class extends base {} + return class_ } + + +const cls = make({ + prout(this: Reffuse.Reffuse) {} +})(Reffuse.Reffuse) + +class Cls extends cls {} + +const cls2 = make({ + aya() {} +})(cls) diff --git a/packages/reffuse/src/types.ts b/packages/reffuse/src/types.ts new file mode 100644 index 0000000..51f4129 --- /dev/null +++ b/packages/reffuse/src/types.ts @@ -0,0 +1,21 @@ +/** + * Extracts the common keys between two types + */ +export type CommonKeys = Extract + +/** + * Obtain the static members type of a constructor function type + */ +export type StaticType any> = Omit + +export type Extend = + Extendable extends true + ? Omit> & Self + : never + +export type Extendable = + Pick> extends Pick> + ? true + : false + +export type Merge = Omit> & Self -- 2.49.1 From 837dcbb1cb5a4aaf51d45c7edcb7ca8e8d8a3126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 21 Feb 2025 15:27:11 +0100 Subject: [PATCH 021/101] Extension work --- packages/reffuse/src/ReffuseExtension.ts | 56 ++- packages/reffuse/src/ReffuseHelpers.ts | 426 +++++++++++++++++++++++ 2 files changed, 475 insertions(+), 7 deletions(-) create mode 100644 packages/reffuse/src/ReffuseHelpers.ts diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 28987cb..8038e61 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,13 +1,24 @@ -import * as Reffuse from "./Reffuse.js" +import { Effect } from "effect" +import * as ReffuseContext from "./ReffuseContext.js" +import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" +class Reffuse extends ReffuseHelpers.ReffuseHelpers {} + +class MyService extends Effect.Service()("MyService", { + succeed: {} +}) {} + +const MyContext = ReffuseContext.make() + + const make = (extension: Ext) => < - BaseClass extends typeof Reffuse.Reffuse, + BaseClass extends typeof Reffuse, R, >( - base: BaseClass & typeof Reffuse.Reffuse + base: BaseClass & typeof Reffuse ): ( { new(): Merge, Ext> } & StaticType @@ -16,12 +27,43 @@ const make = (extension: Ext) => return class_ } +export const withContexts = >( + ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] +) => + < + BaseClass extends typeof ReffuseHelpers.ReffuseHelpers, + R1 + >( + self: BaseClass & typeof ReffuseHelpers.ReffuseHelpers + ): ( + { + new(): Merge< + InstanceType, + { readonly contexts: readonly ReffuseContext.ReffuseContext[] } + > + } & + StaticType + ) => { + const instance = new self() -const cls = make({ - prout(this: Reffuse.Reffuse) {} -})(Reffuse.Reffuse) + return class extends self { + readonly contexts = [...instance.contexts, ...contexts] as const + } as any + } -class Cls extends cls {} + +const withMyContext = withContexts(MyContext) +const clsWithMyContext = withMyContext(Reffuse) +class ReffuseWithMyContext extends clsWithMyContext {} + +const t = new ReffuseWithMyContext() + + +const cls1 = make({ + prout(this: ReffuseHelpers.ReffuseHelpers) {} +})(Reffuse) + +class Cls1 extends cls1 {} const cls2 = make({ aya() {} diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts new file mode 100644 index 0000000..d1016bf --- /dev/null +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -0,0 +1,426 @@ +import { Context, Effect, ExecutionStrategy, Exit, Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import * as React from "react" +import * as ReffuseContext from "./ReffuseContext.js" +import * as ReffuseRuntime from "./ReffuseRuntime.js" +import * as SetStateAction from "./SetStateAction.js" + + +export interface ReffuseHelper extends Pipeable.Pipeable { + useContext(): Context.Context + + useRunSync(): (effect: Effect.Effect) => A + useRunPromise(): (effect: Effect.Effect, options?: { + readonly signal?: AbortSignal + }) => Promise + useRunFork(): (effect: Effect.Effect, options?: Runtime.RunForkOptions) => Fiber.RuntimeFiber + useRunCallback(): (effect: Effect.Effect, options?: Runtime.RunCallbackOptions) => Runtime.Cancel + + useMemo( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions, + ): A + + useMemoScoped( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): A + + useLayoutEffect( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): void + + useFork( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): void + + usePromise( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): Promise + + useRef(value: A): SubscriptionRef.SubscriptionRef + useRefState(ref: SubscriptionRef.SubscriptionRef): readonly [A, React.Dispatch>] +} + + +export class ReffuseHelpers { + + readonly contexts: readonly ReffuseContext.ReffuseContext[] = [] + + + useContext(): Context.Context { + return ReffuseContext.useMergeAll(...this.contexts) + } + + + useRunSync() { + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() + + return React.useCallback(( + effect: Effect.Effect + ): A => effect.pipe( + Effect.provide(context), + Runtime.runSync(runtime), + ), [runtime, context]) + } + + useRunPromise() { + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() + + return React.useCallback(( + effect: Effect.Effect, + options?: { readonly signal?: AbortSignal }, + ): Promise => effect.pipe( + Effect.provide(context), + effect => Runtime.runPromise(runtime)(effect, options), + ), [runtime, context]) + } + + useRunFork() { + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() + + return React.useCallback(( + effect: Effect.Effect, + options?: Runtime.RunForkOptions, + ): Fiber.RuntimeFiber => effect.pipe( + Effect.provide(context), + effect => Runtime.runFork(runtime)(effect, options), + ), [runtime, context]) + } + + useRunCallback() { + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() + + return React.useCallback(( + effect: Effect.Effect, + options?: Runtime.RunCallbackOptions, + ): Runtime.Cancel => effect.pipe( + Effect.provide(context), + effect => Runtime.runCallback(runtime)(effect, options), + ), [runtime, context]) + } + + + /** + * Reffuse equivalent to `React.useMemo`. + * + * `useMemo` will only recompute the memoized value by running the given synchronous effect when one of the deps has changed. \ + * Trying to run an asynchronous effect will throw. + * + * Changes to the Reffuse runtime or context will recompute the value in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + */ + useMemo( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions, + ): A { + const runSync = this.useRunSync() + + return React.useMemo(() => runSync(effect), [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + } + + useMemoScoped( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): A { + const runSync = this.useRunSync() + + // Calculate an initial version of the value so that it can be accessed during the first render + const [initialScope, initialValue] = React.useMemo(() => Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.flatMap(scope => effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.map(value => [scope, value] as const), + )), + + runSync, + ), []) + + // Keep track of the state of the initial scope + const initialScopeClosed = React.useRef(false) + + const [value, setValue] = React.useState(initialValue) + + React.useEffect(() => { + const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( + Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), + Effect.when(() => !initialScopeClosed.current), + ) + + const [scope, value] = closeInitialScopeIfNeeded.pipe( + Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.flatMap(scope => effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.map(value => [scope, value] as const), + )) + )), + + runSync, + ) + + setValue(value) + return () => { runSync(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + + return value + } + + /** + * Reffuse equivalent to `React.useEffect`. + * + * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Trying to run an asynchronous effect will throw. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * useEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * Effect.flatMap(() => Console.log("Component mounted")) + * )) + * ``` + * + * Plain React equivalent: + * ``` + * React.useEffect(() => { + * console.log("Component mounted") + * return () => { console.log("Component unmounted") } + * }) + * ``` + */ + useEffect( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): void { + const runSync = this.useRunSync() + + return React.useEffect(() => { + const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), + runSync, + ) + + return () => { runSync(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + } + + /** + * Reffuse equivalent to `React.useLayoutEffect`. + * + * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Fires synchronously after all DOM mutations. \ + * Trying to run an asynchronous effect will throw. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * useLayoutEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * Effect.flatMap(() => Console.log("Component mounted")) + * )) + * ``` + * + * Plain React equivalent: + * ``` + * React.useLayoutEffect(() => { + * console.log("Component mounted") + * return () => { console.log("Component unmounted") } + * }) + * ``` + */ + useLayoutEffect( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): void { + const runSync = this.useRunSync() + + return React.useLayoutEffect(() => { + const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), + runSync, + ) + + return () => { runSync(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + } + + /** + * An asynchronous and non-blocking alternative to `React.useEffect`. + * + * Forks an effect wrapped into a Scope in the background when one of the deps has changed. + * + * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ + * Add finalizers to the Scope to handle cleanup logic. + * + * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. + * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. + * + * ### Example + * ``` + * const timeRef = useRefFromEffect(DateTime.now) + * + * useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + * Effect.map(() => Stream.repeatEffectWithSchedule( + * DateTime.now, + * Schedule.intersect(Schedule.forever, Schedule.spaced("1 second")), + * )), + * + * Effect.flatMap(Stream.runForEach(time => Ref.set(timeRef, time)), + * )), [timeRef]) + * + * const [time] = useRefState(timeRef) + * ``` + */ + useFork( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): void { + const runSync = this.useRunSync() + const runFork = this.useRunFork() + + return React.useEffect(() => { + const scope = runSync(options?.scope + ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) + : Scope.make(options?.finalizerExecutionStrategy) + ) + runFork(Effect.provideService(effect, Scope.Scope, scope), { ...options, scope }) + + return () => { runFork(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], + ...(deps ?? []), + ]) + } + + usePromise( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, + ): Promise { + const runSync = this.useRunSync() + const runFork = this.useRunFork() + + const [value, setValue] = React.useState(Promise.withResolvers().promise) + + React.useEffect(() => { + const { promise, resolve, reject } = Promise.withResolvers() + setValue(promise) + + const scope = runSync(options?.scope + ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) + : Scope.make(options?.finalizerExecutionStrategy) + ) + + const cleanup = () => { runFork(Scope.close(scope, Exit.void)) } + if (options?.signal) + options.signal.addEventListener("abort", cleanup) + + effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.match({ + onSuccess: resolve, + onFailure: reject, + }), + effect => runFork(effect, { ...options, scope }), + ) + + return () => { + if (options?.signal) + options.signal.removeEventListener("abort", cleanup) + + cleanup() + } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], + ...(deps ?? []), + ]) + + return value + } + + + useRef(value: A): SubscriptionRef.SubscriptionRef { + return this.useMemo( + SubscriptionRef.make(value), + [], + { doNotReExecuteOnRuntimeOrContextChange: true }, // Do not recreate the ref when the context changes + ) + } + + /** + * Binds the state of a `SubscriptionRef` to the state of the React component. + * + * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes. + * + * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. + */ + useRefState(ref: SubscriptionRef.SubscriptionRef): [A, React.Dispatch>] { + const runSync = this.useRunSync() + + const initialState = React.useMemo(() => runSync(ref), []) + const [reactStateValue, setReactStateValue] = React.useState(initialState) + + this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + setReactStateValue(v) + )), [ref]) + + const setValue = React.useCallback((setStateAction: React.SetStateAction) => + runSync(Ref.update(ref, prevState => + SetStateAction.value(setStateAction, prevState) + )), + [ref]) + + return [reactStateValue, setValue] + } + +} + + +export interface ReffuseHelpers extends Pipeable.Pipeable {} + +ReffuseHelpers.prototype.pipe = function pipe() { + return Pipeable.pipeArguments(this, arguments) +} + + +export interface RenderOptions { + /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ + readonly doNotReExecuteOnRuntimeOrContextChange?: boolean +} + +export interface ScopeOptions { + readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy +} -- 2.49.1 From e1349e5e0390668c5a975d188facb3c9811ba8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 21 Feb 2025 15:44:28 +0100 Subject: [PATCH 022/101] Tests --- packages/reffuse/src/ReffuseExtension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 8038e61..948d2c4 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -4,7 +4,7 @@ import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" -class Reffuse extends ReffuseHelpers.ReffuseHelpers {} +class Reffuse extends ReffuseHelpers.ReffuseHelpers {} class MyService extends Effect.Service()("MyService", { succeed: {} @@ -39,7 +39,7 @@ export const withContexts = >( { new(): Merge< InstanceType, - { readonly contexts: readonly ReffuseContext.ReffuseContext[] } + ReffuseHelpers.ReffuseHelpers > } & StaticType -- 2.49.1 From be79d24d6e81aa0ed1874c1a322d36a3fae40e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sat, 22 Feb 2025 01:03:15 +0100 Subject: [PATCH 023/101] Tests --- packages/reffuse/src/ReffuseExtension.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 948d2c4..57ae5af 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -43,13 +43,11 @@ export const withContexts = >( > } & StaticType - ) => { - const instance = new self() - - return class extends self { + ) => new self().pipe( + instance => class extends self { readonly contexts = [...instance.contexts, ...contexts] as const } as any - } + ) const withMyContext = withContexts(MyContext) -- 2.49.1 From e8742e5aa60f1e20255e7a219340141f7d5bbeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 23 Feb 2025 23:38:24 +0100 Subject: [PATCH 024/101] Fix --- packages/reffuse/src/ReffuseExtension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 57ae5af..f39a433 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -34,7 +34,7 @@ export const withContexts = >( BaseClass extends typeof ReffuseHelpers.ReffuseHelpers, R1 >( - self: BaseClass & typeof ReffuseHelpers.ReffuseHelpers + self: BaseClass & { new(): ReffuseHelpers.ReffuseHelpers } ): ( { new(): Merge< -- 2.49.1 From 1f57f7d12779c31bdabe54237f6dd7ee0ededa08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 01:55:47 +0100 Subject: [PATCH 025/101] Tests --- packages/reffuse/src/ReffuseExtension.ts | 6 ++- packages/reffuse/src/ReffuseHelpers.ts | 56 ++++-------------------- 2 files changed, 13 insertions(+), 49 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index f39a433..f3dcc5e 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -39,13 +39,15 @@ export const withContexts = >( { new(): Merge< InstanceType, - ReffuseHelpers.ReffuseHelpers + ReffuseHelpers.ReffuseHelpers & { + prototype: ReffuseHelpers.ReffuseHelpers + } > } & StaticType ) => new self().pipe( instance => class extends self { - readonly contexts = [...instance.contexts, ...contexts] as const + readonly contexts = [...instance.contexts, ...contexts] as any } as any ) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index d1016bf..0ac8c55 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -5,58 +5,13 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as SetStateAction from "./SetStateAction.js" -export interface ReffuseHelper extends Pipeable.Pipeable { - useContext(): Context.Context - - useRunSync(): (effect: Effect.Effect) => A - useRunPromise(): (effect: Effect.Effect, options?: { - readonly signal?: AbortSignal - }) => Promise - useRunFork(): (effect: Effect.Effect, options?: Runtime.RunForkOptions) => Fiber.RuntimeFiber - useRunCallback(): (effect: Effect.Effect, options?: Runtime.RunCallbackOptions) => Runtime.Cancel - - useMemo( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions, - ): A - - useMemoScoped( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): A - - useLayoutEffect( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): void - - useFork( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): void - - usePromise( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): Promise - - useRef(value: A): SubscriptionRef.SubscriptionRef - useRefState(ref: SubscriptionRef.SubscriptionRef): readonly [A, React.Dispatch>] -} - - export class ReffuseHelpers { - readonly contexts: readonly ReffuseContext.ReffuseContext[] = [] + declare ["constructor"]: ReffuseHelpersClass useContext(): Context.Context { - return ReffuseContext.useMergeAll(...this.contexts) + return ReffuseContext.useMergeAll(...this.constructor.contexts) } @@ -416,6 +371,13 @@ ReffuseHelpers.prototype.pipe = function pipe() { } +export interface ReffuseHelpersClass extends Pipeable.Pipeable { + new(): ReffuseHelpers + prototype: ReffuseHelpers + readonly contexts: readonly ReffuseContext.ReffuseContext[] +} + + export interface RenderOptions { /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ readonly doNotReExecuteOnRuntimeOrContextChange?: boolean -- 2.49.1 From fb5bb7fcef01990ff12ea7da797505b0e84eaf91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 02:21:37 +0100 Subject: [PATCH 026/101] Cleanup --- packages/reffuse/src/ReffuseExtension.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index f3dcc5e..46e381b 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -39,9 +39,7 @@ export const withContexts = >( { new(): Merge< InstanceType, - ReffuseHelpers.ReffuseHelpers & { - prototype: ReffuseHelpers.ReffuseHelpers - } + ReffuseHelpers.ReffuseHelpers > } & StaticType -- 2.49.1 From e063eb06f745588247660defc6891670bfb4822f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 13:17:10 +0100 Subject: [PATCH 027/101] Extension work --- packages/reffuse/src/ReffuseExtension.ts | 32 +++++++++++------------- packages/reffuse/src/ReffuseHelpers.ts | 27 +++++++++++++------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 46e381b..2160bf9 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -4,7 +4,7 @@ import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" -class Reffuse extends ReffuseHelpers.ReffuseHelpers {} +class Reffuse extends ReffuseHelpers.make([]) {} class MyService extends Effect.Service()("MyService", { succeed: {} @@ -15,15 +15,15 @@ const MyContext = ReffuseContext.make() const make = (extension: Ext) => < - BaseClass extends typeof Reffuse, - R, + BaseClass extends ReffuseHelpers.ReffuseHelpersClass, + R >( - base: BaseClass & typeof Reffuse + self: BaseClass & ReffuseHelpers.ReffuseHelpersClass ): ( { new(): Merge, Ext> } & StaticType ) => { - const class_ = class extends base {} + const class_ = class extends self {} return class_ } @@ -31,10 +31,10 @@ export const withContexts = >( ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] ) => < - BaseClass extends typeof ReffuseHelpers.ReffuseHelpers, + BaseClass extends ReffuseHelpers.ReffuseHelpersClass, R1 >( - self: BaseClass & { new(): ReffuseHelpers.ReffuseHelpers } + self: BaseClass & ReffuseHelpers.ReffuseHelpersClass ): ( { new(): Merge< @@ -42,12 +42,13 @@ export const withContexts = >( ReffuseHelpers.ReffuseHelpers > } & - StaticType - ) => new self().pipe( - instance => class extends self { - readonly contexts = [...instance.contexts, ...contexts] as any - } as any - ) + Merge< + StaticType, + StaticType> + > + ) => class extends self { + readonly contexts = [...self.contexts, ...contexts] + } as any const withMyContext = withContexts(MyContext) @@ -56,13 +57,8 @@ class ReffuseWithMyContext extends clsWithMyContext {} const t = new ReffuseWithMyContext() - const cls1 = make({ prout(this: ReffuseHelpers.ReffuseHelpers) {} })(Reffuse) class Cls1 extends cls1 {} - -const cls2 = make({ - aya() {} -})(cls) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 0ac8c55..47a0160 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -5,7 +5,17 @@ import * as ReffuseRuntime from "./ReffuseRuntime.js" import * as SetStateAction from "./SetStateAction.js" -export class ReffuseHelpers { +export interface RenderOptions { + /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ + readonly doNotReExecuteOnRuntimeOrContextChange?: boolean +} + +export interface ScopeOptions { + readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy +} + + +export abstract class ReffuseHelpers { declare ["constructor"]: ReffuseHelpersClass @@ -373,16 +383,15 @@ ReffuseHelpers.prototype.pipe = function pipe() { export interface ReffuseHelpersClass extends Pipeable.Pipeable { new(): ReffuseHelpers - prototype: ReffuseHelpers readonly contexts: readonly ReffuseContext.ReffuseContext[] } - -export interface RenderOptions { - /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ - readonly doNotReExecuteOnRuntimeOrContextChange?: boolean +(ReffuseHelpers as ReffuseHelpersClass).pipe = function pipe() { + return Pipeable.pipeArguments(this, arguments) } -export interface ScopeOptions { - readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy -} + +export const make = (contexts: readonly ReffuseContext.ReffuseContext[]): ReffuseHelpersClass => + class extends (ReffuseHelpers as ReffuseHelpersClass) { + static readonly contexts = contexts + } -- 2.49.1 From 28424b63cb0d59b697ee14873f216a9dbfd75107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 13:47:29 +0100 Subject: [PATCH 028/101] Working extension --- packages/reffuse/src/ReffuseExtension.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 2160bf9..4e16d61 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -24,7 +24,8 @@ const make = (extension: Ext) => StaticType ) => { const class_ = class extends self {} - return class_ + class_.prototype = { ...class_.prototype, ...extension } as any + return class_ as any } export const withContexts = >( @@ -55,10 +56,14 @@ const withMyContext = withContexts(MyContext) const clsWithMyContext = withMyContext(Reffuse) class ReffuseWithMyContext extends clsWithMyContext {} -const t = new ReffuseWithMyContext() -const cls1 = make({ +const withProut = make({ prout(this: ReffuseHelpers.ReffuseHelpers) {} -})(Reffuse) +}) -class Cls1 extends cls1 {} +class MyReffuse extends Reffuse.pipe( + withProut, + withContexts(MyContext), +) {} + +new MyReffuse().useFork() -- 2.49.1 From 60274266da489d197994c5efced1c2b17cbc2a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 20:00:02 +0100 Subject: [PATCH 029/101] Extension work --- packages/reffuse/src/Reffuse.ts | 420 ++--------------------- packages/reffuse/src/ReffuseExtension.ts | 34 +- packages/reffuse/src/ReffuseHelpers.ts | 46 ++- 3 files changed, 58 insertions(+), 442 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 5f899f5..7aac7eb 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,399 +1,29 @@ -import { Context, Effect, ExecutionStrategy, Exit, Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" -import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" -import * as ReffuseRuntime from "./ReffuseRuntime.js" -import * as SetStateAction from "./SetStateAction.js" +import * as ReffuseHelpers from "./ReffuseHelpers.js" +import type { Merge, StaticType } from "./types.js" -export class Reffuse { +export class Reffuse extends ReffuseHelpers.make() {} - constructor( - readonly contexts: readonly ReffuseContext.ReffuseContext[] - ) {} - - - useContext(): Context.Context { - return ReffuseContext.useMergeAll(...this.contexts) - } - - - useRunSync() { - const runtime = ReffuseRuntime.useRuntime() - const context = this.useContext() - - return React.useCallback(( - effect: Effect.Effect - ): A => effect.pipe( - Effect.provide(context), - Runtime.runSync(runtime), - ), [runtime, context]) - } - - useRunPromise() { - const runtime = ReffuseRuntime.useRuntime() - const context = this.useContext() - - return React.useCallback(( - effect: Effect.Effect, - options?: { readonly signal?: AbortSignal }, - ): Promise => effect.pipe( - Effect.provide(context), - effect => Runtime.runPromise(runtime)(effect, options), - ), [runtime, context]) - } - - useRunFork() { - const runtime = ReffuseRuntime.useRuntime() - const context = this.useContext() - - return React.useCallback(( - effect: Effect.Effect, - options?: Runtime.RunForkOptions, - ): Fiber.RuntimeFiber => effect.pipe( - Effect.provide(context), - effect => Runtime.runFork(runtime)(effect, options), - ), [runtime, context]) - } - - useRunCallback() { - const runtime = ReffuseRuntime.useRuntime() - const context = this.useContext() - - return React.useCallback(( - effect: Effect.Effect, - options?: Runtime.RunCallbackOptions, - ): Runtime.Cancel => effect.pipe( - Effect.provide(context), - effect => Runtime.runCallback(runtime)(effect, options), - ), [runtime, context]) - } - - - /** - * Reffuse equivalent to `React.useMemo`. - * - * `useMemo` will only recompute the memoized value by running the given synchronous effect when one of the deps has changed. \ - * Trying to run an asynchronous effect will throw. - * - * Changes to the Reffuse runtime or context will recompute the value in addition to the deps. - * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. - */ - useMemo( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions, - ): A { - const runSync = this.useRunSync() - - return React.useMemo(() => runSync(effect), [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), - ]) - } - - useMemoScoped( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): A { - const runSync = this.useRunSync() - - // Calculate an initial version of the value so that it can be accessed during the first render - const [initialScope, initialValue] = React.useMemo(() => Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect.pipe( - Effect.provideService(Scope.Scope, scope), - Effect.map(value => [scope, value] as const), - )), - - runSync, - ), []) - - // Keep track of the state of the initial scope - const initialScopeClosed = React.useRef(false) - - const [value, setValue] = React.useState(initialValue) - - React.useEffect(() => { - const closeInitialScopeIfNeeded = Scope.close(initialScope, Exit.void).pipe( - Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), - Effect.when(() => !initialScopeClosed.current), - ) - - const [scope, value] = closeInitialScopeIfNeeded.pipe( - Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect.pipe( - Effect.provideService(Scope.Scope, scope), - Effect.map(value => [scope, value] as const), - )) - )), - - runSync, - ) - - setValue(value) - return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), - ]) - - return value - } - - /** - * Reffuse equivalent to `React.useEffect`. - * - * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Trying to run an asynchronous effect will throw. - * - * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ - * Add finalizers to the Scope to handle cleanup logic. - * - * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. - * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. - * - * ### Example - * ``` - * useEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( - * Effect.flatMap(() => Console.log("Component mounted")) - * )) - * ``` - * - * Plain React equivalent: - * ``` - * React.useEffect(() => { - * console.log("Component mounted") - * return () => { console.log("Component unmounted") } - * }) - * ``` - */ - useEffect( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): void { - const runSync = this.useRunSync() - - return React.useEffect(() => { - const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), - runSync, - ) - - return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), - ]) - } - - /** - * Reffuse equivalent to `React.useLayoutEffect`. - * - * Executes a synchronous effect wrapped into a Scope when one of the deps has changed. Fires synchronously after all DOM mutations. \ - * Trying to run an asynchronous effect will throw. - * - * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ - * Add finalizers to the Scope to handle cleanup logic. - * - * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. - * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. - * - * ### Example - * ``` - * useLayoutEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( - * Effect.flatMap(() => Console.log("Component mounted")) - * )) - * ``` - * - * Plain React equivalent: - * ``` - * React.useLayoutEffect(() => { - * console.log("Component mounted") - * return () => { console.log("Component unmounted") } - * }) - * ``` - */ - useLayoutEffect( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): void { - const runSync = this.useRunSync() - - return React.useLayoutEffect(() => { - const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), - runSync, - ) - - return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), - ]) - } - - /** - * An asynchronous and non-blocking alternative to `React.useEffect`. - * - * Forks an effect wrapped into a Scope in the background when one of the deps has changed. - * - * The Scope is closed on every cleanup, i.e. when one of the deps has changed and the effect needs to be re-executed. \ - * Add finalizers to the Scope to handle cleanup logic. - * - * Changes to the Reffuse runtime or context will re-execute the effect in addition to the deps. - * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. - * - * ### Example - * ``` - * const timeRef = useRefFromEffect(DateTime.now) - * - * useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( - * Effect.map(() => Stream.repeatEffectWithSchedule( - * DateTime.now, - * Schedule.intersect(Schedule.forever, Schedule.spaced("1 second")), - * )), - * - * Effect.flatMap(Stream.runForEach(time => Ref.set(timeRef, time)), - * )), [timeRef]) - * - * const [time] = useRefState(timeRef) - * ``` - */ - useFork( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): void { - const runSync = this.useRunSync() - const runFork = this.useRunFork() - - return React.useEffect(() => { - const scope = runSync(options?.scope - ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) - : Scope.make(options?.finalizerExecutionStrategy) - ) - runFork(Effect.provideService(effect, Scope.Scope, scope), { ...options, scope }) - - return () => { runFork(Scope.close(scope, Exit.void)) } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], - ...(deps ?? []), - ]) - } - - usePromise( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): Promise { - const runSync = this.useRunSync() - const runFork = this.useRunFork() - - const [value, setValue] = React.useState(Promise.withResolvers().promise) - - React.useEffect(() => { - const { promise, resolve, reject } = Promise.withResolvers() - setValue(promise) - - const scope = runSync(options?.scope - ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) - : Scope.make(options?.finalizerExecutionStrategy) - ) - - const cleanup = () => { runFork(Scope.close(scope, Exit.void)) } - if (options?.signal) - options.signal.addEventListener("abort", cleanup) - - effect.pipe( - Effect.provideService(Scope.Scope, scope), - Effect.match({ - onSuccess: resolve, - onFailure: reject, - }), - effect => runFork(effect, { ...options, scope }), - ) - - return () => { - if (options?.signal) - options.signal.removeEventListener("abort", cleanup) - - cleanup() - } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], - ...(deps ?? []), - ]) - - return value - } - - - useRef(value: A): SubscriptionRef.SubscriptionRef { - return this.useMemo( - SubscriptionRef.make(value), - [], - { doNotReExecuteOnRuntimeOrContextChange: true }, // Do not recreate the ref when the context changes - ) - } - - /** - * Binds the state of a `SubscriptionRef` to the state of the React component. - * - * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes. - * - * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. - */ - useRefState(ref: SubscriptionRef.SubscriptionRef): [A, React.Dispatch>] { - const runSync = this.useRunSync() - - const initialState = React.useMemo(() => runSync(ref), []) - const [reactStateValue, setReactStateValue] = React.useState(initialState) - - this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => - setReactStateValue(v) - )), [ref]) - - const setValue = React.useCallback((setStateAction: React.SetStateAction) => - runSync(Ref.update(ref, prevState => - SetStateAction.value(setStateAction, prevState) - )), - [ref]) - - return [reactStateValue, setValue] - } - -} - - -export interface Reffuse extends Pipeable.Pipeable {} - -Reffuse.prototype.pipe = function pipe() { - return Pipeable.pipeArguments(this, arguments) -} - - -export interface RenderOptions { - /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ - readonly doNotReExecuteOnRuntimeOrContextChange?: boolean -} - -export interface ScopeOptions { - readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy -} - - -export const make = >( - ...contexts: [...{ [K in keyof T]: ReffuseContext.ReffuseContext }] -): Reffuse => - new Reffuse(contexts) - -// export const make = (): Reffuse => new Reffuse([]) - -// export const withContexts = >( -// ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] -// ) => -// , R1>(self: T & Reffuse): ( -// Reffuse & Exclude> -// ) => -// new Reffuse([...self.contexts, ...contexts as any]) as any +export const withContexts = >( + ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] +) => + < + BaseClass extends ReffuseHelpers.ReffuseHelpersClass, + R1 + >( + self: BaseClass & ReffuseHelpers.ReffuseHelpersClass + ): ( + { + new(): Merge< + InstanceType, + { constructor: ReffuseHelpers.ReffuseHelpersClass } + > + } & + Merge< + StaticType, + StaticType> + > + ) => class extends self { + readonly contexts = [...self.contexts, ...contexts] + } as any diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 4e16d61..2e0d69a 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,11 +1,10 @@ import { Effect } from "effect" +import * as Reffuse from "./Reffuse.js" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" -class Reffuse extends ReffuseHelpers.make([]) {} - class MyService extends Effect.Service()("MyService", { succeed: {} }) {} @@ -28,32 +27,9 @@ const make = (extension: Ext) => return class_ as any } -export const withContexts = >( - ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] -) => - < - BaseClass extends ReffuseHelpers.ReffuseHelpersClass, - R1 - >( - self: BaseClass & ReffuseHelpers.ReffuseHelpersClass - ): ( - { - new(): Merge< - InstanceType, - ReffuseHelpers.ReffuseHelpers - > - } & - Merge< - StaticType, - StaticType> - > - ) => class extends self { - readonly contexts = [...self.contexts, ...contexts] - } as any - -const withMyContext = withContexts(MyContext) -const clsWithMyContext = withMyContext(Reffuse) +const withMyContext = Reffuse.withContexts(MyContext) +const clsWithMyContext = withMyContext(Reffuse.Reffuse) class ReffuseWithMyContext extends clsWithMyContext {} @@ -61,9 +37,9 @@ const withProut = make({ prout(this: ReffuseHelpers.ReffuseHelpers) {} }) -class MyReffuse extends Reffuse.pipe( +class MyReffuse extends Reffuse.Reffuse.pipe( withProut, - withContexts(MyContext), + Reffuse.withContexts(MyContext), ) {} new MyReffuse().useFork() diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 47a0160..1f967ff 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -16,16 +16,15 @@ export interface ScopeOptions { export abstract class ReffuseHelpers { - declare ["constructor"]: ReffuseHelpersClass - useContext(): Context.Context { + useContext(this: ReffuseHelpers): Context.Context { return ReffuseContext.useMergeAll(...this.constructor.contexts) } - useRunSync() { + useRunSync(this: ReffuseHelpers) { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() @@ -37,7 +36,7 @@ export abstract class ReffuseHelpers { ), [runtime, context]) } - useRunPromise() { + useRunPromise(this: ReffuseHelpers) { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() @@ -50,7 +49,7 @@ export abstract class ReffuseHelpers { ), [runtime, context]) } - useRunFork() { + useRunFork(this: ReffuseHelpers) { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() @@ -63,7 +62,7 @@ export abstract class ReffuseHelpers { ), [runtime, context]) } - useRunCallback() { + useRunCallback(this: ReffuseHelpers) { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() @@ -86,7 +85,8 @@ export abstract class ReffuseHelpers { * Changes to the Reffuse runtime or context will recompute the value in addition to the deps. * You can disable this behavior by setting `doNotReExecuteOnRuntimeOrContextChange` to `true` in `options`. */ - useMemo( + useMemo( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: RenderOptions, @@ -99,7 +99,8 @@ export abstract class ReffuseHelpers { ]) } - useMemoScoped( + useMemoScoped( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, @@ -174,7 +175,8 @@ export abstract class ReffuseHelpers { * }) * ``` */ - useEffect( + useEffect( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, @@ -221,7 +223,8 @@ export abstract class ReffuseHelpers { * }) * ``` */ - useLayoutEffect( + useLayoutEffect( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, @@ -268,7 +271,8 @@ export abstract class ReffuseHelpers { * const [time] = useRefState(timeRef) * ``` */ - useFork( + useFork( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, @@ -290,7 +294,8 @@ export abstract class ReffuseHelpers { ]) } - usePromise( + usePromise( + this: ReffuseHelpers, effect: Effect.Effect, deps?: React.DependencyList, options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, @@ -337,7 +342,10 @@ export abstract class ReffuseHelpers { } - useRef(value: A): SubscriptionRef.SubscriptionRef { + useRef( + this: ReffuseHelpers, + value: A, + ): SubscriptionRef.SubscriptionRef { return this.useMemo( SubscriptionRef.make(value), [], @@ -352,7 +360,10 @@ export abstract class ReffuseHelpers { * * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. */ - useRefState(ref: SubscriptionRef.SubscriptionRef): [A, React.Dispatch>] { + useRefState( + this: ReffuseHelpers, + ref: SubscriptionRef.SubscriptionRef, + ): [A, React.Dispatch>] { const runSync = this.useRunSync() const initialState = React.useMemo(() => runSync(ref), []) @@ -370,7 +381,6 @@ export abstract class ReffuseHelpers { return [reactStateValue, setValue] } - } @@ -391,7 +401,7 @@ export interface ReffuseHelpersClass extends Pipeable.Pipeable { } -export const make = (contexts: readonly ReffuseContext.ReffuseContext[]): ReffuseHelpersClass => - class extends (ReffuseHelpers as ReffuseHelpersClass) { - static readonly contexts = contexts +export const make = (): ReffuseHelpersClass => + class extends (ReffuseHelpers as ReffuseHelpersClass) { + static readonly contexts = [] } -- 2.49.1 From 690dec1f1a989b5fa9a9a0921003fa41e300e91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 20:18:56 +0100 Subject: [PATCH 030/101] Finalized --- packages/example/src/reffuse.ts | 6 ++- packages/example/src/todos/reffuse.ts | 7 ++- packages/reffuse/src/ReffuseExtension.ts | 29 +----------- packages/reffuse/src/ReffuseHelper.ts | 57 ------------------------ packages/reffuse/src/index.ts | 2 + 5 files changed, 13 insertions(+), 88 deletions(-) delete mode 100644 packages/reffuse/src/ReffuseHelper.ts diff --git a/packages/example/src/reffuse.ts b/packages/example/src/reffuse.ts index beba3d3..ac2e2b8 100644 --- a/packages/example/src/reffuse.ts +++ b/packages/example/src/reffuse.ts @@ -10,4 +10,8 @@ export const GlobalContext = ReffuseContext.make< | HttpClient.HttpClient >() -export const R = Reffuse.make(GlobalContext) +export class GlobalReffuse extends Reffuse.Reffuse.pipe( + Reffuse.withContexts(GlobalContext) +) {} + +export const R = new GlobalReffuse() diff --git a/packages/example/src/todos/reffuse.ts b/packages/example/src/todos/reffuse.ts index 8502e12..d01357c 100644 --- a/packages/example/src/todos/reffuse.ts +++ b/packages/example/src/todos/reffuse.ts @@ -1,7 +1,10 @@ -import { GlobalContext } from "@/reffuse" +import { GlobalReffuse } from "@/reffuse" import { Reffuse, ReffuseContext } from "reffuse" import { TodosState } from "./services" export const TodosContext = ReffuseContext.make() -export const R = Reffuse.make(GlobalContext, TodosContext) + +export const R = new class TodosReffuse extends GlobalReffuse.pipe( + Reffuse.withContexts(TodosContext) +) {} diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 2e0d69a..0ba7909 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,18 +1,8 @@ -import { Effect } from "effect" -import * as Reffuse from "./Reffuse.js" -import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" -class MyService extends Effect.Service()("MyService", { - succeed: {} -}) {} - -const MyContext = ReffuseContext.make() - - -const make = (extension: Ext) => +export const make = (extension: Ext) => < BaseClass extends ReffuseHelpers.ReffuseHelpersClass, R @@ -26,20 +16,3 @@ const make = (extension: Ext) => class_.prototype = { ...class_.prototype, ...extension } as any return class_ as any } - - -const withMyContext = Reffuse.withContexts(MyContext) -const clsWithMyContext = withMyContext(Reffuse.Reffuse) -class ReffuseWithMyContext extends clsWithMyContext {} - - -const withProut = make({ - prout(this: ReffuseHelpers.ReffuseHelpers) {} -}) - -class MyReffuse extends Reffuse.Reffuse.pipe( - withProut, - Reffuse.withContexts(MyContext), -) {} - -new MyReffuse().useFork() diff --git a/packages/reffuse/src/ReffuseHelper.ts b/packages/reffuse/src/ReffuseHelper.ts deleted file mode 100644 index d41f572..0000000 --- a/packages/reffuse/src/ReffuseHelper.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { Context, Effect, ExecutionStrategy, Fiber, Pipeable, Runtime, Scope, SubscriptionRef } from "effect" -import type * as React from "react" - - -export interface ReffuseHelper extends Pipeable.Pipeable { - useContext(): Context.Context - - useRunSync(): (effect: Effect.Effect) => A - useRunPromise(): (effect: Effect.Effect, options?: { - readonly signal?: AbortSignal - }) => Promise - useRunFork(): (effect: Effect.Effect, options?: Runtime.RunForkOptions) => Fiber.RuntimeFiber - useRunCallback(): (effect: Effect.Effect, options?: Runtime.RunCallbackOptions) => Runtime.Cancel - - useMemo( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions, - ): A - - useMemoScoped( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): A - - useLayoutEffect( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: RenderOptions & ScopeOptions, - ): void - - useFork( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): void - - usePromise( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, - ): Promise - - useRef(value: A): SubscriptionRef.SubscriptionRef - useRefState(ref: SubscriptionRef.SubscriptionRef): readonly [A, React.Dispatch>] -} - - -export interface RenderOptions { - /** Prevents re-executing the effect when the Effect runtime or context changes. Defaults to `false`. */ - readonly doNotReExecuteOnRuntimeOrContextChange?: boolean -} - -export interface ScopeOptions { - readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy -} diff --git a/packages/reffuse/src/index.ts b/packages/reffuse/src/index.ts index 01c00cb..63af29b 100644 --- a/packages/reffuse/src/index.ts +++ b/packages/reffuse/src/index.ts @@ -1,4 +1,6 @@ export * as Reffuse from "./Reffuse.js" export * as ReffuseContext from "./ReffuseContext.js" +export * as ReffuseExtension from "./ReffuseExtension.js" +export * as ReffuseHelpers from "./ReffuseHelpers.js" export * as ReffuseRuntime from "./ReffuseRuntime.js" export * as SetStateAction from "./SetStateAction.js" -- 2.49.1 From da0f6168f0305701568f54d70711d545ac9c49a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 20:47:49 +0100 Subject: [PATCH 031/101] Fix --- packages/reffuse/src/Reffuse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 7aac7eb..5372b25 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -25,5 +25,5 @@ export const withContexts = >( StaticType> > ) => class extends self { - readonly contexts = [...self.contexts, ...contexts] + static readonly contexts = [...self.contexts, ...contexts] } as any -- 2.49.1 From ce3989ab77d25ef8e00babb1bb76985142596400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 21:09:44 +0100 Subject: [PATCH 032/101] Extension fix --- packages/reffuse/src/ReffuseExtension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index 0ba7909..f15af1b 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -2,7 +2,7 @@ import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" -export const make = (extension: Ext) => +export const make = (extension: () => Ext) => < BaseClass extends ReffuseHelpers.ReffuseHelpersClass, R @@ -13,6 +13,6 @@ export const make = (extension: Ext) => StaticType ) => { const class_ = class extends self {} - class_.prototype = { ...class_.prototype, ...extension } as any + Object.assign(class_.prototype, extension()) return class_ as any } -- 2.49.1 From 85e7b549624200ab3bf315bf52e72720203341b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 21:24:38 +0100 Subject: [PATCH 033/101] extension-lazyref --- bun.lock | 11 ++++++++ packages/extension-lazyref/README.md | 12 ++++++++ packages/extension-lazyref/package.json | 36 ++++++++++++++++++++++++ packages/extension-lazyref/src/index.ts | 0 packages/extension-lazyref/tsconfig.json | 33 ++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 packages/extension-lazyref/README.md create mode 100644 packages/extension-lazyref/package.json create mode 100644 packages/extension-lazyref/src/index.ts create mode 100644 packages/extension-lazyref/tsconfig.json diff --git a/bun.lock b/bun.lock index bf4b7fe..b932993 100644 --- a/bun.lock +++ b/bun.lock @@ -41,6 +41,15 @@ "vite": "^6.1.0", }, }, + "packages/extension-lazyref": { + "name": "@reffuse/extension-lazyref", + "version": "0.1.0", + "devDependencies": { + "@types/react": "^19.0.10", + "effect": "~3.13.1", + "react": "^19.0.0", + }, + }, "packages/reffuse": { "name": "reffuse", "version": "0.1.1", @@ -314,6 +323,8 @@ "@reffuse/example": ["@reffuse/example@workspace:packages/example"], + "@reffuse/extension-lazyref": ["@reffuse/extension-lazyref@workspace:packages/extension-lazyref"], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="], diff --git a/packages/extension-lazyref/README.md b/packages/extension-lazyref/README.md new file mode 100644 index 0000000..dab847a --- /dev/null +++ b/packages/extension-lazyref/README.md @@ -0,0 +1,12 @@ +# Reffuse + +[Effect-TS](https://effect.website/) integration for React 19+ with the aim of integrating the Effect context system within React's component hierarchy, while avoiding touching React's internals. + +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. + +## Dependencies +(needs to be manually installed) +- `effect` +- `react` 19+ diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json new file mode 100644 index 0000000..17434bd --- /dev/null +++ b/packages/extension-lazyref/package.json @@ -0,0 +1,36 @@ +{ + "name": "@reffuse/extension-lazyref", + "version": "0.1.0", + "type": "module", + "files": [ + "./README.md", + "./dist" + ], + "license": "MIT", + "repository": { + "url": "git+https://github.com/Thiladev/reffuse.git" + }, + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./*": { + "types": "./dist/*.d.ts", + "default": "./dist/*.js" + } + }, + "scripts": { + "build": "tsc", + "lint:tsc": "tsc --noEmit", + "clean:cache": "rm -f tsconfig.tsbuildinfo", + "clean:dist": "rm -rf dist", + "clean:node": "rm -rf node_modules" + }, + "devDependencies": { + "@types/react": "^19.0.10", + "effect": "~3.13.1", + "react": "^19.0.0" + } +} diff --git a/packages/extension-lazyref/src/index.ts b/packages/extension-lazyref/src/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/extension-lazyref/tsconfig.json b/packages/extension-lazyref/tsconfig.json new file mode 100644 index 0000000..eea16a8 --- /dev/null +++ b/packages/extension-lazyref/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "NodeNext", + "moduleDetection": "force", + "jsx": "react-jsx", + // "allowJs": true, + + // Bundler mode + "moduleResolution": "NodeNext", + // "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + // "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + + // Build + "outDir": "./dist", + "declaration": true + }, + + "include": ["./src"] +} -- 2.49.1 From 411397c7de7e496141df24789c605774b8069326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 24 Feb 2025 21:30:13 +0100 Subject: [PATCH 034/101] Fix --- packages/reffuse/src/Reffuse.ts | 2 +- packages/reffuse/src/ReffuseExtension.ts | 2 +- packages/reffuse/src/ReffuseHelpers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 5372b25..0721298 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,4 +1,4 @@ -import * as ReffuseContext from "./ReffuseContext.js" +import type * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index f15af1b..ce1fdea 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,4 +1,4 @@ -import * as ReffuseHelpers from "./ReffuseHelpers.js" +import type * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 1f967ff..1605791 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -1,4 +1,4 @@ -import { Context, Effect, ExecutionStrategy, Exit, Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" -- 2.49.1 From 38fcafb15cedb816a4551fab624a4dc36f6d55bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 10:21:34 +0100 Subject: [PATCH 035/101] Dependencies --- bun.lock | 206 +++++++++--------------- packages/example/package.json | 26 +-- packages/extension-lazyref/package.json | 6 +- packages/reffuse/package.json | 6 +- 4 files changed, 96 insertions(+), 148 deletions(-) diff --git a/bun.lock b/bun.lock index b932993..b795ae8 100644 --- a/bun.lock +++ b/bun.lock @@ -12,50 +12,50 @@ "name": "@reffuse/example", "version": "0.0.0", "dependencies": { - "@effect/platform": "~0.77.1", - "@effect/platform-browser": "~0.56.1", + "@effect/platform": "^0.77.2", + "@effect/platform-browser": "^0.56.2", "@radix-ui/themes": "^3.2.0", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", - "effect": "~3.13.1", - "lucide-react": "^0.475.0", + "effect": "^3.13.2", + "lucide-react": "^0.476.0", "mobx": "^6.13.6", "reffuse": "workspace:*", }, "devDependencies": { - "@eslint/js": "^9.20.0", - "@tanstack/react-router": "^1.105.0", - "@tanstack/router-devtools": "^1.105.0", - "@tanstack/router-plugin": "^1.105.0", + "@eslint/js": "^9.21.0", + "@tanstack/react-router": "^1.111.7", + "@tanstack/router-devtools": "^1.111.7", + "@tanstack/router-plugin": "^1.111.7", "@thilawyn/thilaschema": "^0.1.4", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.20.1", + "eslint": "^9.21.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", - "globals": "^15.15.0", + "globals": "^16.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "typescript-eslint": "^8.24.1", - "vite": "^6.1.0", + "typescript-eslint": "^8.25.0", + "vite": "^6.2.0", }, }, "packages/extension-lazyref": { "name": "@reffuse/extension-lazyref", "version": "0.1.0", - "devDependencies": { - "@types/react": "^19.0.10", - "effect": "~3.13.1", + "peerDependencies": { + "@types/react": "^19.0.0", + "effect": "^3.13.0", "react": "^19.0.0", }, }, "packages/reffuse": { "name": "reffuse", "version": "0.1.1", - "devDependencies": { - "@types/react": "^19.0.10", - "effect": "~3.13.1", + "peerDependencies": { + "@types/react": "^19.0.0", + "effect": "^3.13.0", "react": "^19.0.0", }, }, @@ -103,59 +103,59 @@ "@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="], - "@effect/platform": ["@effect/platform@0.77.1", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.13.1" } }, "sha512-3oHbKiOLN7AIjyucZW+kH5ebG1PhEEBrsdd+HWbDQbAG0gVZfgOUmXR9cyM6M9L+9oVPgOW5mIgcEi6RvD02Cw=="], + "@effect/platform": ["@effect/platform@0.77.2", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.13.2" } }, "sha512-stvroKHJVfjd3XhZJEPUAOgzqu9DH1vnGHIAjfs2ma6Z4qcjVpFXrxa0ZYmwRaWVIFsiADMenkN0I7XrRdAgLw=="], - "@effect/platform-browser": ["@effect/platform-browser@0.56.1", "", { "dependencies": { "multipasta": "^0.2.5" }, "peerDependencies": { "@effect/platform": "^0.77.1", "effect": "^3.13.1" } }, "sha512-LKuLblMHuHKsv9ZdN8j44zzY4ftQaGh5jsOWqTtoHIDSS8beUOcp2a5JnsRT310N4Ym7e14cKWfqgdAXm+J0dw=="], + "@effect/platform-browser": ["@effect/platform-browser@0.56.2", "", { "dependencies": { "multipasta": "^0.2.5" }, "peerDependencies": { "@effect/platform": "^0.77.2", "effect": "^3.13.2" } }, "sha512-mzCNipg3FN9/ATPEO7Cc3cLmTF4gtdoQSVVi5RPJzIxXflVHbNmMFSIuFdGp0W3AbrQ20dfF6FGFaRUo3aFHeA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.0", "", { "os": "android", "cpu": "arm" }, "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.0", "", { "os": "android", "cpu": "arm64" }, "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.24.2", "", { "os": "android", "cpu": "x64" }, "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.0", "", { "os": "android", "cpu": "x64" }, "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.24.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.24.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.0", "", { "os": "none", "cpu": "arm64" }, "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.24.2", "", { "os": "none", "cpu": "x64" }, "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.0", "", { "os": "none", "cpu": "x64" }, "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.24.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.24.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.24.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.4.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA=="], @@ -163,15 +163,15 @@ "@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="], - "@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="], + "@eslint/core": ["@eslint/core@0.12.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg=="], - "@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="], + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ=="], - "@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="], + "@eslint/js": ["@eslint/js@9.21.0", "", {}, "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="], + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.7", "", { "dependencies": { "@eslint/core": "^0.12.0", "levn": "^0.4.1" } }, "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g=="], "@floating-ui/core": ["@floating-ui/core@1.6.9", "", { "dependencies": { "@floating-ui/utils": "^0.2.9" } }, "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw=="], @@ -187,7 +187,7 @@ "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="], + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], @@ -367,17 +367,17 @@ "@tanstack/history": ["@tanstack/history@1.99.13", "", {}, "sha512-JMd7USmnp8zV8BRGIjALqzPxazvKtQ7PGXQC7n39HpbqdsmfV2ePCzieO84IvN+mwsTrXErpbjI4BfKCa+ZNCg=="], - "@tanstack/react-router": ["@tanstack/react-router@1.105.0", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "^1.104.1", "jsesc": "^3.1.0", "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-k4Umuy7rna/hhfHkmbq9dCmj9Hp8D0V6dPNCrCXceJb0gQWGxl1KWLXFbw8Ywe/sNyzIzPrMwrMit++MXHo8iw=="], + "@tanstack/react-router": ["@tanstack/react-router@1.111.7", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "^1.111.7", "jsesc": "^3.1.0", "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-/hOWy7lPmVfRqbwIy2d9mvVLA6ZC4tbcgLDdMXCNRN93LMsGEHCTrgFADdSL2f/rvhPyHeYxsFazEo9+ktgUiw=="], "@tanstack/react-store": ["@tanstack/react-store@0.7.0", "", { "dependencies": { "@tanstack/store": "0.7.0", "use-sync-external-store": "^1.4.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-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng=="], - "@tanstack/router-core": ["@tanstack/router-core@1.104.1", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/store": "^0.7.0" } }, "sha512-8nP/V5paP+S/17rlw+B2F12R2bB9PixU/+qnD2QdCjK1ajnG4qA0pVN3VSTQe2oCKND6GPZpm2ikmQWumwss9Q=="], + "@tanstack/router-core": ["@tanstack/router-core@1.111.7", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/store": "^0.7.0" } }, "sha512-N3u3HGBNb1k+MvL15CGmE4KFEDy3euU/L3ENXjmzPm8zfpeVjs+Tyk3y0nicAk3MSSboGXVU1po19RATdWnTsg=="], - "@tanstack/router-devtools": ["@tanstack/router-devtools@1.105.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/react-router": "^1.105.0", "csstype": "^3.0.10", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["csstype"] }, "sha512-X583hyUyhL30g5ax1J/lbgb3DYpgsiSUv0ERaF5Gg0PoxPYJSybmw79xwFbrTBDxXCXxfg4AFCAEcmkAQemPWA=="], + "@tanstack/router-devtools": ["@tanstack/router-devtools@1.111.7", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/react-router": "^1.111.7", "csstype": "^3.0.10", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["csstype"] }, "sha512-xZpiIWy/HBhpYUqUxT1dNUn5smQhWhkgjNlJOATzrm81G5T3l2jEr79XPXqwRndWzu2WKqv1kPkScC0ekRgE7Q=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.105.0", "", { "dependencies": { "@tanstack/virtual-file-routes": "^1.99.0", "prettier": "^3.5.0", "tsx": "^4.19.2", "zod": "^3.24.1" }, "peerDependencies": { "@tanstack/react-router": "^1.105.0" }, "optionalPeers": ["@tanstack/react-router"] }, "sha512-P5e4S7XcaECWKDdR4Zs/FpY4Z127zGv1FcmKEzsFRSGJZm7lHshWayYJIjwkeJ+Ier2IkVN+VRaFWC5GKv0jIg=="], + "@tanstack/router-generator": ["@tanstack/router-generator@1.111.7", "", { "dependencies": { "@tanstack/virtual-file-routes": "^1.99.0", "prettier": "^3.5.0", "tsx": "^4.19.2", "zod": "^3.24.1" }, "peerDependencies": { "@tanstack/react-router": "^1.111.7" }, "optionalPeers": ["@tanstack/react-router"] }, "sha512-+jHX35iF45NHQvHzXuLgyCILUUTyMl3EeClKNkfdaKLvV1adwGDQr24cSKDQLmNKEDXGTijBI5nX8ntkKo5oyA=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.105.0", "", { "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-generator": "^1.105.0", "@tanstack/router-utils": "^1.102.2", "@tanstack/virtual-file-routes": "^1.99.0", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/babel__traverse": "^7.20.6", "babel-dead-code-elimination": "^1.0.9", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.1" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.105.0", "vite": ">=5.0.0 || >=6.0.0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "webpack"] }, "sha512-iGwKZIyl8+os4PA9v57BlTtKVnQ5mCvxYT4p5TR/Q8zW1KBs4fC5F7EhL1BgH8fY12IL4ByuuJ+porzp+mfmJQ=="], + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.111.7", "", { "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-core": "^1.111.7", "@tanstack/router-generator": "^1.111.7", "@tanstack/router-utils": "^1.102.2", "@tanstack/virtual-file-routes": "^1.99.0", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/babel__traverse": "^7.20.6", "babel-dead-code-elimination": "^1.0.9", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.1" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.111.7", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-aiT/j2OadGbqEWTZUY53o2UeVQIR11+S1h1Gq6GYxQmD/OjdyK/WiMighBK5zeryeWYG4XeC8eFlXMoyuG0v+g=="], "@tanstack/router-utils": ["@tanstack/router-utils@1.102.2", "", { "dependencies": { "@babel/generator": "^7.26.8", "@babel/parser": "^7.26.8", "ansis": "^3.11.0", "diff": "^7.0.0" } }, "sha512-Uwl2nbrxhCzviaHHBLNPhSC/OMpZLdOTxTJndUSsXTzWUP4IoQcVmngaIsxi9iriE3ArC1VXuanUAkfGmimNOQ=="], @@ -407,21 +407,21 @@ "@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.24.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/type-utils": "8.24.1", "@typescript-eslint/utils": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.25.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/type-utils": "8.25.0", "@typescript-eslint/utils": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.24.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/types": "8.24.1", "@typescript-eslint/typescript-estree": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.25.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/types": "8.25.0", "@typescript-eslint/typescript-estree": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1" } }, "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0" } }, "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.24.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.24.1", "@typescript-eslint/utils": "8.24.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.25.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.25.0", "@typescript-eslint/utils": "8.25.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.24.1", "", {}, "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.25.0", "", {}, "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.24.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/types": "8.24.1", "@typescript-eslint/typescript-estree": "8.24.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.25.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/types": "8.25.0", "@typescript-eslint/typescript-estree": "8.25.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.24.1", "", { "dependencies": { "@typescript-eslint/types": "8.24.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="], @@ -433,7 +433,7 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansis": ["ansis@3.15.0", "", {}, "sha512-zIcWDJ+Kwqxfdnogx66Gxzr0kVmCcRAdat9nlY2IHsshqTN4fBH6tMeRMPA/2w0rpBayIJvjQAaa2/4RDrNqwg=="], + "ansis": ["ansis@3.16.0", "", {}, "sha512-sU7d/tfZiYrsIAXbdL/CNZld5bCkruzwT5KmqmadCJYxuLxHAOBjidxD5+iLmN/6xEfjcQq1l7OpsiCBlc4LzA=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -485,17 +485,17 @@ "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], - "effect": ["effect@3.13.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-YbA45m51eZapqy/ptZvIIZi+XBj13fPCzbiDRLgxZTEUhKuf4xLzuuSsKc61Y3SIscMM2o+VPht2ty+bVEQHQQ=="], + "effect": ["effect@3.13.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-/w+CPqHDJ33Wq7xC4YKAchrEEPtjvxh563xH9kDTZp99seNYBoBs87vl8DJwartEjj+KLQLP8PzoDne+XmGT2A=="], - "electron-to-chromium": ["electron-to-chromium@1.5.102", "", {}, "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q=="], + "electron-to-chromium": ["electron-to-chromium@1.5.104", "", {}, "sha512-Us9M2L4cO/zMBqVkJtnj353nQhMju9slHm62NprKTmdF3HH8wYOtNvDFq/JB2+ZRoGLzdvYDiATlMHs98XBM1g=="], - "esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="], + "esbuild": ["esbuild@0.25.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.0", "@esbuild/android-arm": "0.25.0", "@esbuild/android-arm64": "0.25.0", "@esbuild/android-x64": "0.25.0", "@esbuild/darwin-arm64": "0.25.0", "@esbuild/darwin-x64": "0.25.0", "@esbuild/freebsd-arm64": "0.25.0", "@esbuild/freebsd-x64": "0.25.0", "@esbuild/linux-arm": "0.25.0", "@esbuild/linux-arm64": "0.25.0", "@esbuild/linux-ia32": "0.25.0", "@esbuild/linux-loong64": "0.25.0", "@esbuild/linux-mips64el": "0.25.0", "@esbuild/linux-ppc64": "0.25.0", "@esbuild/linux-riscv64": "0.25.0", "@esbuild/linux-s390x": "0.25.0", "@esbuild/linux-x64": "0.25.0", "@esbuild/netbsd-arm64": "0.25.0", "@esbuild/netbsd-x64": "0.25.0", "@esbuild/openbsd-arm64": "0.25.0", "@esbuild/openbsd-x64": "0.25.0", "@esbuild/sunos-x64": "0.25.0", "@esbuild/win32-arm64": "0.25.0", "@esbuild/win32-ia32": "0.25.0", "@esbuild/win32-x64": "0.25.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@9.20.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g=="], + "eslint": ["eslint@9.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.0", "@eslint/js": "9.21.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg=="], "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.1.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw=="], @@ -537,7 +537,7 @@ "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - "flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="], + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -549,7 +549,7 @@ "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], + "globals": ["globals@16.0.0", "", {}, "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A=="], "goober": ["goober@2.1.16", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g=="], @@ -597,7 +597,7 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "lucide-react": ["lucide-react@0.475.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg=="], + "lucide-react": ["lucide-react@0.476.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-x6cLTk8gahdUPje0hSgLN1/MgiJH+Xl90Xoxy9bkPAsMPOUiyRSKR4JCDPGVCEpyqnZXH3exFWNItcvra9WzUQ=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], @@ -619,7 +619,7 @@ "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - "npm-check-updates": ["npm-check-updates@17.1.14", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-dr4bXIxETubLI1tFGeock5hN8yVjahvaVpx+lPO4/O2md3zJuxB7FgH3MIoTvQSCgsgkIRpe0skti01IEAA5tA=="], + "npm-check-updates": ["npm-check-updates@17.1.15", "", { "bin": { "npm-check-updates": "build/cli.js", "ncu": "build/cli.js" } }, "sha512-miATvKu5rjec/1wxc5TGDjpsucgtCHwRVZorZpDkS6NzdWXfnUWlN4abZddWb7XSijAuBNzzYglIdTm9SbgMVg=="], "npm-sort": ["npm-sort@0.0.4", "", { "bin": { "npm-sort": "./index.js" } }, "sha512-S5Id/3Jvr7Cf/QnWjRteprngERCBhhEFOM+wMhUrAYP060/HUBC1aL5GoXS3xITlgacJCWaSmP4HQaAt91nNYQ=="], @@ -639,11 +639,11 @@ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "postcss": ["postcss@8.5.2", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA=="], + "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.5.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw=="], + "prettier": ["prettier@3.5.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -705,7 +705,7 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsx": ["tsx@4.19.2", "", { "dependencies": { "esbuild": "~0.23.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g=="], + "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], @@ -713,7 +713,7 @@ "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], - "typescript-eslint": ["typescript-eslint@8.24.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.24.1", "@typescript-eslint/parser": "8.24.1", "@typescript-eslint/utils": "8.24.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA=="], + "typescript-eslint": ["typescript-eslint@8.25.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.25.0", "@typescript-eslint/parser": "8.25.0", "@typescript-eslint/utils": "8.25.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q=="], "unplugin": ["unplugin@2.2.0", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw=="], @@ -727,7 +727,7 @@ "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="], - "vite": ["vite@6.1.0", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.5.1", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ=="], + "vite": ["vite@6.2.0", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], @@ -747,8 +747,6 @@ "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - "@eslint/plugin-kit/@eslint/core": ["@eslint/core@0.10.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw=="], - "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -759,56 +757,6 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "tsx/esbuild": ["esbuild@0.23.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.23.1", "@esbuild/android-arm": "0.23.1", "@esbuild/android-arm64": "0.23.1", "@esbuild/android-x64": "0.23.1", "@esbuild/darwin-arm64": "0.23.1", "@esbuild/darwin-x64": "0.23.1", "@esbuild/freebsd-arm64": "0.23.1", "@esbuild/freebsd-x64": "0.23.1", "@esbuild/linux-arm": "0.23.1", "@esbuild/linux-arm64": "0.23.1", "@esbuild/linux-ia32": "0.23.1", "@esbuild/linux-loong64": "0.23.1", "@esbuild/linux-mips64el": "0.23.1", "@esbuild/linux-ppc64": "0.23.1", "@esbuild/linux-riscv64": "0.23.1", "@esbuild/linux-s390x": "0.23.1", "@esbuild/linux-x64": "0.23.1", "@esbuild/netbsd-x64": "0.23.1", "@esbuild/openbsd-arm64": "0.23.1", "@esbuild/openbsd-x64": "0.23.1", "@esbuild/sunos-x64": "0.23.1", "@esbuild/win32-arm64": "0.23.1", "@esbuild/win32-ia32": "0.23.1", "@esbuild/win32-x64": "0.23.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg=="], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.23.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ=="], - - "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.23.1", "", { "os": "android", "cpu": "arm" }, "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ=="], - - "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.23.1", "", { "os": "android", "cpu": "arm64" }, "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw=="], - - "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.23.1", "", { "os": "android", "cpu": "x64" }, "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg=="], - - "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.23.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q=="], - - "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.23.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw=="], - - "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.23.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA=="], - - "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.23.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g=="], - - "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.23.1", "", { "os": "linux", "cpu": "arm" }, "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ=="], - - "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.23.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g=="], - - "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.23.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ=="], - - "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw=="], - - "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q=="], - - "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.23.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw=="], - - "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.23.1", "", { "os": "linux", "cpu": "none" }, "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA=="], - - "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.23.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw=="], - - "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.23.1", "", { "os": "linux", "cpu": "x64" }, "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ=="], - - "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.23.1", "", { "os": "none", "cpu": "x64" }, "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA=="], - - "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.23.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q=="], - - "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.23.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA=="], - - "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.23.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA=="], - - "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.23.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A=="], - - "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.23.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ=="], - - "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.23.1", "", { "os": "win32", "cpu": "x64" }, "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg=="], } } diff --git a/packages/example/package.json b/packages/example/package.json index 2bb12a0..24c7735 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -11,35 +11,35 @@ "preview": "vite preview" }, "devDependencies": { - "@eslint/js": "^9.20.0", - "@tanstack/react-router": "^1.105.0", - "@tanstack/router-devtools": "^1.105.0", - "@tanstack/router-plugin": "^1.105.0", + "@eslint/js": "^9.21.0", + "@tanstack/react-router": "^1.111.7", + "@tanstack/router-devtools": "^1.111.7", + "@tanstack/router-plugin": "^1.111.7", "@thilawyn/thilaschema": "^0.1.4", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.20.1", + "eslint": "^9.21.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", - "globals": "^15.15.0", + "globals": "^16.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "typescript-eslint": "^8.24.1", - "vite": "^6.1.0" + "typescript-eslint": "^8.25.0", + "vite": "^6.2.0" }, "dependencies": { - "@effect/platform": "~0.77.1", - "@effect/platform-browser": "~0.56.1", + "@effect/platform": "^0.77.2", + "@effect/platform-browser": "^0.56.2", "@radix-ui/themes": "^3.2.0", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", - "effect": "~3.13.1", - "lucide-react": "^0.475.0", + "effect": "^3.13.2", + "lucide-react": "^0.476.0", "mobx": "^6.13.6", "reffuse": "workspace:*" }, "overrides": { - "effect": "~3.13.1" + "effect": "^3.13.2" } } diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index 17434bd..ea92696 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -28,9 +28,9 @@ "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" }, - "devDependencies": { - "@types/react": "^19.0.10", - "effect": "~3.13.1", + "peerDependencies": { + "@types/react": "^19.0.0", + "effect": "^3.13.0", "react": "^19.0.0" } } diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index 8b27899..5082340 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -28,9 +28,9 @@ "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" }, - "devDependencies": { - "@types/react": "^19.0.10", - "effect": "~3.13.1", + "peerDependencies": { + "@types/react": "^19.0.0", + "effect": "^3.13.0", "react": "^19.0.0" } } -- 2.49.1 From 8873e81f7cd80c5d55871f268fdf0a338e0639b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 10:31:43 +0100 Subject: [PATCH 036/101] Dependencies --- bun.lock | 1 + packages/extension-lazyref/package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index b795ae8..238d47b 100644 --- a/bun.lock +++ b/bun.lock @@ -48,6 +48,7 @@ "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", + "reffuse": "^0.1.1", }, }, "packages/reffuse": { diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index ea92696..16f34b6 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -31,6 +31,7 @@ "peerDependencies": { "@types/react": "^19.0.0", "effect": "^3.13.0", - "react": "^19.0.0" + "react": "^19.0.0", + "reffuse": "^0.1.1" } } -- 2.49.1 From d9a01dae0f6abd108f38eb1272e9dafca4bf2831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 11:22:49 +0100 Subject: [PATCH 037/101] withLazyRef --- bun.lock | 1 + packages/extension-lazyref/package.json | 1 + packages/extension-lazyref/src/index.ts | 29 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/bun.lock b/bun.lock index 238d47b..5743f6a 100644 --- a/bun.lock +++ b/bun.lock @@ -45,6 +45,7 @@ "name": "@reffuse/extension-lazyref", "version": "0.1.0", "peerDependencies": { + "@typed/lazy-ref": "^0.3.3", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index 16f34b6..8ca9de8 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -29,6 +29,7 @@ "clean:node": "rm -rf node_modules" }, "peerDependencies": { + "@typed/lazy-ref": "^0.3.3", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", diff --git a/packages/extension-lazyref/src/index.ts b/packages/extension-lazyref/src/index.ts index e69de29..301509a 100644 --- a/packages/extension-lazyref/src/index.ts +++ b/packages/extension-lazyref/src/index.ts @@ -0,0 +1,29 @@ +import * as LazyRef from "@typed/lazy-ref" +import { Effect, Stream } from "effect" +import * as React from "react" +import { ReffuseExtension, ReffuseHelpers, SetStateAction } from "reffuse" + + +export const withLazyRef = ReffuseExtension.make(() => ({ + useLazyRefState( + this: ReffuseHelpers.ReffuseHelpers, + ref: LazyRef.LazyRef, + ): [A, React.Dispatch>] { + const runSync = this.useRunSync() + + const initialState = React.useMemo(() => runSync(ref), []) + const [reactStateValue, setReactStateValue] = React.useState(initialState) + + this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + setReactStateValue(v) + )), [ref]) + + const setValue = React.useCallback((setStateAction: React.SetStateAction) => + runSync(LazyRef.update(ref, prevState => + SetStateAction.value(setStateAction, prevState) + )), + [ref]) + + return [reactStateValue, setValue] + }, +})) -- 2.49.1 From 8754020323badd2d5f8798d9f656be6f237ac266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 12:17:45 +0100 Subject: [PATCH 038/101] Working lazyref extension --- packages/example/package.json | 1 + packages/example/src/reffuse.ts | 4 ++- packages/example/src/routeTree.gen.ts | 44 ++++++++++++++++++++++-- packages/example/src/routes/lazyref.tsx | 31 +++++++++++++++++ packages/extension-lazyref/src/index.ts | 4 +-- packages/reffuse/src/Reffuse.ts | 18 ++++++++++ packages/reffuse/src/ReffuseContext.tsx | 3 +- packages/reffuse/src/ReffuseExtension.ts | 23 ++++--------- 8 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 packages/example/src/routes/lazyref.tsx diff --git a/packages/example/package.json b/packages/example/package.json index 24c7735..e1a234e 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -32,6 +32,7 @@ "@effect/platform": "^0.77.2", "@effect/platform-browser": "^0.56.2", "@radix-ui/themes": "^3.2.0", + "@reffuse/extension-lazyref": "workspace:*", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", "effect": "^3.13.2", diff --git a/packages/example/src/reffuse.ts b/packages/example/src/reffuse.ts index ac2e2b8..0aefd92 100644 --- a/packages/example/src/reffuse.ts +++ b/packages/example/src/reffuse.ts @@ -1,5 +1,6 @@ import { HttpClient } from "@effect/platform" import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" +import { LazyRefExtension } from "@reffuse/extension-lazyref" import { Reffuse, ReffuseContext } from "reffuse" @@ -11,7 +12,8 @@ export const GlobalContext = ReffuseContext.make< >() export class GlobalReffuse extends Reffuse.Reffuse.pipe( - Reffuse.withContexts(GlobalContext) + Reffuse.withExtension(LazyRefExtension), + Reffuse.withContexts(GlobalContext), ) {} export const R = new GlobalReffuse() diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index b1e3d9c..98b4224 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -14,6 +14,7 @@ import { Route as rootRoute } from './routes/__root' import { Route as TimeImport } from './routes/time' import { Route as TestsImport } from './routes/tests' import { Route as PromiseImport } from './routes/promise' +import { Route as LazyrefImport } from './routes/lazyref' import { Route as CountImport } from './routes/count' import { Route as BlankImport } from './routes/blank' import { Route as IndexImport } from './routes/index' @@ -38,6 +39,12 @@ const PromiseRoute = PromiseImport.update({ getParentRoute: () => rootRoute, } as any) +const LazyrefRoute = LazyrefImport.update({ + id: '/lazyref', + path: '/lazyref', + getParentRoute: () => rootRoute, +} as any) + const CountRoute = CountImport.update({ id: '/count', path: '/count', @@ -81,6 +88,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof CountImport parentRoute: typeof rootRoute } + '/lazyref': { + id: '/lazyref' + path: '/lazyref' + fullPath: '/lazyref' + preLoaderRoute: typeof LazyrefImport + parentRoute: typeof rootRoute + } '/promise': { id: '/promise' path: '/promise' @@ -111,6 +125,7 @@ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute @@ -120,6 +135,7 @@ export interface FileRoutesByTo { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute @@ -130,6 +146,7 @@ export interface FileRoutesById { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute + '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute '/tests': typeof TestsRoute '/time': typeof TimeRoute @@ -137,10 +154,25 @@ export interface FileRoutesById { export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' + fullPaths: + | '/' + | '/blank' + | '/count' + | '/lazyref' + | '/promise' + | '/tests' + | '/time' fileRoutesByTo: FileRoutesByTo - to: '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' - id: '__root__' | '/' | '/blank' | '/count' | '/promise' | '/tests' | '/time' + to: '/' | '/blank' | '/count' | '/lazyref' | '/promise' | '/tests' | '/time' + id: + | '__root__' + | '/' + | '/blank' + | '/count' + | '/lazyref' + | '/promise' + | '/tests' + | '/time' fileRoutesById: FileRoutesById } @@ -148,6 +180,7 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute BlankRoute: typeof BlankRoute CountRoute: typeof CountRoute + LazyrefRoute: typeof LazyrefRoute PromiseRoute: typeof PromiseRoute TestsRoute: typeof TestsRoute TimeRoute: typeof TimeRoute @@ -157,6 +190,7 @@ const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, BlankRoute: BlankRoute, CountRoute: CountRoute, + LazyrefRoute: LazyrefRoute, PromiseRoute: PromiseRoute, TestsRoute: TestsRoute, TimeRoute: TimeRoute, @@ -175,6 +209,7 @@ export const routeTree = rootRoute "/", "/blank", "/count", + "/lazyref", "/promise", "/tests", "/time" @@ -189,6 +224,9 @@ export const routeTree = rootRoute "/count": { "filePath": "count.tsx" }, + "/lazyref": { + "filePath": "lazyref.tsx" + }, "/promise": { "filePath": "promise.tsx" }, diff --git a/packages/example/src/routes/lazyref.tsx b/packages/example/src/routes/lazyref.tsx new file mode 100644 index 0000000..586f25c --- /dev/null +++ b/packages/example/src/routes/lazyref.tsx @@ -0,0 +1,31 @@ +import { R } from "@/reffuse" +import { Button, Text } from "@radix-ui/themes" +import { createFileRoute } from "@tanstack/react-router" +import * as LazyRef from "@typed/lazy-ref" +import { Suspense, use } from "react" + + +export const Route = createFileRoute("/lazyref")({ + component: RouteComponent +}) + +function RouteComponent() { + const promise = R.usePromise(LazyRef.of(0)) + + return ( + Loading...}> + + + ) +} + +function LazyRefComponent({ promise }: { readonly promise: Promise> }) { + const ref = use(promise) + const [value, setValue] = R.useLazyRefState(ref) + + return ( + + ) +} diff --git a/packages/extension-lazyref/src/index.ts b/packages/extension-lazyref/src/index.ts index 301509a..42728c5 100644 --- a/packages/extension-lazyref/src/index.ts +++ b/packages/extension-lazyref/src/index.ts @@ -1,10 +1,10 @@ import * as LazyRef from "@typed/lazy-ref" import { Effect, Stream } from "effect" import * as React from "react" -import { ReffuseExtension, ReffuseHelpers, SetStateAction } from "reffuse" +import { ReffuseExtension, type ReffuseHelpers, SetStateAction } from "reffuse" -export const withLazyRef = ReffuseExtension.make(() => ({ +export const LazyRefExtension = ReffuseExtension.make(() => ({ useLazyRefState( this: ReffuseHelpers.ReffuseHelpers, ref: LazyRef.LazyRef, diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index 0721298..87d13e4 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,10 +1,12 @@ import type * as ReffuseContext from "./ReffuseContext.js" +import type * as ReffuseExtension from "./ReffuseExtension.js" import * as ReffuseHelpers from "./ReffuseHelpers.js" import type { Merge, StaticType } from "./types.js" export class Reffuse extends ReffuseHelpers.make() {} + export const withContexts = >( ...contexts: [...{ [K in keyof R2]: ReffuseContext.ReffuseContext }] ) => @@ -27,3 +29,19 @@ export const withContexts = >( ) => class extends self { static readonly contexts = [...self.contexts, ...contexts] } as any + + +export const withExtension = (extension: ReffuseExtension.ReffuseExtension) => + < + BaseClass extends ReffuseHelpers.ReffuseHelpersClass, + R + >( + self: BaseClass & ReffuseHelpers.ReffuseHelpersClass + ): ( + { new(): Merge, A> } & + StaticType + ) => { + const class_ = class extends self {} + Object.assign(class_.prototype, extension()) + return class_ as any + } diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index c914a61..e7e723a 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -3,7 +3,6 @@ import * as React from "react" import * as ReffuseRuntime from "./ReffuseRuntime.js" -// TODO: merge this with the Provider, just like React 19 contexts export class ReffuseContext { readonly Context = React.createContext>(null!) @@ -11,7 +10,7 @@ export class ReffuseContext { constructor() { // TODO: scope the layer creation - this.Provider = (props) => { + this.Provider = props => { const runtime = ReffuseRuntime.useRuntime() const value = React.useMemo(() => Effect.context().pipe( diff --git a/packages/reffuse/src/ReffuseExtension.ts b/packages/reffuse/src/ReffuseExtension.ts index ce1fdea..3dda6c2 100644 --- a/packages/reffuse/src/ReffuseExtension.ts +++ b/packages/reffuse/src/ReffuseExtension.ts @@ -1,18 +1,7 @@ -import type * as ReffuseHelpers from "./ReffuseHelpers.js" -import type { Merge, StaticType } from "./types.js" +export interface ReffuseExtension { + (): A + readonly Type: A +} - -export const make = (extension: () => Ext) => - < - BaseClass extends ReffuseHelpers.ReffuseHelpersClass, - R - >( - self: BaseClass & ReffuseHelpers.ReffuseHelpersClass - ): ( - { new(): Merge, Ext> } & - StaticType - ) => { - const class_ = class extends self {} - Object.assign(class_.prototype, extension()) - return class_ as any - } +export const make = (extension: () => A): ReffuseExtension => + extension as ReffuseExtension -- 2.49.1 From 8e1f0a27cfbd08a5259ca2cc8a6aa693546b630f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 13:45:09 +0100 Subject: [PATCH 039/101] Lockfile --- bun.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/bun.lock b/bun.lock index 5743f6a..f832058 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "@effect/platform": "^0.77.2", "@effect/platform-browser": "^0.56.2", "@radix-ui/themes": "^3.2.0", + "@reffuse/extension-lazyref": "workspace:*", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", "effect": "^3.13.2", -- 2.49.1 From 44de864713c1c5fef4058436d50aa63e14eaf5eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 14:48:58 +0100 Subject: [PATCH 040/101] API update --- packages/example/src/routes/lazyref.tsx | 2 +- packages/example/src/routes/promise.tsx | 2 +- packages/example/src/routes/tests.tsx | 2 +- packages/example/src/routes/time.tsx | 4 +- packages/example/src/todos/views/VNewTodo.tsx | 2 +- packages/example/src/todos/views/VTodos.tsx | 4 +- packages/extension-lazyref/src/index.ts | 2 +- packages/reffuse/src/ReffuseHelpers.ts | 68 +++++++++---------- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/packages/example/src/routes/lazyref.tsx b/packages/example/src/routes/lazyref.tsx index 586f25c..32d8187 100644 --- a/packages/example/src/routes/lazyref.tsx +++ b/packages/example/src/routes/lazyref.tsx @@ -10,7 +10,7 @@ export const Route = createFileRoute("/lazyref")({ }) function RouteComponent() { - const promise = R.usePromise(LazyRef.of(0)) + const promise = R.usePromise(() => LazyRef.of(0)) return ( Loading...}> diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index 58c1452..09af62a 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -15,7 +15,7 @@ const Result = Schema.Tuple(Schema.String) type Result = typeof Result.Type function RouteComponent() { - const promise = R.usePromise(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + const promise = R.usePromise(() => Effect.addFinalizer(() => Console.log("Cleanup")).pipe( Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index 82b6919..ab6e89a 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -14,7 +14,7 @@ function RouteComponent() { // ), []) // console.log(value) - R.useFork(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + R.useFork(() => Effect.addFinalizer(() => Console.log("cleanup")).pipe( Effect.andThen(Console.log("ouient")), Effect.delay("1 second"), )) diff --git a/packages/example/src/routes/time.tsx b/packages/example/src/routes/time.tsx index 7332f6b..f99f979 100644 --- a/packages/example/src/routes/time.tsx +++ b/packages/example/src/routes/time.tsx @@ -15,9 +15,9 @@ export const Route = createFileRoute("/time")({ function Time() { - const timeRef = R.useMemo(DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make))) + const timeRef = R.useMemo(() => DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make))) - R.useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + R.useFork(() => Effect.addFinalizer(() => Console.log("Cleanup")).pipe( Effect.andThen(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v))) ), [timeRef]) diff --git a/packages/example/src/todos/views/VNewTodo.tsx b/packages/example/src/todos/views/VNewTodo.tsx index ccb4346..2328006 100644 --- a/packages/example/src/todos/views/VNewTodo.tsx +++ b/packages/example/src/todos/views/VNewTodo.tsx @@ -18,7 +18,7 @@ export function VNewTodo() { const runSync = R.useRunSync() - const todoRef = R.useMemo(createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make))) + const todoRef = R.useMemo(() => createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make))) const [todo, setTodo] = R.useRefState(todoRef) diff --git a/packages/example/src/todos/views/VTodos.tsx b/packages/example/src/todos/views/VTodos.tsx index c747afa..83485b0 100644 --- a/packages/example/src/todos/views/VTodos.tsx +++ b/packages/example/src/todos/views/VTodos.tsx @@ -9,13 +9,13 @@ import { VTodo } from "./VTodo" export function VTodos() { // Sync changes to the todos with the local storage - R.useFork(TodosState.TodosState.pipe( + R.useFork(() => TodosState.TodosState.pipe( Effect.flatMap(state => Stream.runForEach(state.todos.changes, () => state.saveToLocalStorage) ) )) - const todosRef = R.useMemo(TodosState.TodosState.pipe(Effect.map(state => state.todos))) + const todosRef = R.useMemo(() => TodosState.TodosState.pipe(Effect.map(state => state.todos))) const [todos] = R.useRefState(todosRef) diff --git a/packages/extension-lazyref/src/index.ts b/packages/extension-lazyref/src/index.ts index 42728c5..e5fbb02 100644 --- a/packages/extension-lazyref/src/index.ts +++ b/packages/extension-lazyref/src/index.ts @@ -14,7 +14,7 @@ export const LazyRefExtension = ReffuseExtension.make(() => ({ const initialState = React.useMemo(() => runSync(ref), []) const [reactStateValue, setReactStateValue] = React.useState(initialState) - this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + this.useFork(() => Stream.runForEach(ref.changes, v => Effect.sync(() => setReactStateValue(v) )), [ref]) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 1605791..08a8ebc 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -24,52 +24,50 @@ export abstract class ReffuseHelpers { } - useRunSync(this: ReffuseHelpers) { + useRunSync(this: ReffuseHelpers): (effect: Effect.Effect) => A { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() - return React.useCallback(( - effect: Effect.Effect - ): A => effect.pipe( + return React.useCallback(effect => effect.pipe( Effect.provide(context), Runtime.runSync(runtime), ), [runtime, context]) } - useRunPromise(this: ReffuseHelpers) { + useRunPromise(this: ReffuseHelpers): ( + effect: Effect.Effect, + options?: { readonly signal?: AbortSignal }, + ) => Promise { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() - return React.useCallback(( - effect: Effect.Effect, - options?: { readonly signal?: AbortSignal }, - ): Promise => effect.pipe( + return React.useCallback((effect, options) => effect.pipe( Effect.provide(context), effect => Runtime.runPromise(runtime)(effect, options), ), [runtime, context]) } - useRunFork(this: ReffuseHelpers) { + useRunFork(this: ReffuseHelpers): ( + effect: Effect.Effect, + options?: Runtime.RunForkOptions, + ) => Fiber.RuntimeFiber { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() - return React.useCallback(( - effect: Effect.Effect, - options?: Runtime.RunForkOptions, - ): Fiber.RuntimeFiber => effect.pipe( + return React.useCallback((effect, options) => effect.pipe( Effect.provide(context), effect => Runtime.runFork(runtime)(effect, options), ), [runtime, context]) } - useRunCallback(this: ReffuseHelpers) { + useRunCallback(this: ReffuseHelpers): ( + effect: Effect.Effect, + options?: Runtime.RunCallbackOptions, + ) => Runtime.Cancel { const runtime = ReffuseRuntime.useRuntime() const context = this.useContext() - return React.useCallback(( - effect: Effect.Effect, - options?: Runtime.RunCallbackOptions, - ): Runtime.Cancel => effect.pipe( + return React.useCallback((effect, options) => effect.pipe( Effect.provide(context), effect => Runtime.runCallback(runtime)(effect, options), ), [runtime, context]) @@ -87,13 +85,13 @@ export abstract class ReffuseHelpers { */ useMemo( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: RenderOptions, ): A { const runSync = this.useRunSync() - return React.useMemo(() => runSync(effect), [ + return React.useMemo(() => runSync(effect()), [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], ...(deps ?? []), ]) @@ -101,7 +99,7 @@ export abstract class ReffuseHelpers { useMemoScoped( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, ): A { @@ -109,7 +107,7 @@ export abstract class ReffuseHelpers { // Calculate an initial version of the value so that it can be accessed during the first render const [initialScope, initialValue] = React.useMemo(() => Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect.pipe( + Effect.flatMap(scope => effect().pipe( Effect.provideService(Scope.Scope, scope), Effect.map(value => [scope, value] as const), )), @@ -130,7 +128,7 @@ export abstract class ReffuseHelpers { const [scope, value] = closeInitialScopeIfNeeded.pipe( Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.flatMap(scope => effect.pipe( + Effect.flatMap(scope => effect().pipe( Effect.provideService(Scope.Scope, scope), Effect.map(value => [scope, value] as const), )) @@ -177,15 +175,15 @@ export abstract class ReffuseHelpers { */ useEffect( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, ): void { const runSync = this.useRunSync() - return React.useEffect(() => { + React.useEffect(() => { const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), + Effect.tap(scope => Effect.provideService(effect(), Scope.Scope, scope)), runSync, ) @@ -225,7 +223,7 @@ export abstract class ReffuseHelpers { */ useLayoutEffect( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: RenderOptions & ScopeOptions, ): void { @@ -233,7 +231,7 @@ export abstract class ReffuseHelpers { return React.useLayoutEffect(() => { const scope = Scope.make(options?.finalizerExecutionStrategy).pipe( - Effect.tap(scope => Effect.provideService(effect, Scope.Scope, scope)), + Effect.tap(scope => Effect.provideService(effect(), Scope.Scope, scope)), runSync, ) @@ -273,7 +271,7 @@ export abstract class ReffuseHelpers { */ useFork( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: Runtime.RunForkOptions & RenderOptions & ScopeOptions, ): void { @@ -285,7 +283,7 @@ export abstract class ReffuseHelpers { ? Scope.fork(options.scope, options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential) : Scope.make(options?.finalizerExecutionStrategy) ) - runFork(Effect.provideService(effect, Scope.Scope, scope), { ...options, scope }) + runFork(Effect.provideService(effect(), Scope.Scope, scope), { ...options, scope }) return () => { runFork(Scope.close(scope, Exit.void)) } }, [ @@ -296,7 +294,7 @@ export abstract class ReffuseHelpers { usePromise( this: ReffuseHelpers, - effect: Effect.Effect, + effect: () => Effect.Effect, deps?: React.DependencyList, options?: { readonly signal?: AbortSignal } & Runtime.RunForkOptions & RenderOptions & ScopeOptions, ): Promise { @@ -318,7 +316,7 @@ export abstract class ReffuseHelpers { if (options?.signal) options.signal.addEventListener("abort", cleanup) - effect.pipe( + effect().pipe( Effect.provideService(Scope.Scope, scope), Effect.match({ onSuccess: resolve, @@ -347,7 +345,7 @@ export abstract class ReffuseHelpers { value: A, ): SubscriptionRef.SubscriptionRef { return this.useMemo( - SubscriptionRef.make(value), + () => SubscriptionRef.make(value), [], { doNotReExecuteOnRuntimeOrContextChange: true }, // Do not recreate the ref when the context changes ) @@ -369,7 +367,7 @@ export abstract class ReffuseHelpers { const initialState = React.useMemo(() => runSync(ref), []) const [reactStateValue, setReactStateValue] = React.useState(initialState) - this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + this.useFork(() => Stream.runForEach(ref.changes, v => Effect.sync(() => setReactStateValue(v) )), [ref]) -- 2.49.1 From 523d835d00c238d410c300cb5fa988bc44d31a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 17:14:07 +0100 Subject: [PATCH 041/101] Fix --- packages/reffuse/src/ReffuseHelpers.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 08a8ebc..1aa5164 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -160,7 +160,7 @@ export abstract class ReffuseHelpers { * * ### Example * ``` - * useEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * useEffect(() => Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( * Effect.flatMap(() => Console.log("Component mounted")) * )) * ``` @@ -170,7 +170,7 @@ export abstract class ReffuseHelpers { * React.useEffect(() => { * console.log("Component mounted") * return () => { console.log("Component unmounted") } - * }) + * }, []) * ``` */ useEffect( @@ -208,7 +208,7 @@ export abstract class ReffuseHelpers { * * ### Example * ``` - * useLayoutEffect(Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( + * useLayoutEffect(() => Effect.addFinalizer(() => Console.log("Component unmounted")).pipe( * Effect.flatMap(() => Console.log("Component mounted")) * )) * ``` @@ -218,7 +218,7 @@ export abstract class ReffuseHelpers { * React.useLayoutEffect(() => { * console.log("Component mounted") * return () => { console.log("Component unmounted") } - * }) + * }, []) * ``` */ useLayoutEffect( @@ -257,7 +257,7 @@ export abstract class ReffuseHelpers { * ``` * const timeRef = useRefFromEffect(DateTime.now) * - * useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( + * useFork(() => Effect.addFinalizer(() => Console.log("Cleanup")).pipe( * Effect.map(() => Stream.repeatEffectWithSchedule( * DateTime.now, * Schedule.intersect(Schedule.forever, Schedule.spaced("1 second")), -- 2.49.1 From 8244c34d2a87df8cc71f44b9edd9de1040fc8c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 18:29:00 +0100 Subject: [PATCH 042/101] Callback helpers --- packages/reffuse/src/ReffuseHelpers.ts | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 1aa5164..ef94f2d 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -73,7 +73,6 @@ export abstract class ReffuseHelpers { ), [runtime, context]) } - /** * Reffuse equivalent to `React.useMemo`. * @@ -339,6 +338,33 @@ export abstract class ReffuseHelpers { return value } + useCallbackSync( + this: ReffuseHelpers, + callback: (...args: Args) => Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions, + ): (...args: Args) => A { + const runSync = this.useRunSync() + + return React.useCallback((...args) => runSync(callback(...args)), [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + } + + useCallbackPromise( + this: ReffuseHelpers, + callback: (...args: Args) => Effect.Effect, + deps?: React.DependencyList, + options?: { readonly signal?: AbortSignal } & RenderOptions, + ): (...args: Args) => Promise { + const runPromise = this.useRunPromise() + + return React.useCallback((...args) => runPromise(callback(...args), options), [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], + ...(deps ?? []), + ]) + } useRef( this: ReffuseHelpers, -- 2.49.1 From 618cee4028daf8849e8729680427656b8c322741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 18:39:19 +0100 Subject: [PATCH 043/101] Callback tests --- packages/example/src/routes/tests.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index ab6e89a..bb58968 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -1,4 +1,5 @@ import { R } from "@/reffuse" +import { Button } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import { Console, Effect } from "effect" @@ -19,6 +20,12 @@ function RouteComponent() { Effect.delay("1 second"), )) + const logValue = R.useCallbackSync(Effect.fn(function*(value: string) { + yield* Effect.log(value) + })) - return
Hello "/tests"!
+ + return ( + + ) } -- 2.49.1 From af077d34aa304ffbab8f06a834588fda43f86856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 22:07:18 +0100 Subject: [PATCH 044/101] Turbo setup --- .gitignore | 1 + bun.lock | 18 +++++++++++++++++- package.json | 6 +++++- turbo.json | 14 ++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 turbo.json diff --git a/.gitignore b/.gitignore index ceaea36..2519628 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,4 @@ dist .yarn/install-state.gz .pnp.* +.turbo diff --git a/bun.lock b/bun.lock index f832058..74b3dd4 100644 --- a/bun.lock +++ b/bun.lock @@ -2,9 +2,11 @@ "lockfileVersion": 1, "workspaces": { "": { + "name": "@reffuse/monorepo", "devDependencies": { "npm-check-updates": "^17.1.14", "npm-sort": "^0.0.4", + "turbo": "^2.4.4", "typescript": "^5.7.3", }, }, @@ -678,7 +680,7 @@ "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="], @@ -710,6 +712,20 @@ "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], + "turbo": ["turbo@2.4.4", "", { "optionalDependencies": { "turbo-darwin-64": "2.4.4", "turbo-darwin-arm64": "2.4.4", "turbo-linux-64": "2.4.4", "turbo-linux-arm64": "2.4.4", "turbo-windows-64": "2.4.4", "turbo-windows-arm64": "2.4.4" }, "bin": { "turbo": "bin/turbo" } }, "sha512-N9FDOVaY3yz0YCOhYIgOGYad7+m2ptvinXygw27WPLQvcZDl3+0Sa77KGVlLSiuPDChOUEnTKE9VJwLSi9BPGQ=="], + + "turbo-darwin-64": ["turbo-darwin-64@2.4.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-5kPvRkLAfmWI0MH96D+/THnDMGXlFNmjeqNRj5grLKiry+M9pKj3pRuScddAXPdlxjO5Ptz06UNaOQrrYGTx1g=="], + + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.4.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/gtHPqbGQXDFhrmy+Q/MFW2HUTUlThJ97WLLSe4bxkDrKHecDYhAjbZ4rN3MM93RV9STQb3Tqy4pZBtsd4DfCw=="], + + "turbo-linux-64": ["turbo-linux-64@2.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-SR0gri4k0bda56hw5u9VgDXLKb1Q+jrw4lM7WAhnNdXvVoep4d6LmnzgMHQQR12Wxl3KyWPbkz9d1whL6NTm2Q=="], + + "turbo-linux-arm64": ["turbo-linux-arm64@2.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-COXXwzRd3vslQIfJhXUklgEqlwq35uFUZ7hnN+AUyXx7hUOLIiD5NblL+ETrHnhY4TzWszrbwUMfe2BYWtaPQg=="], + + "turbo-windows-64": ["turbo-windows-64@2.4.4", "", { "os": "win32", "cpu": "x64" }, "sha512-PV9rYNouGz4Ff3fd6sIfQy5L7HT9a4fcZoEv8PKRavU9O75G7PoDtm8scpHU10QnK0QQNLbE9qNxOAeRvF0fJg=="], + + "turbo-windows-arm64": ["turbo-windows-arm64@2.4.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-403sqp9t5sx6YGEC32IfZTVWkRAixOQomGYB8kEc6ZD+//LirSxzeCHCnM8EmSXw7l57U1G+Fb0kxgTcKPU/Lg=="], + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], "type-fest": ["type-fest@4.35.0", "", {}, "sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A=="], diff --git a/package.json b/package.json index 692bb61..7851115 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { + "name": "@reffuse/monorepo", + "packageManager": "bun@1.2.2", "private": true, "workspaces": [ "./packages/*" ], "scripts": { - "lint:tsc": "bun run --filter '*' lint:tsc", + "build": "turbo build --filter=!@reffuse/example", + "lint:tsc": "turbo lint:tsc", "clean:cache": "rm -f tsconfig.tsbuildinfo", "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" @@ -12,6 +15,7 @@ "devDependencies": { "npm-check-updates": "^17.1.14", "npm-sort": "^0.0.4", + "turbo": "^2.4.4", "typescript": "^5.7.3" } } diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..a059c7b --- /dev/null +++ b/turbo.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "dependsOn": ["^build"], + "inputs": ["./src/**"], + "outputs": ["./dist/**"] + }, + "dev": { + "persistent": true, + "cache": false + } + } +} -- 2.49.1 From 8d276d2fbf76ef7d83bec98d839f5877b4251a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 22:16:53 +0100 Subject: [PATCH 045/101] Dependencies --- bun.lock | 3 +++ packages/extension-lazyref/package.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/bun.lock b/bun.lock index 74b3dd4..14fcfe5 100644 --- a/bun.lock +++ b/bun.lock @@ -47,6 +47,9 @@ "packages/extension-lazyref": { "name": "@reffuse/extension-lazyref", "version": "0.1.0", + "devDependencies": { + "reffuse": "workspace:*", + }, "peerDependencies": { "@typed/lazy-ref": "^0.3.3", "@types/react": "^19.0.0", diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index 8ca9de8..bb5f144 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -28,6 +28,9 @@ "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" }, + "devDependencies": { + "reffuse": "workspace:*" + }, "peerDependencies": { "@typed/lazy-ref": "^0.3.3", "@types/react": "^19.0.0", -- 2.49.1 From 02da3df8eb76d16b1c6395ad8ec469a691115cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 22:45:55 +0100 Subject: [PATCH 046/101] CI fix --- .gitea/workflows/lint.yaml | 4 ++-- .gitea/workflows/publish.yaml | 8 ++------ .gitea/workflows/test-build.yaml | 8 ++------ package.json | 2 ++ packages/extension-lazyref/package.json | 2 ++ packages/reffuse/package.json | 2 ++ turbo.json | 6 ++++++ 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/lint.yaml b/.gitea/workflows/lint.yaml index 7efb5a0..d96555a 100644 --- a/.gitea/workflows/lint.yaml +++ b/.gitea/workflows/lint.yaml @@ -12,5 +12,5 @@ jobs: uses: actions/checkout@v4 - name: Install dependencies run: bun install --frozen-lockfile - - name: Lint TypeScript - run: bun run lint:tsc + - name: Build + run: bun run build diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index 075a2c3..fa80a71 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -21,12 +21,8 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - name: Build - run: | - cd packages/reffuse - bun run build + run: bun run build - name: Publish - run: | - cd packages/reffuse - npm publish --access public + run: bun run publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitea/workflows/test-build.yaml b/.gitea/workflows/test-build.yaml index ee239a7..bf2f832 100644 --- a/.gitea/workflows/test-build.yaml +++ b/.gitea/workflows/test-build.yaml @@ -18,10 +18,6 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - name: Build - run: | - cd packages/reffuse - bun run build + run: bun run build - name: Pack - run: | - cd packages/reffuse - npm pack --dry-run + run: bun run pack diff --git a/package.json b/package.json index 7851115..06e0721 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "scripts": { "build": "turbo build --filter=!@reffuse/example", "lint:tsc": "turbo lint:tsc", + "pack": "turbo pack --filter=!@reffuse/example", + "publish": "turbo publish --filter=!@reffuse/example", "clean:cache": "rm -f tsconfig.tsbuildinfo", "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index bb5f144..8c66625 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -24,6 +24,8 @@ "scripts": { "build": "tsc", "lint:tsc": "tsc --noEmit", + "pack": "npm pack", + "publish": "npm publish --access public", "clean:cache": "rm -f tsconfig.tsbuildinfo", "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index 5082340..e898ed0 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -24,6 +24,8 @@ "scripts": { "build": "tsc", "lint:tsc": "tsc --noEmit", + "pack": "npm pack", + "publish": "npm publish --access public", "clean:cache": "rm -f tsconfig.tsbuildinfo", "clean:dist": "rm -rf dist", "clean:node": "rm -rf node_modules" diff --git a/turbo.json b/turbo.json index a059c7b..d40bdac 100644 --- a/turbo.json +++ b/turbo.json @@ -6,6 +6,12 @@ "inputs": ["./src/**"], "outputs": ["./dist/**"] }, + "pack": { + "dependsOn": ["^pack"] + }, + "publish": { + "dependsOn": ["^publish"] + }, "dev": { "persistent": true, "cache": false -- 2.49.1 From 47aa1304863aa28b58b9163ff213c96e7ab6a5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 22:53:07 +0100 Subject: [PATCH 047/101] CI fix --- turbo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/turbo.json b/turbo.json index d40bdac..c4d0706 100644 --- a/turbo.json +++ b/turbo.json @@ -7,10 +7,10 @@ "outputs": ["./dist/**"] }, "pack": { - "dependsOn": ["^pack"] + "dependsOn": ["pack"] }, "publish": { - "dependsOn": ["^publish"] + "dependsOn": ["publish"] }, "dev": { "persistent": true, -- 2.49.1 From 3b4eb750eda5e622bf7cf0b266a757cb25cc53fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 22:55:45 +0100 Subject: [PATCH 048/101] Version bump --- packages/extension-lazyref/package.json | 2 +- packages/reffuse/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index 8c66625..055bae6 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -38,6 +38,6 @@ "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", - "reffuse": "^0.1.1" + "reffuse": "^0.1.2" } } diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index e898ed0..842c01d 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -1,6 +1,6 @@ { "name": "reffuse", - "version": "0.1.1", + "version": "0.1.2", "type": "module", "files": [ "./README.md", -- 2.49.1 From ea768218a0ce7bc6c89a6dad676fbd0998cc8cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 23:11:58 +0100 Subject: [PATCH 049/101] Deps API change --- packages/example/src/routes/lazyref.tsx | 2 +- packages/example/src/routes/promise.tsx | 2 +- packages/example/src/routes/tests.tsx | 4 +-- packages/example/src/routes/time.tsx | 2 +- packages/example/src/todos/views/VNewTodo.tsx | 2 +- packages/example/src/todos/views/VTodos.tsx | 4 +-- packages/reffuse/src/ReffuseHelpers.ts | 36 +++++++++---------- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/example/src/routes/lazyref.tsx b/packages/example/src/routes/lazyref.tsx index 32d8187..67657a7 100644 --- a/packages/example/src/routes/lazyref.tsx +++ b/packages/example/src/routes/lazyref.tsx @@ -10,7 +10,7 @@ export const Route = createFileRoute("/lazyref")({ }) function RouteComponent() { - const promise = R.usePromise(() => LazyRef.of(0)) + const promise = R.usePromise(() => LazyRef.of(0), []) return ( Loading...}> diff --git a/packages/example/src/routes/promise.tsx b/packages/example/src/routes/promise.tsx index 09af62a..4b197cf 100644 --- a/packages/example/src/routes/promise.tsx +++ b/packages/example/src/routes/promise.tsx @@ -20,7 +20,7 @@ function RouteComponent() { HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), - )) + ), []) return ( Loading...}> diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index bb58968..93e791e 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -18,11 +18,11 @@ function RouteComponent() { R.useFork(() => Effect.addFinalizer(() => Console.log("cleanup")).pipe( Effect.andThen(Console.log("ouient")), Effect.delay("1 second"), - )) + ), []) const logValue = R.useCallbackSync(Effect.fn(function*(value: string) { yield* Effect.log(value) - })) + }), []) return ( diff --git a/packages/example/src/routes/time.tsx b/packages/example/src/routes/time.tsx index f99f979..99e7e39 100644 --- a/packages/example/src/routes/time.tsx +++ b/packages/example/src/routes/time.tsx @@ -15,7 +15,7 @@ export const Route = createFileRoute("/time")({ function Time() { - const timeRef = R.useMemo(() => DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make))) + const timeRef = R.useMemo(() => DateTime.now.pipe(Effect.flatMap(SubscriptionRef.make)), []) R.useFork(() => Effect.addFinalizer(() => Console.log("Cleanup")).pipe( Effect.andThen(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v))) diff --git a/packages/example/src/todos/views/VNewTodo.tsx b/packages/example/src/todos/views/VNewTodo.tsx index 2328006..67e4088 100644 --- a/packages/example/src/todos/views/VNewTodo.tsx +++ b/packages/example/src/todos/views/VNewTodo.tsx @@ -18,7 +18,7 @@ export function VNewTodo() { const runSync = R.useRunSync() - const todoRef = R.useMemo(() => createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make))) + const todoRef = R.useMemo(() => createEmptyTodo.pipe(Effect.flatMap(SubscriptionRef.make)), []) const [todo, setTodo] = R.useRefState(todoRef) diff --git a/packages/example/src/todos/views/VTodos.tsx b/packages/example/src/todos/views/VTodos.tsx index 83485b0..27229aa 100644 --- a/packages/example/src/todos/views/VTodos.tsx +++ b/packages/example/src/todos/views/VTodos.tsx @@ -13,9 +13,9 @@ export function VTodos() { Effect.flatMap(state => Stream.runForEach(state.todos.changes, () => state.saveToLocalStorage) ) - )) + ), []) - const todosRef = R.useMemo(() => TodosState.TodosState.pipe(Effect.map(state => state.todos))) + const todosRef = R.useMemo(() => TodosState.TodosState.pipe(Effect.map(state => state.todos)), []) const [todos] = R.useRefState(todosRef) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index ef94f2d..cd48191 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -85,21 +85,21 @@ export abstract class ReffuseHelpers { useMemo( this: ReffuseHelpers, effect: () => Effect.Effect, - deps?: React.DependencyList, + deps: React.DependencyList, options?: RenderOptions, ): A { const runSync = this.useRunSync() return React.useMemo(() => runSync(effect()), [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), + ...deps, ]) } useMemoScoped( this: ReffuseHelpers, effect: () => Effect.Effect, - deps?: React.DependencyList, + deps: React.DependencyList, options?: RenderOptions & ScopeOptions, ): A { const runSync = this.useRunSync() @@ -140,7 +140,7 @@ export abstract class ReffuseHelpers { return () => { runSync(Scope.close(scope, Exit.void)) } }, [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), + ...deps, ]) return value @@ -187,9 +187,9 @@ export abstract class ReffuseHelpers { ) return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ + }, deps && [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), + ...deps, ]) } @@ -235,9 +235,9 @@ export abstract class ReffuseHelpers { ) return () => { runSync(Scope.close(scope, Exit.void)) } - }, [ + }, deps && [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), + ...deps, ]) } @@ -285,9 +285,9 @@ export abstract class ReffuseHelpers { runFork(Effect.provideService(effect(), Scope.Scope, scope), { ...options, scope }) return () => { runFork(Scope.close(scope, Exit.void)) } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], - ...(deps ?? []), + }, deps && [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...deps, ]) } @@ -330,9 +330,9 @@ export abstract class ReffuseHelpers { cleanup() } - }, [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runFork], - ...(deps ?? []), + }, deps && [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...deps, ]) return value @@ -341,28 +341,28 @@ export abstract class ReffuseHelpers { useCallbackSync( this: ReffuseHelpers, callback: (...args: Args) => Effect.Effect, - deps?: React.DependencyList, + deps: React.DependencyList, options?: RenderOptions, ): (...args: Args) => A { const runSync = this.useRunSync() return React.useCallback((...args) => runSync(callback(...args)), [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], - ...(deps ?? []), + ...deps, ]) } useCallbackPromise( this: ReffuseHelpers, callback: (...args: Args) => Effect.Effect, - deps?: React.DependencyList, + deps: React.DependencyList, options?: { readonly signal?: AbortSignal } & RenderOptions, ): (...args: Args) => Promise
{ const runPromise = this.useRunPromise() return React.useCallback((...args) => runPromise(callback(...args), options), [ ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], - ...(deps ?? []), + ...deps, ]) } -- 2.49.1 From 5f60d03d83018cddb1ab725492796c0be2730b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 25 Feb 2025 23:19:44 +0100 Subject: [PATCH 050/101] Fix --- packages/example/src/todos/views/VNewTodo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/example/src/todos/views/VNewTodo.tsx b/packages/example/src/todos/views/VNewTodo.tsx index 67e4088..4d183b5 100644 --- a/packages/example/src/todos/views/VNewTodo.tsx +++ b/packages/example/src/todos/views/VNewTodo.tsx @@ -37,7 +37,7 @@ export function VNewTodo() { + ) } diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index c528f62..c5e7731 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,12 +1,11 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Option, Ref } from "effect" +import { Effect, Fiber, Option, Ref, Scope } from "effect" import * as React from "react" -import { useState } from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" export interface UseQueryProps { - effect: () => Effect.Effect + effect: () => Effect.Effect readonly deps: React.DependencyList } @@ -22,7 +21,7 @@ export const QueryExtension = ReffuseExtension.make(() => ({ props: UseQueryProps, ): UseQueryResult { const fiberRef = this.useRef(Option.none>()) - const [state, setState] = useState(AsyncData.noData()) + const stateRef = this.useRef(AsyncData.noData()) const interruptRunningQuery = React.useMemo(() => fiberRef.pipe( Effect.flatMap(Option.match({ @@ -32,32 +31,35 @@ export const QueryExtension = ReffuseExtension.make(() => ({ ), []) const runQuery = React.useMemo(() => props.effect().pipe( - Effect.matchCause({ - onSuccess: v => setState(AsyncData.success(v)), - onFailure: c => setState(AsyncData.failure(c)), + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), }) ), props.deps) const refresh = React.useMemo(() => interruptRunningQuery.pipe( - Effect.andThen(Effect.sync(() => setState(prev => + Effect.andThen(Ref.update(stateRef, prev => AsyncData.isSuccess(prev) || AsyncData.isFailure(prev) ? AsyncData.refreshing(prev) : AsyncData.loading() - ))), + )), Effect.andThen(runQuery), + Effect.scoped, Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), ), [runQuery]) this.useEffect(() => interruptRunningQuery.pipe( - Effect.andThen(Effect.sync(() => setState(AsyncData.loading()))), + Effect.andThen(Ref.set(stateRef, AsyncData.loading())), Effect.andThen(runQuery), + Effect.scoped, Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), ), [runQuery]) + const [state] = this.useRefState(stateRef) return { state, refresh } } })) -- 2.49.1 From f76b3f333a0b5637db865dcb39cd97e55756a372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 28 Feb 2025 02:13:23 +0100 Subject: [PATCH 064/101] Query work --- packages/example/src/routes/query.tsx | 9 ++++++--- packages/extension-query/src/index.ts | 26 ++++++++++++++------------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index cfca90c..c8f1374 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -16,7 +16,7 @@ const Result = Schema.Tuple(Schema.String) function RouteComponent() { const runSync = R.useRunSync() - const { state, refresh } = R.useQuery({ + const { state, triggerRefresh } = R.useQuery({ effect: () => HttpClient.get("https://www.uuidtools.com/api/generate/v4").pipe( HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), @@ -26,11 +26,14 @@ function RouteComponent() { deps: [], }) + const [queryState] = R.useRefState(state) + + return ( - {AsyncData.match(state, { + {AsyncData.match(queryState, { NoData: () => "No data yet", Loading: () => "Loading...", Success: (value, { isRefreshing, isOptimistic }) => @@ -40,7 +43,7 @@ function RouteComponent() { })} - + ) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index c5e7731..c5694cd 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Option, Ref, Scope } from "effect" +import { Effect, Fiber, Option, Ref, Scope, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" @@ -9,9 +9,9 @@ export interface UseQueryProps { readonly deps: React.DependencyList } -export interface UseQueryResult { - readonly state: AsyncData.AsyncData - readonly refresh: Effect.Effect +export interface UseQueryResult { + readonly state: SubscriptionRef.SubscriptionRef> + readonly triggerRefresh: Effect.Effect } @@ -19,7 +19,9 @@ export const QueryExtension = ReffuseExtension.make(() => ({ useQuery( this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, - ): UseQueryResult { + ): UseQueryResult { + const context = this.useContext() + const fiberRef = this.useRef(Option.none>()) const stateRef = this.useRef(AsyncData.noData()) @@ -28,27 +30,28 @@ export const QueryExtension = ReffuseExtension.make(() => ({ onSome: Fiber.interrupt, onNone: () => Effect.void, })) - ), []) + ), [fiberRef]) const runQuery = React.useMemo(() => props.effect().pipe( Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), }) - ), props.deps) + ), [...props.deps, stateRef]) - const refresh = React.useMemo(() => interruptRunningQuery.pipe( + const triggerRefresh = React.useMemo(() => interruptRunningQuery.pipe( Effect.andThen(Ref.update(stateRef, prev => AsyncData.isSuccess(prev) || AsyncData.isFailure(prev) ? AsyncData.refreshing(prev) : AsyncData.loading() )), Effect.andThen(runQuery), + Effect.provide(context), Effect.scoped, Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [runQuery]) + ), [interruptRunningQuery, stateRef, runQuery, context, fiberRef]) this.useEffect(() => interruptRunningQuery.pipe( Effect.andThen(Ref.set(stateRef, AsyncData.loading())), @@ -57,9 +60,8 @@ export const QueryExtension = ReffuseExtension.make(() => ({ Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [runQuery]) + ), [stateRef, runQuery, fiberRef]) - const [state] = this.useRefState(stateRef) - return { state, refresh } + return React.useMemo(() => ({ state: stateRef, triggerRefresh }), [stateRef, triggerRefresh]) } })) -- 2.49.1 From 3f2639fda1e5ffa85e09553700571b4dac2d527e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 28 Feb 2025 16:08:08 +0100 Subject: [PATCH 065/101] Query work --- packages/extension-query/src/index.ts | 46 +++++++++++++++------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index c5694cd..eff2bfd 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -15,6 +15,24 @@ export interface UseQueryResult { } +const interruptRunningQuery = (fiberRef: Ref.Ref>>) => fiberRef.pipe( + Effect.flatMap(Option.match({ + onSome: Fiber.interrupt, + onNone: () => Effect.void, + })) +) + +const runQuery = ( + effect: Effect.Effect, + stateRef: Ref.Ref>, +) => effect.pipe( + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }) +) + + export const QueryExtension = ReffuseExtension.make(() => ({ useQuery( this: ReffuseHelpers.ReffuseHelpers, @@ -22,45 +40,31 @@ export const QueryExtension = ReffuseExtension.make(() => ({ ): UseQueryResult { const context = this.useContext() - const fiberRef = this.useRef(Option.none>()) + const fiberRef = this.useRef(Option.none>()) const stateRef = this.useRef(AsyncData.noData()) - const interruptRunningQuery = React.useMemo(() => fiberRef.pipe( - Effect.flatMap(Option.match({ - onSome: Fiber.interrupt, - onNone: () => Effect.void, - })) - ), [fiberRef]) - - const runQuery = React.useMemo(() => props.effect().pipe( - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }) - ), [...props.deps, stateRef]) - - const triggerRefresh = React.useMemo(() => interruptRunningQuery.pipe( + const triggerRefresh = React.useMemo(() => interruptRunningQuery(fiberRef).pipe( Effect.andThen(Ref.update(stateRef, prev => AsyncData.isSuccess(prev) || AsyncData.isFailure(prev) ? AsyncData.refreshing(prev) : AsyncData.loading() )), - Effect.andThen(runQuery), + Effect.andThen(runQuery(props.effect(), stateRef)), Effect.provide(context), Effect.scoped, Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [interruptRunningQuery, stateRef, runQuery, context, fiberRef]) + ), [stateRef, context, fiberRef]) - this.useEffect(() => interruptRunningQuery.pipe( + this.useEffect(() => interruptRunningQuery(fiberRef).pipe( Effect.andThen(Ref.set(stateRef, AsyncData.loading())), - Effect.andThen(runQuery), + Effect.andThen(runQuery(props.effect(), stateRef)), Effect.scoped, Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [stateRef, runQuery, fiberRef]) + ), [stateRef, fiberRef]) return React.useMemo(() => ({ state: stateRef, triggerRefresh }), [stateRef, triggerRefresh]) } -- 2.49.1 From 660f32a1714fa4d258a3bb551df59784e439e6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 28 Feb 2025 17:24:40 +0100 Subject: [PATCH 066/101] Fix --- packages/extension-query/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index eff2bfd..c2731f8 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -64,7 +64,7 @@ export const QueryExtension = ReffuseExtension.make(() => ({ Effect.forkDaemon, Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [stateRef, fiberRef]) + ), [...props.deps, stateRef, fiberRef]) return React.useMemo(() => ({ state: stateRef, triggerRefresh }), [stateRef, triggerRefresh]) } -- 2.49.1 From 2e00db57785870bce1fc364cf91c5421ede8b13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 2 Mar 2025 01:11:18 +0100 Subject: [PATCH 067/101] Query work --- packages/extension-query/src/Query.ts | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 packages/extension-query/src/Query.ts diff --git a/packages/extension-query/src/Query.ts b/packages/extension-query/src/Query.ts new file mode 100644 index 0000000..8098466 --- /dev/null +++ b/packages/extension-query/src/Query.ts @@ -0,0 +1,39 @@ +import { Effect, Fiber, Option, type Ref, type SubscriptionRef } from "effect" +import * as AsyncData from "@typed/async-data" + + +export interface QueryRunner { + readonly stateRef: SubscriptionRef.SubscriptionRef> + readonly fiberRef: SubscriptionRef.SubscriptionRef>> + + readonly interrupt: Effect.Effect + readonly fetch: Effect.Effect + readonly refetch: Effect.Effect +} + + +export class Query { + constructor( + private readonly stateRef: SubscriptionRef.SubscriptionRef>, + private readonly fiberRef: SubscriptionRef.SubscriptionRef>>, + ) {} + + private run(effect: Effect.Effect) { + + } + + // interrupt(): Effect.Effect { + // return this.fiberRef.pipe( + // Effect.flatMap(Option.match({ + // onSome: Fiber.interrupt, + // onNone: () => Effect.void, + // })) + // ) + // } + + + + fetch = Effect.gen(this, function*() { + yield* this.interrupt() + }) +} -- 2.49.1 From 6b0f2f33cbe28c0fed9d76261f2ed23e6912b33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 2 Mar 2025 02:48:19 +0100 Subject: [PATCH 068/101] Query work --- packages/extension-query/src/Query.ts | 46 ++++++++++++--------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/packages/extension-query/src/Query.ts b/packages/extension-query/src/Query.ts index 8098466..0cf4bdf 100644 --- a/packages/extension-query/src/Query.ts +++ b/packages/extension-query/src/Query.ts @@ -1,4 +1,4 @@ -import { Effect, Fiber, Option, type Ref, type SubscriptionRef } from "effect" +import { Effect, Fiber, Option, SubscriptionRef, type Ref } from "effect" import * as AsyncData from "@typed/async-data" @@ -7,33 +7,29 @@ export interface QueryRunner { readonly fiberRef: SubscriptionRef.SubscriptionRef>> readonly interrupt: Effect.Effect - readonly fetch: Effect.Effect - readonly refetch: Effect.Effect + fetch(effect: Effect.Effect): Effect.Effect + // refetch(effect: Effect.Effect): Effect.Effect } +export const make = Effect.fnUntraced(function*(): Effect.Effect> { + const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) + const fiberRef = yield* SubscriptionRef.make(Option.none>()) -export class Query { - constructor( - private readonly stateRef: SubscriptionRef.SubscriptionRef>, - private readonly fiberRef: SubscriptionRef.SubscriptionRef>>, - ) {} + const interrupt = fiberRef.pipe( + Effect.flatMap(Option.match({ + onSome: Fiber.interrupt, + onNone: () => Effect.void, + })) + ) - private run(effect: Effect.Effect) { + const fetch = Effect.fnUntraced(function*(effect: Effect.Effect) { - } - - // interrupt(): Effect.Effect { - // return this.fiberRef.pipe( - // Effect.flatMap(Option.match({ - // onSome: Fiber.interrupt, - // onNone: () => Effect.void, - // })) - // ) - // } - - - - fetch = Effect.gen(this, function*() { - yield* this.interrupt() }) -} + + return { + stateRef, + fiberRef, + interrupt, + fetch, + } +}) -- 2.49.1 From 3fa9b7d82153d041aeb12f93ecc629a573c13d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 2 Mar 2025 20:14:45 +0100 Subject: [PATCH 069/101] Working query --- packages/example/src/routes/query.tsx | 5 +- packages/extension-query/src/Query.ts | 35 ---------- packages/extension-query/src/QueryRunner.ts | 75 +++++++++++++++++++++ packages/extension-query/src/index.ts | 64 +++++------------- 4 files changed, 94 insertions(+), 85 deletions(-) delete mode 100644 packages/extension-query/src/Query.ts create mode 100644 packages/extension-query/src/QueryRunner.ts diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index c8f1374..efa1d87 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -16,12 +16,13 @@ const Result = Schema.Tuple(Schema.String) function RouteComponent() { const runSync = R.useRunSync() - const { state, triggerRefresh } = R.useQuery({ + const { state, refresh } = R.useQuery({ effect: () => HttpClient.get("https://www.uuidtools.com/api/generate/v4").pipe( HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), Effect.delay("500 millis"), + Effect.scoped, ), deps: [], }) @@ -43,7 +44,7 @@ function RouteComponent() { })} - + ) diff --git a/packages/extension-query/src/Query.ts b/packages/extension-query/src/Query.ts deleted file mode 100644 index 0cf4bdf..0000000 --- a/packages/extension-query/src/Query.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Effect, Fiber, Option, SubscriptionRef, type Ref } from "effect" -import * as AsyncData from "@typed/async-data" - - -export interface QueryRunner { - readonly stateRef: SubscriptionRef.SubscriptionRef> - readonly fiberRef: SubscriptionRef.SubscriptionRef>> - - readonly interrupt: Effect.Effect - fetch(effect: Effect.Effect): Effect.Effect - // refetch(effect: Effect.Effect): Effect.Effect -} - -export const make = Effect.fnUntraced(function*(): Effect.Effect> { - const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) - const fiberRef = yield* SubscriptionRef.make(Option.none>()) - - const interrupt = fiberRef.pipe( - Effect.flatMap(Option.match({ - onSome: Fiber.interrupt, - onNone: () => Effect.void, - })) - ) - - const fetch = Effect.fnUntraced(function*(effect: Effect.Effect) { - - }) - - return { - stateRef, - fiberRef, - interrupt, - fetch, - } -}) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts new file mode 100644 index 0000000..ddf931d --- /dev/null +++ b/packages/extension-query/src/QueryRunner.ts @@ -0,0 +1,75 @@ +import * as AsyncData from "@typed/async-data" +import { Effect, Fiber, flow, identity, Option, Ref, SubscriptionRef } from "effect" + + +export interface QueryRunner { + readonly queryRef: SubscriptionRef.SubscriptionRef> + readonly stateRef: SubscriptionRef.SubscriptionRef> + readonly fiberRef: SubscriptionRef.SubscriptionRef>> + + readonly interrupt: Effect.Effect + readonly forkFetch: Effect.Effect + readonly forkRefetch: Effect.Effect +} + + +export const make = ( + query: Effect.Effect +): Effect.Effect, never, R> => Effect.gen(function*() { + const context = yield* Effect.context() + + const queryRef = yield* SubscriptionRef.make(query) + const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) + const fiberRef = yield* SubscriptionRef.make(Option.none>()) + + const interrupt = fiberRef.pipe( + Effect.flatMap(Option.match({ + onSome: flow( + Fiber.interrupt, + Effect.andThen(Ref.set(fiberRef, Option.none())), + ), + onNone: () => Effect.void, + })) + ) + + const forkFetch = interrupt.pipe( + Effect.andThen(Ref.set(stateRef, AsyncData.loading())), + Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }), + Effect.provide(context), + Effect.forkDaemon, + + Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), + ) + + const forkRefetch = interrupt.pipe( + Effect.andThen(Ref.update(stateRef, previous => { + if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) + return AsyncData.refreshing(previous) + if (AsyncData.isRefreshing(previous)) + return AsyncData.refreshing(previous.previous) + return AsyncData.loading() + })), + Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }), + Effect.provide(context), + Effect.forkDaemon, + + Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), + ) + + return { + queryRef, + stateRef, + fiberRef, + interrupt, + forkFetch, + forkRefetch, + } +}) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index c2731f8..05797e8 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,71 +1,39 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Option, Ref, Scope, SubscriptionRef } from "effect" +import { Effect, Ref, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" +import * as QueryRunner from "./QueryRunner.js" export interface UseQueryProps { - effect: () => Effect.Effect + effect: () => Effect.Effect readonly deps: React.DependencyList } export interface UseQueryResult { readonly state: SubscriptionRef.SubscriptionRef> - readonly triggerRefresh: Effect.Effect + readonly refresh: Effect.Effect } -const interruptRunningQuery = (fiberRef: Ref.Ref>>) => fiberRef.pipe( - Effect.flatMap(Option.match({ - onSome: Fiber.interrupt, - onNone: () => Effect.void, - })) -) - -const runQuery = ( - effect: Effect.Effect, - stateRef: Ref.Ref>, -) => effect.pipe( - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }) -) - - export const QueryExtension = ReffuseExtension.make(() => ({ useQuery( this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, ): UseQueryResult { - const context = this.useContext() + const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) - const fiberRef = this.useRef(Option.none>()) - const stateRef = this.useRef(AsyncData.noData()) + this.useFork(() => Effect.addFinalizer(() => runner.interrupt).pipe( + Effect.andThen(Ref.set(runner.queryRef, props.effect())), + Effect.andThen(runner.forkFetch), + ), [runner, ...props.deps]) - const triggerRefresh = React.useMemo(() => interruptRunningQuery(fiberRef).pipe( - Effect.andThen(Ref.update(stateRef, prev => - AsyncData.isSuccess(prev) || AsyncData.isFailure(prev) - ? AsyncData.refreshing(prev) - : AsyncData.loading() - )), - Effect.andThen(runQuery(props.effect(), stateRef)), - Effect.provide(context), - Effect.scoped, - Effect.forkDaemon, - - Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [stateRef, context, fiberRef]) - - this.useEffect(() => interruptRunningQuery(fiberRef).pipe( - Effect.andThen(Ref.set(stateRef, AsyncData.loading())), - Effect.andThen(runQuery(props.effect(), stateRef)), - Effect.scoped, - Effect.forkDaemon, - - Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), - ), [...props.deps, stateRef, fiberRef]) - - return React.useMemo(() => ({ state: stateRef, triggerRefresh }), [stateRef, triggerRefresh]) + return React.useMemo(() => ({ + state: runner.stateRef, + refresh: runner.forkRefetch, + }), [runner]) } })) + + +export * as QueryRunner from "./QueryRunner.js" -- 2.49.1 From 9c96741c8ee97119d897bbe5de7247fa5ca79a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 3 Mar 2025 03:37:39 +0100 Subject: [PATCH 070/101] Fix --- packages/extension-query/src/QueryRunner.ts | 2 ++ packages/extension-query/src/index.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index ddf931d..3bfa162 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -39,6 +39,7 @@ export const make = ( onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), }), + Effect.andThen(Ref.set(fiberRef, Option.none())), Effect.provide(context), Effect.forkDaemon, @@ -58,6 +59,7 @@ export const make = ( onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), }), + Effect.andThen(Ref.set(fiberRef, Option.none())), Effect.provide(context), Effect.forkDaemon, diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index 05797e8..390a9cc 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Ref, SubscriptionRef } from "effect" +import { Console, Effect, Ref, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -23,6 +23,8 @@ export const QueryExtension = ReffuseExtension.make(() => ({ ): UseQueryResult { const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) + this.useFork(() => Stream.runForEach(runner.fiberRef.changes, Console.log), []) + this.useFork(() => Effect.addFinalizer(() => runner.interrupt).pipe( Effect.andThen(Ref.set(runner.queryRef, props.effect())), Effect.andThen(runner.forkFetch), -- 2.49.1 From 40e8bf6a1f0ef8ec3b419b1af5c6725471afc14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 3 Mar 2025 19:42:33 +0100 Subject: [PATCH 071/101] Query work --- packages/example/src/main.tsx | 4 ++-- packages/extension-query/src/QueryRunner.ts | 16 ++++++++++++---- packages/extension-query/src/index.ts | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/example/src/main.tsx b/packages/example/src/main.tsx index 8fe1e6d..fc8645f 100644 --- a/packages/example/src/main.tsx +++ b/packages/example/src/main.tsx @@ -26,11 +26,11 @@ declare module "@tanstack/react-router" { createRoot(document.getElementById("root")!).render( - + // - + // ) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 3bfa162..aa66331 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, flow, identity, Option, Ref, SubscriptionRef } from "effect" +import { Effect, Fiber, identity, Option, Ref, SubscriptionRef } from "effect" export interface QueryRunner { @@ -24,9 +24,17 @@ export const make = ( const interrupt = fiberRef.pipe( Effect.flatMap(Option.match({ - onSome: flow( - Fiber.interrupt, - Effect.andThen(Ref.set(fiberRef, Option.none())), + onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( + Effect.andThen(Fiber.interrupt(fiber)) + ), + onNone: () => Effect.void, + })) + ) + + const forkInterrupt = fiberRef.pipe( + Effect.flatMap(Option.match({ + onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( + Effect.andThen(Fiber.interruptFork(fiber)) ), onNone: () => Effect.void, })) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index 390a9cc..e647a3a 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -25,7 +25,7 @@ export const QueryExtension = ReffuseExtension.make(() => ({ this.useFork(() => Stream.runForEach(runner.fiberRef.changes, Console.log), []) - this.useFork(() => Effect.addFinalizer(() => runner.interrupt).pipe( + this.useEffect(() => Effect.addFinalizer(() => Effect.void).pipe( Effect.andThen(Ref.set(runner.queryRef, props.effect())), Effect.andThen(runner.forkFetch), ), [runner, ...props.deps]) -- 2.49.1 From b2f1626268fbe629b957d68f4b41454ae7ce36f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 01:19:42 +0100 Subject: [PATCH 072/101] Working query --- packages/extension-query/src/QueryRunner.ts | 104 +++++++++++--------- packages/extension-query/src/index.ts | 10 +- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index aa66331..072e816 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -5,11 +5,11 @@ import { Effect, Fiber, identity, Option, Ref, SubscriptionRef } from "effect" export interface QueryRunner { readonly queryRef: SubscriptionRef.SubscriptionRef> readonly stateRef: SubscriptionRef.SubscriptionRef> - readonly fiberRef: SubscriptionRef.SubscriptionRef>> + readonly fiberRef: SubscriptionRef.SubscriptionRef>> - readonly interrupt: Effect.Effect - readonly forkFetch: Effect.Effect - readonly forkRefetch: Effect.Effect + readonly forkInterrupt: Effect.Effect> + readonly forkFetch: Effect.Effect> + readonly forkRefresh: Effect.Effect> } @@ -20,66 +20,80 @@ export const make = ( const queryRef = yield* SubscriptionRef.make(query) const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) - const fiberRef = yield* SubscriptionRef.make(Option.none>()) + const fiberRef = yield* SubscriptionRef.make(Option.none>()) const interrupt = fiberRef.pipe( Effect.flatMap(Option.match({ - onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( - Effect.andThen(Fiber.interrupt(fiber)) - ), + onSome: Fiber.interrupt, onNone: () => Effect.void, })) ) - const forkInterrupt = fiberRef.pipe( - Effect.flatMap(Option.match({ - onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( - Effect.andThen(Fiber.interruptFork(fiber)) - ), - onNone: () => Effect.void, - })) - ) + const forkInterrupt = Effect.forkDaemon(interrupt) const forkFetch = interrupt.pipe( - Effect.andThen(Ref.set(stateRef, AsyncData.loading())), - Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }), - Effect.andThen(Ref.set(fiberRef, Option.none())), - Effect.provide(context), - Effect.forkDaemon, + Effect.andThen( + Effect.addFinalizer(() => Ref.set(fiberRef, Option.none())).pipe( + Effect.andThen(Ref.set(stateRef, AsyncData.loading())), + Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }), - Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), + Effect.provide(context), + Effect.scoped, + Effect.fork, + ) + ), + + Effect.flatMap(fiber => + Ref.set(fiberRef, Option.some(fiber)).pipe( + Effect.andThen(Fiber.join(fiber)) + ) + ), + + Effect.forkDaemon, ) - const forkRefetch = interrupt.pipe( - Effect.andThen(Ref.update(stateRef, previous => { - if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) - return AsyncData.refreshing(previous) - if (AsyncData.isRefreshing(previous)) - return AsyncData.refreshing(previous.previous) - return AsyncData.loading() - })), - Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }), - Effect.andThen(Ref.set(fiberRef, Option.none())), - Effect.provide(context), - Effect.forkDaemon, + const forkRefresh = interrupt.pipe( + Effect.andThen( + Effect.addFinalizer(() => Ref.set(fiberRef, Option.none())).pipe( + Effect.andThen(Ref.update(stateRef, previous => { + if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) + return AsyncData.refreshing(previous) + if (AsyncData.isRefreshing(previous)) + return AsyncData.refreshing(previous.previous) + return AsyncData.loading() + })), + Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }), - Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber))), + Effect.provide(context), + Effect.scoped, + Effect.fork, + ) + ), + + Effect.flatMap(fiber => + Ref.set(fiberRef, Option.some(fiber)).pipe( + Effect.andThen(Fiber.join(fiber)) + ) + ), + + Effect.forkDaemon, ) return { queryRef, stateRef, fiberRef, - interrupt, + + forkInterrupt, forkFetch, - forkRefetch, + forkRefresh, } }) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index e647a3a..76bb022 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Console, Effect, Ref, Stream, SubscriptionRef } from "effect" +import { Effect, Fiber, Ref, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -12,7 +12,7 @@ export interface UseQueryProps { export interface UseQueryResult { readonly state: SubscriptionRef.SubscriptionRef> - readonly refresh: Effect.Effect + readonly refresh: Effect.Effect> } @@ -23,16 +23,14 @@ export const QueryExtension = ReffuseExtension.make(() => ({ ): UseQueryResult { const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) - this.useFork(() => Stream.runForEach(runner.fiberRef.changes, Console.log), []) - - this.useEffect(() => Effect.addFinalizer(() => Effect.void).pipe( + this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( Effect.andThen(Ref.set(runner.queryRef, props.effect())), Effect.andThen(runner.forkFetch), ), [runner, ...props.deps]) return React.useMemo(() => ({ state: runner.stateRef, - refresh: runner.forkRefetch, + refresh: runner.forkRefresh, }), [runner]) } })) -- 2.49.1 From 98091d4598a2fc0fce961f283c1c6a6c3322f299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 01:22:51 +0100 Subject: [PATCH 073/101] Refactoring --- .../extension-query/src/QueryExtension.ts | 36 +++++++++++++++++ packages/extension-query/src/index.ts | 39 +------------------ 2 files changed, 37 insertions(+), 38 deletions(-) create mode 100644 packages/extension-query/src/QueryExtension.ts diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts new file mode 100644 index 0000000..2ee4607 --- /dev/null +++ b/packages/extension-query/src/QueryExtension.ts @@ -0,0 +1,36 @@ +import * as AsyncData from "@typed/async-data" +import { Effect, Fiber, Ref, SubscriptionRef } from "effect" +import * as React from "react" +import { ReffuseExtension, type ReffuseHelpers } from "reffuse" +import * as QueryRunner from "./QueryRunner.js" + + +export interface UseQueryProps { + effect: () => Effect.Effect + readonly deps: React.DependencyList +} + +export interface UseQueryResult { + readonly state: SubscriptionRef.SubscriptionRef> + readonly refresh: Effect.Effect> +} + + +export const QueryExtension = ReffuseExtension.make(() => ({ + useQuery( + this: ReffuseHelpers.ReffuseHelpers, + props: UseQueryProps, + ): UseQueryResult { + const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) + + this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( + Effect.andThen(Ref.set(runner.queryRef, props.effect())), + Effect.andThen(runner.forkFetch), + ), [runner, ...props.deps]) + + return React.useMemo(() => ({ + state: runner.stateRef, + refresh: runner.forkRefresh, + }), [runner]) + } +})) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index 76bb022..0052524 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,39 +1,2 @@ -import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Ref, SubscriptionRef } from "effect" -import * as React from "react" -import { ReffuseExtension, type ReffuseHelpers } from "reffuse" -import * as QueryRunner from "./QueryRunner.js" - - -export interface UseQueryProps { - effect: () => Effect.Effect - readonly deps: React.DependencyList -} - -export interface UseQueryResult { - readonly state: SubscriptionRef.SubscriptionRef> - readonly refresh: Effect.Effect> -} - - -export const QueryExtension = ReffuseExtension.make(() => ({ - useQuery( - this: ReffuseHelpers.ReffuseHelpers, - props: UseQueryProps, - ): UseQueryResult { - const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) - - this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Ref.set(runner.queryRef, props.effect())), - Effect.andThen(runner.forkFetch), - ), [runner, ...props.deps]) - - return React.useMemo(() => ({ - state: runner.stateRef, - refresh: runner.forkRefresh, - }), [runner]) - } -})) - - +export * from "./QueryExtension.js" export * as QueryRunner from "./QueryRunner.js" -- 2.49.1 From 74cf37e3a3df2853a8ddbde45c3b3d842a2b1427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 01:35:52 +0100 Subject: [PATCH 074/101] Query example --- packages/example/src/main.tsx | 4 ++-- packages/example/src/routes/__root.tsx | 1 + packages/example/src/routes/query.tsx | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/example/src/main.tsx b/packages/example/src/main.tsx index fc8645f..8fe1e6d 100644 --- a/packages/example/src/main.tsx +++ b/packages/example/src/main.tsx @@ -26,11 +26,11 @@ declare module "@tanstack/react-router" { createRoot(document.getElementById("root")!).render( - // + - // + ) diff --git a/packages/example/src/routes/__root.tsx b/packages/example/src/routes/__root.tsx index e5a9b44..a02f201 100644 --- a/packages/example/src/routes/__root.tsx +++ b/packages/example/src/routes/__root.tsx @@ -20,6 +20,7 @@ function Root() { Count Tests Promise + Query Blank diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index efa1d87..8a2c328 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -3,7 +3,7 @@ import { HttpClient } from "@effect/platform" import { Button, Container, Flex, Text } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import * as AsyncData from "@typed/async-data" -import { Effect, Schema } from "effect" +import { Console, Effect, Schema } from "effect" export const Route = createFileRoute("/query")({ @@ -17,11 +17,12 @@ function RouteComponent() { const runSync = R.useRunSync() const { state, refresh } = R.useQuery({ - effect: () => HttpClient.get("https://www.uuidtools.com/api/generate/v4").pipe( + effect: () => Console.log("Querying...").pipe( + Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), - Effect.delay("500 millis"), Effect.scoped, ), deps: [], -- 2.49.1 From c2b2b1b96e12bcb80f052a04594f3d58b61c0b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 02:04:29 +0100 Subject: [PATCH 075/101] Dependencies fix --- bun.lock | 125 +++++++++--------- packages/example/package.json | 27 ++-- packages/extension-lazyref/package.json | 2 +- packages/extension-query/package.json | 4 +- .../extension-query/src/QueryExtension.ts | 8 +- 5 files changed, 91 insertions(+), 75 deletions(-) diff --git a/bun.lock b/bun.lock index c0936b8..5d880de 100644 --- a/bun.lock +++ b/bun.lock @@ -14,34 +14,35 @@ "name": "@reffuse/example", "version": "0.0.0", "dependencies": { - "@effect/platform": "^0.77.2", - "@effect/platform-browser": "^0.56.2", - "@radix-ui/themes": "^3.2.0", + "@effect/platform": "^0.77.6", + "@effect/platform-browser": "^0.56.6", + "@radix-ui/themes": "^3.2.1", "@reffuse/extension-lazyref": "workspace:*", "@reffuse/extension-query": "workspace:*", + "@typed/async-data": "^0.13.1", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", - "effect": "^3.13.2", - "lucide-react": "^0.476.0", + "effect": "^3.13.6", + "lucide-react": "^0.477.0", "mobx": "^6.13.6", "reffuse": "workspace:*", }, "devDependencies": { "@eslint/js": "^9.21.0", - "@tanstack/react-router": "^1.111.7", - "@tanstack/router-devtools": "^1.111.7", - "@tanstack/router-plugin": "^1.111.7", + "@tanstack/react-router": "^1.112.7", + "@tanstack/router-devtools": "^1.112.7", + "@tanstack/router-plugin": "^1.112.7", "@thilawyn/thilaschema": "^0.1.4", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.21.0", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "typescript-eslint": "^8.25.0", + "typescript-eslint": "^8.26.0", "vite": "^6.2.0", }, }, @@ -52,7 +53,7 @@ "reffuse": "workspace:*", }, "peerDependencies": { - "@typed/lazy-ref": "^0.3.3", + "@typed/lazy-ref": "^0.3.0", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", @@ -66,7 +67,9 @@ "reffuse": "workspace:*", }, "peerDependencies": { - "@typed/async-data": "^0.13.1", + "@effect/platform": "^0.77.0", + "@effect/platform-browser": "^0.56.0", + "@typed/async-data": "^0.13.0", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", @@ -126,9 +129,9 @@ "@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="], - "@effect/platform": ["@effect/platform@0.77.2", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.13.2" } }, "sha512-stvroKHJVfjd3XhZJEPUAOgzqu9DH1vnGHIAjfs2ma6Z4qcjVpFXrxa0ZYmwRaWVIFsiADMenkN0I7XrRdAgLw=="], + "@effect/platform": ["@effect/platform@0.77.6", "", { "dependencies": { "find-my-way-ts": "^0.1.5", "multipasta": "^0.2.5" }, "peerDependencies": { "effect": "^3.13.6" } }, "sha512-ghhLNyj/UoQvmp2I29nqngMlAzQB72BhjUKcOA58cUPaUUwNy3K2jmUAzdU6SB3RHIObsX44CM/jXZiYfTv59A=="], - "@effect/platform-browser": ["@effect/platform-browser@0.56.2", "", { "dependencies": { "multipasta": "^0.2.5" }, "peerDependencies": { "@effect/platform": "^0.77.2", "effect": "^3.13.2" } }, "sha512-mzCNipg3FN9/ATPEO7Cc3cLmTF4gtdoQSVVi5RPJzIxXflVHbNmMFSIuFdGp0W3AbrQ20dfF6FGFaRUo3aFHeA=="], + "@effect/platform-browser": ["@effect/platform-browser@0.56.6", "", { "dependencies": { "multipasta": "^0.2.5" }, "peerDependencies": { "@effect/platform": "^0.77.6", "effect": "^3.13.6" } }, "sha512-kD4AtfoC81/de3fdk57gRIsKDezr8Fn8jePzjYVx2nGY/0379wJfTwLIDMEHE03Ekv/61UVLbmApT5Cyor3H/A=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ=="], @@ -342,7 +345,7 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.0", "", {}, "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="], - "@radix-ui/themes": ["@radix-ui/themes@3.2.0", "", { "dependencies": { "@radix-ui/colors": "^3.0.0", "classnames": "^2.3.2", "radix-ui": "^1.1.2", "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-cG/47tfHN9FW1ZoAigd3oUeJaIm591vGtQ97PrhfwS22IJgWhE5h6D0w2m+NVbKRVo8qIWCG+hiWN04MlLoW4A=="], + "@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=="], "@reffuse/example": ["@reffuse/example@workspace:packages/example"], @@ -350,59 +353,59 @@ "@reffuse/extension-query": ["@reffuse/extension-query@workspace:packages/extension-query"], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.9", "", { "os": "android", "cpu": "arm" }, "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.9", "", { "os": "android", "cpu": "arm64" }, "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A=="], - "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="], + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg=="], - "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="], + "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.9", "", { "os": "win32", "cpu": "x64" }, "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw=="], "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], "@tanstack/history": ["@tanstack/history@1.99.13", "", {}, "sha512-JMd7USmnp8zV8BRGIjALqzPxazvKtQ7PGXQC7n39HpbqdsmfV2ePCzieO84IvN+mwsTrXErpbjI4BfKCa+ZNCg=="], - "@tanstack/react-router": ["@tanstack/react-router@1.111.7", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "^1.111.7", "jsesc": "^3.1.0", "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-/hOWy7lPmVfRqbwIy2d9mvVLA6ZC4tbcgLDdMXCNRN93LMsGEHCTrgFADdSL2f/rvhPyHeYxsFazEo9+ktgUiw=="], + "@tanstack/react-router": ["@tanstack/react-router@1.112.7", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "^1.112.0", "jsesc": "^3.1.0", "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-udThbvP01cXMvMUK5OPayxuR7ib5AtFL2VnbZSnnKS/dHGsk8KRS+qmkyqZBuuOxRkkF2MC3+BdPj2UTZ4UNjQ=="], "@tanstack/react-store": ["@tanstack/react-store@0.7.0", "", { "dependencies": { "@tanstack/store": "0.7.0", "use-sync-external-store": "^1.4.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-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng=="], - "@tanstack/router-core": ["@tanstack/router-core@1.111.7", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/store": "^0.7.0" } }, "sha512-N3u3HGBNb1k+MvL15CGmE4KFEDy3euU/L3ENXjmzPm8zfpeVjs+Tyk3y0nicAk3MSSboGXVU1po19RATdWnTsg=="], + "@tanstack/router-core": ["@tanstack/router-core@1.112.0", "", { "dependencies": { "@tanstack/history": "1.99.13", "@tanstack/store": "^0.7.0" } }, "sha512-kmpMiBuz17Hxyl+ZO+B6/F98p07NSEmgr2JlZkKXcdupLIBAWqcXw+bjowFXNcTEwe9RWsS/WjAC/bBTftr0rA=="], - "@tanstack/router-devtools": ["@tanstack/router-devtools@1.111.7", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/react-router": "^1.111.7", "csstype": "^3.0.10", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["csstype"] }, "sha512-xZpiIWy/HBhpYUqUxT1dNUn5smQhWhkgjNlJOATzrm81G5T3l2jEr79XPXqwRndWzu2WKqv1kPkScC0ekRgE7Q=="], + "@tanstack/router-devtools": ["@tanstack/router-devtools@1.112.7", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/react-router": "^1.112.7", "csstype": "^3.0.10", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["csstype"] }, "sha512-37qpVzYK4JEg/i0CvnbKI2G+OyWai9yLyvnm8UIc9f2yDzVZKJ1qEpnRXhuLdGCL8dmsf7PjhAPmw46YnD3fHQ=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.111.7", "", { "dependencies": { "@tanstack/virtual-file-routes": "^1.99.0", "prettier": "^3.5.0", "tsx": "^4.19.2", "zod": "^3.24.1" }, "peerDependencies": { "@tanstack/react-router": "^1.111.7" }, "optionalPeers": ["@tanstack/react-router"] }, "sha512-+jHX35iF45NHQvHzXuLgyCILUUTyMl3EeClKNkfdaKLvV1adwGDQr24cSKDQLmNKEDXGTijBI5nX8ntkKo5oyA=="], + "@tanstack/router-generator": ["@tanstack/router-generator@1.112.7", "", { "dependencies": { "@tanstack/virtual-file-routes": "^1.99.0", "prettier": "^3.5.0", "tsx": "^4.19.2", "zod": "^3.24.1" }, "peerDependencies": { "@tanstack/react-router": "^1.112.7" }, "optionalPeers": ["@tanstack/react-router"] }, "sha512-2BlV64vej9T+NnjUEX42BOEKpCnC2dUtfxr9Xz0sQk43fMWtNe+2b1jzPzJZWlu8RjaQ5OK22hL+p7GSpph3Kw=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.111.7", "", { "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-core": "^1.111.7", "@tanstack/router-generator": "^1.111.7", "@tanstack/router-utils": "^1.102.2", "@tanstack/virtual-file-routes": "^1.99.0", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/babel__traverse": "^7.20.6", "babel-dead-code-elimination": "^1.0.9", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.1" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.111.7", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-aiT/j2OadGbqEWTZUY53o2UeVQIR11+S1h1Gq6GYxQmD/OjdyK/WiMighBK5zeryeWYG4XeC8eFlXMoyuG0v+g=="], + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.112.7", "", { "dependencies": { "@babel/core": "^7.26.8", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9", "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-core": "^1.112.0", "@tanstack/router-generator": "^1.112.7", "@tanstack/router-utils": "^1.102.2", "@tanstack/virtual-file-routes": "^1.99.0", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", "@types/babel__traverse": "^7.20.6", "babel-dead-code-elimination": "^1.0.9", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.1" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.112.7", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-9m5UfLSWd5T2jOG9O0BWd1WkChalYfkO/zZjnQ+JoyvixbqTUmkXWkbNtMrZSfM/lNQO4HiftPMMflLSGWMrWg=="], "@tanstack/router-utils": ["@tanstack/router-utils@1.102.2", "", { "dependencies": { "@babel/generator": "^7.26.8", "@babel/parser": "^7.26.8", "ansis": "^3.11.0", "diff": "^7.0.0" } }, "sha512-Uwl2nbrxhCzviaHHBLNPhSC/OMpZLdOTxTJndUSsXTzWUP4IoQcVmngaIsxi9iriE3ArC1VXuanUAkfGmimNOQ=="], @@ -434,21 +437,21 @@ "@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.25.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/type-utils": "8.25.0", "@typescript-eslint/utils": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.26.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.26.0", "@typescript-eslint/type-utils": "8.26.0", "@typescript-eslint/utils": "8.26.0", "@typescript-eslint/visitor-keys": "8.26.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.25.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/types": "8.25.0", "@typescript-eslint/typescript-estree": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.26.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.26.0", "@typescript-eslint/types": "8.26.0", "@typescript-eslint/typescript-estree": "8.26.0", "@typescript-eslint/visitor-keys": "8.26.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0" } }, "sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "@typescript-eslint/visitor-keys": "8.26.0" } }, "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.25.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.25.0", "@typescript-eslint/utils": "8.25.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.26.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.26.0", "@typescript-eslint/utils": "8.26.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.25.0", "", {}, "sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.26.0", "", {}, "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "@typescript-eslint/visitor-keys": "8.25.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "@typescript-eslint/visitor-keys": "8.26.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.25.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.25.0", "@typescript-eslint/types": "8.25.0", "@typescript-eslint/typescript-estree": "8.25.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.26.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.26.0", "@typescript-eslint/types": "8.26.0", "@typescript-eslint/typescript-estree": "8.26.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.25.0", "", { "dependencies": { "@typescript-eslint/types": "8.25.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.0", "", { "dependencies": { "@typescript-eslint/types": "8.26.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="], @@ -460,7 +463,7 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansis": ["ansis@3.16.0", "", {}, "sha512-sU7d/tfZiYrsIAXbdL/CNZld5bCkruzwT5KmqmadCJYxuLxHAOBjidxD5+iLmN/6xEfjcQq1l7OpsiCBlc4LzA=="], + "ansis": ["ansis@3.17.0", "", {}, "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -482,7 +485,7 @@ "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - "caniuse-lite": ["caniuse-lite@1.0.30001700", "", {}, "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001701", "", {}, "sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -512,9 +515,9 @@ "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], - "effect": ["effect@3.13.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-/w+CPqHDJ33Wq7xC4YKAchrEEPtjvxh563xH9kDTZp99seNYBoBs87vl8DJwartEjj+KLQLP8PzoDne+XmGT2A=="], + "effect": ["effect@3.13.6", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-NKmzyIuOb2UuHFPRz9EYScbhMBxXkzjPRuu+4axE+hMk1f0U7TZxzi2CP3TVVxA2kzvh00aBQEbyH7Opq4PnWg=="], - "electron-to-chromium": ["electron-to-chromium@1.5.104", "", {}, "sha512-Us9M2L4cO/zMBqVkJtnj353nQhMju9slHm62NprKTmdF3HH8wYOtNvDFq/JB2+ZRoGLzdvYDiATlMHs98XBM1g=="], + "electron-to-chromium": ["electron-to-chromium@1.5.111", "", {}, "sha512-vJyJlO95wQRAw6K2ZGF/8nol7AcbCOnp8S6H91mwOOBbXoS9seDBYxCTPYAFsvXLxl3lc0jLXXe9GLxC4nXVog=="], "esbuild": ["esbuild@0.25.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.0", "@esbuild/android-arm": "0.25.0", "@esbuild/android-arm64": "0.25.0", "@esbuild/android-x64": "0.25.0", "@esbuild/darwin-arm64": "0.25.0", "@esbuild/darwin-x64": "0.25.0", "@esbuild/freebsd-arm64": "0.25.0", "@esbuild/freebsd-x64": "0.25.0", "@esbuild/linux-arm": "0.25.0", "@esbuild/linux-arm64": "0.25.0", "@esbuild/linux-ia32": "0.25.0", "@esbuild/linux-loong64": "0.25.0", "@esbuild/linux-mips64el": "0.25.0", "@esbuild/linux-ppc64": "0.25.0", "@esbuild/linux-riscv64": "0.25.0", "@esbuild/linux-s390x": "0.25.0", "@esbuild/linux-x64": "0.25.0", "@esbuild/netbsd-arm64": "0.25.0", "@esbuild/netbsd-x64": "0.25.0", "@esbuild/openbsd-arm64": "0.25.0", "@esbuild/openbsd-x64": "0.25.0", "@esbuild/sunos-x64": "0.25.0", "@esbuild/win32-arm64": "0.25.0", "@esbuild/win32-ia32": "0.25.0", "@esbuild/win32-x64": "0.25.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw=="], @@ -524,7 +527,7 @@ "eslint": ["eslint@9.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.0", "@eslint/js": "9.21.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg=="], - "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.1.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw=="], + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.19", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ=="], @@ -552,7 +555,7 @@ "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fastq": ["fastq@1.19.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA=="], + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], @@ -624,7 +627,7 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "lucide-react": ["lucide-react@0.476.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-x6cLTk8gahdUPje0hSgLN1/MgiJH+Xl90Xoxy9bkPAsMPOUiyRSKR4JCDPGVCEpyqnZXH3exFWNItcvra9WzUQ=="], + "lucide-react": ["lucide-react@0.477.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yCf7aYxerFZAbd8jHJxjwe1j7jEMPptjnaOqdYeirFnEy85cNR3/L+o0I875CYFYya+eEVzZSbNuRk8BZPDpVw=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], @@ -670,7 +673,7 @@ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.5.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg=="], + "prettier": ["prettier@3.5.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -696,7 +699,7 @@ "reffuse": ["reffuse@workspace:packages/reffuse"], - "remeda": ["remeda@2.20.2", "", { "dependencies": { "type-fest": "^4.33.0" } }, "sha512-38pfm5aUq6mUkNYbt7TdY2WEk9mSqRVV+6UsoTjabwmbu8obLbh8sYYSX2WQ3W4u6EYp3XxUKqIiwGFZu+OY9g=="], + "remeda": ["remeda@2.21.0", "", { "dependencies": { "type-fest": "^4.35.0" } }, "sha512-ANFqOts3BsvW1MrKOv9SVHG3ly0MzzLa0HIu5qLkiRuEPGPuH9ny3sgd7VdHvC2VOUSN/7RkmabPlAda6JtGgg=="], "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], @@ -704,7 +707,7 @@ "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="], + "rollup": ["rollup@4.34.9", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.9", "@rollup/rollup-android-arm64": "4.34.9", "@rollup/rollup-darwin-arm64": "4.34.9", "@rollup/rollup-darwin-x64": "4.34.9", "@rollup/rollup-freebsd-arm64": "4.34.9", "@rollup/rollup-freebsd-x64": "4.34.9", "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", "@rollup/rollup-linux-arm-musleabihf": "4.34.9", "@rollup/rollup-linux-arm64-gnu": "4.34.9", "@rollup/rollup-linux-arm64-musl": "4.34.9", "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", "@rollup/rollup-linux-riscv64-gnu": "4.34.9", "@rollup/rollup-linux-s390x-gnu": "4.34.9", "@rollup/rollup-linux-x64-gnu": "4.34.9", "@rollup/rollup-linux-x64-musl": "4.34.9", "@rollup/rollup-win32-arm64-msvc": "4.34.9", "@rollup/rollup-win32-ia32-msvc": "4.34.9", "@rollup/rollup-win32-x64-msvc": "4.34.9", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], @@ -750,15 +753,15 @@ "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "type-fest": ["type-fest@4.35.0", "", {}, "sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A=="], + "type-fest": ["type-fest@4.36.0", "", {}, "sha512-3T/PUdKTCnkUmhQU6FFJEHsLwadsRegktX3TNHk+2JJB9HlA8gp1/VXblXVDI93kSnXF2rdPx0GMbHtJIV2LPg=="], - "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], + "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], - "typescript-eslint": ["typescript-eslint@8.25.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.25.0", "@typescript-eslint/parser": "8.25.0", "@typescript-eslint/utils": "8.25.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q=="], + "typescript-eslint": ["typescript-eslint@8.26.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.26.0", "@typescript-eslint/parser": "8.26.0", "@typescript-eslint/utils": "8.26.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA=="], "unplugin": ["unplugin@2.2.0", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw=="], - "update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="], + "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], diff --git a/packages/example/package.json b/packages/example/package.json index 6d93aba..08ae5f9 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -12,36 +12,41 @@ }, "devDependencies": { "@eslint/js": "^9.21.0", - "@tanstack/react-router": "^1.111.7", - "@tanstack/router-devtools": "^1.111.7", - "@tanstack/router-plugin": "^1.111.7", + "@tanstack/react-router": "^1.112.7", + "@tanstack/router-devtools": "^1.112.7", + "@tanstack/router-plugin": "^1.112.7", "@thilawyn/thilaschema": "^0.1.4", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.21.0", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "typescript-eslint": "^8.25.0", + "typescript-eslint": "^8.26.0", "vite": "^6.2.0" }, "dependencies": { - "@effect/platform": "^0.77.2", - "@effect/platform-browser": "^0.56.2", - "@radix-ui/themes": "^3.2.0", + "@effect/platform": "^0.77.6", + "@effect/platform-browser": "^0.56.6", + "@radix-ui/themes": "^3.2.1", "@reffuse/extension-lazyref": "workspace:*", "@reffuse/extension-query": "workspace:*", + "@typed/async-data": "^0.13.1", "@typed/id": "^0.17.1", "@typed/lazy-ref": "^0.3.3", - "effect": "^3.13.2", - "lucide-react": "^0.476.0", + "effect": "^3.13.6", + "lucide-react": "^0.477.0", "mobx": "^6.13.6", "reffuse": "workspace:*" }, "overrides": { - "effect": "^3.13.2" + "effect": "^3.13.6", + "@effect/platform": "^0.77.6", + "@effect/platform-browser": "^0.56.6", + "@typed/lazy-ref": "^0.3.3", + "@typed/async-data": "^0.13.1" } } diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index 2e77c53..d9b9498 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -33,7 +33,7 @@ "reffuse": "workspace:*" }, "peerDependencies": { - "@typed/lazy-ref": "^0.3.3", + "@typed/lazy-ref": "^0.3.0", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", diff --git a/packages/extension-query/package.json b/packages/extension-query/package.json index d50650c..5b61105 100644 --- a/packages/extension-query/package.json +++ b/packages/extension-query/package.json @@ -33,7 +33,9 @@ "reffuse": "workspace:*" }, "peerDependencies": { - "@typed/async-data": "^0.13.1", + "@effect/platform": "^0.77.0", + "@effect/platform-browser": "^0.56.0", + "@typed/async-data": "^0.13.0", "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 2ee4607..6d5d304 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,5 +1,6 @@ +import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Ref, SubscriptionRef } from "effect" +import { Console, Effect, Fiber, Ref, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -28,6 +29,11 @@ export const QueryExtension = ReffuseExtension.make(() => ({ Effect.andThen(runner.forkFetch), ), [runner, ...props.deps]) + this.useFork(() => Stream.runForEach( + BrowserStream.fromEventListenerWindow("focus"), + () => Console.log("focus!"), + ), []) + return React.useMemo(() => ({ state: runner.stateRef, refresh: runner.forkRefresh, -- 2.49.1 From 00b72280730c33d55245ba80cadd2033725e32db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 02:15:31 +0100 Subject: [PATCH 076/101] Refetch on focus --- packages/extension-query/src/QueryExtension.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 6d5d304..83ecdd7 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,6 +1,6 @@ import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { Console, Effect, Fiber, Ref, Stream, SubscriptionRef } from "effect" +import { Effect, Fiber, Ref, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -31,8 +31,8 @@ export const QueryExtension = ReffuseExtension.make(() => ({ this.useFork(() => Stream.runForEach( BrowserStream.fromEventListenerWindow("focus"), - () => Console.log("focus!"), - ), []) + () => runner.forkRefresh, + ), [runner]) return React.useMemo(() => ({ state: runner.stateRef, -- 2.49.1 From 3af7c3bf7ad475de5800fc63cd8a22fbf0851bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 22:44:40 +0100 Subject: [PATCH 077/101] Query service work --- packages/example/src/query/reffuse.ts | 10 ++++ .../example/src/query/services/Uuid4Query.ts | 20 ++++++++ packages/example/src/query/services/index.ts | 1 + .../src/query/views/Uuid4QueryService.tsx | 32 ++++++++++++ packages/example/src/routeTree.gen.ts | 49 ++++++++++++++++--- packages/example/src/routes/query/service.tsx | 26 ++++++++++ packages/extension-query/src/QueryService.ts | 26 ++++++++++ packages/extension-query/src/index.ts | 1 + packages/reffuse/src/ReffuseHelpers.ts | 6 ++- 9 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 packages/example/src/query/reffuse.ts create mode 100644 packages/example/src/query/services/Uuid4Query.ts create mode 100644 packages/example/src/query/services/index.ts create mode 100644 packages/example/src/query/views/Uuid4QueryService.tsx create mode 100644 packages/example/src/routes/query/service.tsx create mode 100644 packages/extension-query/src/QueryService.ts diff --git a/packages/example/src/query/reffuse.ts b/packages/example/src/query/reffuse.ts new file mode 100644 index 0000000..ced8e18 --- /dev/null +++ b/packages/example/src/query/reffuse.ts @@ -0,0 +1,10 @@ +import { GlobalReffuse } from "@/reffuse" +import { Reffuse, ReffuseContext } from "reffuse" +import { Uuid4Query } from "./services" + + +export const QueryContext = ReffuseContext.make() + +export const R = new class QueryReffuse extends GlobalReffuse.pipe( + Reffuse.withContexts(QueryContext) +) {} diff --git a/packages/example/src/query/services/Uuid4Query.ts b/packages/example/src/query/services/Uuid4Query.ts new file mode 100644 index 0000000..ab11b0e --- /dev/null +++ b/packages/example/src/query/services/Uuid4Query.ts @@ -0,0 +1,20 @@ +import { HttpClient, HttpClientError } from "@effect/platform" +import { QueryService } from "@reffuse/extension-query" +import { Console, Effect, ParseResult, Schema } from "effect" + + +export const Result = Schema.Tuple(Schema.String) + +export class Uuid4Query extends QueryService.Tag("Uuid4Query")() {} + +export const Uuid4QueryLive = QueryService.layer(Uuid4Query, Console.log("Querying...").pipe( + Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), + HttpClient.withTracerPropagation(false), + Effect.flatMap(res => res.json), + Effect.flatMap(Schema.decodeUnknown(Result)), + Effect.scoped, +)) diff --git a/packages/example/src/query/services/index.ts b/packages/example/src/query/services/index.ts new file mode 100644 index 0000000..4f67d41 --- /dev/null +++ b/packages/example/src/query/services/index.ts @@ -0,0 +1 @@ +export * as Uuid4Query from "./Uuid4Query" diff --git a/packages/example/src/query/views/Uuid4QueryService.tsx b/packages/example/src/query/views/Uuid4QueryService.tsx new file mode 100644 index 0000000..ff6463b --- /dev/null +++ b/packages/example/src/query/views/Uuid4QueryService.tsx @@ -0,0 +1,32 @@ +import { Button, Container, Flex, Text } from "@radix-ui/themes" +import * as AsyncData from "@typed/async-data" +import { R } from "../reffuse" +import { Uuid4Query } from "../services" + + +export function Uuid4QueryService() { + const runSync = R.useRunSync() + + const { state, refresh } = R.useMemo(() => Uuid4Query.Uuid4Query, []) + const [queryState] = R.useRefState(state) + + + return ( + + + + {AsyncData.match(queryState, { + NoData: () => "No data yet", + Loading: () => "Loading...", + Success: (value, { isRefreshing, isOptimistic }) => + `Value: ${value} ${isRefreshing ? "(refreshing)" : ""} ${isOptimistic ? "(optimistic)" : ""}`, + Failure: (cause, { isRefreshing }) => + `Error: ${cause} ${isRefreshing ? "(refreshing)" : ""}`, + })} + + + + + + ) +} diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index 20f3fba..3e3a17c 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -19,6 +19,7 @@ import { Route as LazyrefImport } from './routes/lazyref' import { Route as CountImport } from './routes/count' import { Route as BlankImport } from './routes/blank' import { Route as IndexImport } from './routes/index' +import { Route as QueryServiceImport } from './routes/query/service' // Create/Update Routes @@ -70,6 +71,12 @@ const IndexRoute = IndexImport.update({ getParentRoute: () => rootRoute, } as any) +const QueryServiceRoute = QueryServiceImport.update({ + id: '/service', + path: '/service', + getParentRoute: () => QueryRoute, +} as any) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -130,20 +137,38 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof TimeImport parentRoute: typeof rootRoute } + '/query/service': { + id: '/query/service' + path: '/service' + fullPath: '/query/service' + preLoaderRoute: typeof QueryServiceImport + parentRoute: typeof QueryImport + } } } // Create and export the route tree +interface QueryRouteChildren { + QueryServiceRoute: typeof QueryServiceRoute +} + +const QueryRouteChildren: QueryRouteChildren = { + QueryServiceRoute: QueryServiceRoute, +} + +const QueryRouteWithChildren = QueryRoute._addFileChildren(QueryRouteChildren) + export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRoute + '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute + '/query/service': typeof QueryServiceRoute } export interface FileRoutesByTo { @@ -152,9 +177,10 @@ export interface FileRoutesByTo { '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRoute + '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute + '/query/service': typeof QueryServiceRoute } export interface FileRoutesById { @@ -164,9 +190,10 @@ export interface FileRoutesById { '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRoute + '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute + '/query/service': typeof QueryServiceRoute } export interface FileRouteTypes { @@ -180,6 +207,7 @@ export interface FileRouteTypes { | '/query' | '/tests' | '/time' + | '/query/service' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -190,6 +218,7 @@ export interface FileRouteTypes { | '/query' | '/tests' | '/time' + | '/query/service' id: | '__root__' | '/' @@ -200,6 +229,7 @@ export interface FileRouteTypes { | '/query' | '/tests' | '/time' + | '/query/service' fileRoutesById: FileRoutesById } @@ -209,7 +239,7 @@ export interface RootRouteChildren { CountRoute: typeof CountRoute LazyrefRoute: typeof LazyrefRoute PromiseRoute: typeof PromiseRoute - QueryRoute: typeof QueryRoute + QueryRoute: typeof QueryRouteWithChildren TestsRoute: typeof TestsRoute TimeRoute: typeof TimeRoute } @@ -220,7 +250,7 @@ const rootRouteChildren: RootRouteChildren = { CountRoute: CountRoute, LazyrefRoute: LazyrefRoute, PromiseRoute: PromiseRoute, - QueryRoute: QueryRoute, + QueryRoute: QueryRouteWithChildren, TestsRoute: TestsRoute, TimeRoute: TimeRoute, } @@ -261,13 +291,20 @@ export const routeTree = rootRoute "filePath": "promise.tsx" }, "/query": { - "filePath": "query.tsx" + "filePath": "query.tsx", + "children": [ + "/query/service" + ] }, "/tests": { "filePath": "tests.tsx" }, "/time": { "filePath": "time.tsx" + }, + "/query/service": { + "filePath": "query/service.tsx", + "parent": "/query" } } } diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx new file mode 100644 index 0000000..ad1e3de --- /dev/null +++ b/packages/example/src/routes/query/service.tsx @@ -0,0 +1,26 @@ +import { QueryContext } from "@/query/reffuse" +import { Uuid4Query } from "@/query/services" +import { R } from "@/reffuse" +import { createFileRoute } from "@tanstack/react-router" +import { Effect, Layer } from "effect" +import { useMemo } from "react" + + +export const Route = createFileRoute("/query/service")({ + component: RouteComponent +}) + +function RouteComponent() { + const context = R.useContext() + + const layer = useMemo(() => Layer.empty.pipe( + Layer.provideMerge(Uuid4Query.Uuid4QueryLive), + Layer.provide(context) + ), []) + + return ( + + + + ) +} diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts new file mode 100644 index 0000000..bde1206 --- /dev/null +++ b/packages/extension-query/src/QueryService.ts @@ -0,0 +1,26 @@ +import * as AsyncData from "@typed/async-data" +import { Context, Effect, Fiber, Layer, SubscriptionRef } from "effect" +import * as QueryRunner from "./QueryRunner.js" + + +export interface QueryService { + readonly state: SubscriptionRef.SubscriptionRef> + readonly refresh: Effect.Effect> +} + + +export const Tag = (id: Id) => < + Self, A, E = never, +>() => Effect.Tag(id)>() + +export const layer = ( + tag: Context.TagClass>, + query: Effect.Effect, +): Layer.Layer => Layer.effect(tag, Effect.gen(function*() { + const runner = yield* QueryRunner.make(query) + + return { + state: runner.stateRef, + refresh: runner.forkRefresh, + } +})) diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index 0052524..790fe0c 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,2 +1,3 @@ export * from "./QueryExtension.js" export * as QueryRunner from "./QueryRunner.js" +export * as QueryService from "./QueryService.js" diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 77b3b6c..bdb8858 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -1,4 +1,4 @@ -import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Layer, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" @@ -23,6 +23,10 @@ export abstract class ReffuseHelpers { return ReffuseContext.useMergeAll(...this.constructor.contexts) } + useLayer(this: ReffuseHelpers): Layer.Layer { + return ReffuseContext.useMergeAllLayers(...this.constructor.contexts) + } + useRunSync(this: ReffuseHelpers): (effect: Effect.Effect) => A { const runtime = ReffuseRuntime.useRuntime() -- 2.49.1 From adaadf13b25ba90189af4aaa82d350d8646f2d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 4 Mar 2025 23:18:35 +0100 Subject: [PATCH 078/101] Working service query --- packages/example/src/routes/query/service.tsx | 11 ++++++----- packages/reffuse/src/ReffuseContext.tsx | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index ad1e3de..638dbe3 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -1,8 +1,9 @@ import { QueryContext } from "@/query/reffuse" import { Uuid4Query } from "@/query/services" +import { Uuid4QueryService } from "@/query/views/Uuid4QueryService" import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { Effect, Layer } from "effect" +import { Layer } from "effect" import { useMemo } from "react" @@ -11,16 +12,16 @@ export const Route = createFileRoute("/query/service")({ }) function RouteComponent() { - const context = R.useContext() + const context = R.useLayer() const layer = useMemo(() => Layer.empty.pipe( Layer.provideMerge(Uuid4Query.Uuid4QueryLive), - Layer.provide(context) - ), []) + Layer.provide(context), + ), [context]) return ( - + ) } diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index f1898ff..89d1394 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -97,15 +97,15 @@ export function useMergeAll>( return React.useMemo(() => Context.mergeAll(...values), values) } -export function useMergeAllLayers>( +export function useMergeAllLayers>( ...contexts: [...{ [K in keyof T]: ReffuseContext }] ): Layer.Layer { - const values = Array.map( - contexts as Array.NonEmptyArray>, - v => React.use(v.Context), - ) + const values = contexts.map(v => React.use(v.Context)) - return React.useMemo(() => Layer.mergeAll( - ...Array.map(values, context => Layer.effectContext(Effect.succeed(context))) - ), values) + return React.useMemo(() => Array.isNonEmptyArray(values) + ? Layer.mergeAll( + ...Array.map(values, context => Layer.effectContext(Effect.succeed(context))) + ) + : Layer.empty as Layer.Layer, + values) } -- 2.49.1 From 8fa24b17913699f98d322fbe9751d0040a3e36b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 5 Mar 2025 00:16:13 +0100 Subject: [PATCH 079/101] Query work --- .../example/src/query/services/Uuid4Query.ts | 18 ++++++++++-------- packages/example/src/routes/query.tsx | 4 ++-- packages/extension-query/src/QueryExtension.ts | 12 +++++++----- packages/extension-query/src/QueryRunner.ts | 8 ++++++-- packages/extension-query/src/QueryService.ts | 12 +++++++++--- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/packages/example/src/query/services/Uuid4Query.ts b/packages/example/src/query/services/Uuid4Query.ts index ab11b0e..ab9d4cf 100644 --- a/packages/example/src/query/services/Uuid4Query.ts +++ b/packages/example/src/query/services/Uuid4Query.ts @@ -10,11 +10,13 @@ export class Uuid4Query extends QueryService.Tag("Uuid4Query")() {} -export const Uuid4QueryLive = QueryService.layer(Uuid4Query, Console.log("Querying...").pipe( - Effect.andThen(Effect.sleep("500 millis")), - Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), - HttpClient.withTracerPropagation(false), - Effect.flatMap(res => res.json), - Effect.flatMap(Schema.decodeUnknown(Result)), - Effect.scoped, -)) +export const Uuid4QueryLive = QueryService.layer(Uuid4Query, { + query: Console.log("Querying...").pipe( + Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), + HttpClient.withTracerPropagation(false), + Effect.flatMap(res => res.json), + Effect.flatMap(Schema.decodeUnknown(Result)), + Effect.scoped, + ) +}) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index 8a2c328..bef9373 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -17,7 +17,7 @@ function RouteComponent() { const runSync = R.useRunSync() const { state, refresh } = R.useQuery({ - effect: () => Console.log("Querying...").pipe( + query: () => Console.log("Querying...").pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), HttpClient.withTracerPropagation(false), @@ -25,7 +25,7 @@ function RouteComponent() { Effect.flatMap(Schema.decodeUnknown(Result)), Effect.scoped, ), - deps: [], + key: [], }) const [queryState] = R.useRefState(state) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 83ecdd7..380ff56 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -7,8 +7,8 @@ import * as QueryRunner from "./QueryRunner.js" export interface UseQueryProps { - effect: () => Effect.Effect - readonly deps: React.DependencyList + readonly query: () => Effect.Effect + readonly key: React.DependencyList } export interface UseQueryResult { @@ -22,12 +22,14 @@ export const QueryExtension = ReffuseExtension.make(() => ({ this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, ): UseQueryResult { - const runner = this.useMemo(() => QueryRunner.make(props.effect()), []) + const runner = this.useMemo(() => QueryRunner.make({ + query: props.query() + }), []) this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Ref.set(runner.queryRef, props.effect())), + Effect.andThen(Ref.set(runner.queryRef, props.query())), Effect.andThen(runner.forkFetch), - ), [runner, ...props.deps]) + ), [runner, ...props.key]) this.useFork(() => Stream.runForEach( BrowserStream.fromEventListenerWindow("focus"), diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 072e816..93cef0f 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -13,12 +13,16 @@ export interface QueryRunner { } +export interface MakeProps { + readonly query: Effect.Effect +} + export const make = ( - query: Effect.Effect + props: MakeProps ): Effect.Effect, never, R> => Effect.gen(function*() { const context = yield* Effect.context() - const queryRef = yield* SubscriptionRef.make(query) + const queryRef = yield* SubscriptionRef.make(props.query) const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) const fiberRef = yield* SubscriptionRef.make(Option.none>()) diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index bde1206..6dc92d7 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -8,16 +8,22 @@ export interface QueryService { readonly refresh: Effect.Effect> } - export const Tag = (id: Id) => < Self, A, E = never, >() => Effect.Tag(id)>() + +export interface LayerProps { + readonly query: Effect.Effect +} + export const layer = ( tag: Context.TagClass>, - query: Effect.Effect, + props: LayerProps, ): Layer.Layer => Layer.effect(tag, Effect.gen(function*() { - const runner = yield* QueryRunner.make(query) + const runner = yield* QueryRunner.make({ + query: props.query + }) return { state: runner.stateRef, -- 2.49.1 From 86539f33f0b9b7344001fafeb0c081fdf4d24a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 5 Mar 2025 00:24:38 +0100 Subject: [PATCH 080/101] Fix --- packages/example/src/query/views/Uuid4QueryService.tsx | 8 ++++---- packages/example/src/routes/query.tsx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/example/src/query/views/Uuid4QueryService.tsx b/packages/example/src/query/views/Uuid4QueryService.tsx index ff6463b..bc0eada 100644 --- a/packages/example/src/query/views/Uuid4QueryService.tsx +++ b/packages/example/src/query/views/Uuid4QueryService.tsx @@ -7,15 +7,15 @@ import { Uuid4Query } from "../services" export function Uuid4QueryService() { const runSync = R.useRunSync() - const { state, refresh } = R.useMemo(() => Uuid4Query.Uuid4Query, []) - const [queryState] = R.useRefState(state) + const query = R.useMemo(() => Uuid4Query.Uuid4Query, []) + const [state] = R.useRefState(query.state) return ( - {AsyncData.match(queryState, { + {AsyncData.match(state, { NoData: () => "No data yet", Loading: () => "Loading...", Success: (value, { isRefreshing, isOptimistic }) => @@ -25,7 +25,7 @@ export function Uuid4QueryService() { })} - + ) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index bef9373..eb01ac0 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -16,7 +16,7 @@ const Result = Schema.Tuple(Schema.String) function RouteComponent() { const runSync = R.useRunSync() - const { state, refresh } = R.useQuery({ + const query = R.useQuery({ query: () => Console.log("Querying...").pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), @@ -28,14 +28,14 @@ function RouteComponent() { key: [], }) - const [queryState] = R.useRefState(state) + const [state] = R.useRefState(query.state) return ( - {AsyncData.match(queryState, { + {AsyncData.match(state, { NoData: () => "No data yet", Loading: () => "Loading...", Success: (value, { isRefreshing, isOptimistic }) => @@ -45,7 +45,7 @@ function RouteComponent() { })} - + ) -- 2.49.1 From 1e8a5d412fbca2f91de76f27ed724d555c879c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 5 Mar 2025 00:44:13 +0100 Subject: [PATCH 081/101] Refresh on window focus --- packages/extension-query/src/QueryExtension.ts | 8 ++------ packages/extension-query/src/QueryRunner.ts | 12 +++++++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 380ff56..8ad003f 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,6 +1,5 @@ -import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Ref, Stream, SubscriptionRef } from "effect" +import { Effect, Fiber, Ref, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -31,10 +30,7 @@ export const QueryExtension = ReffuseExtension.make(() => ({ Effect.andThen(runner.forkFetch), ), [runner, ...props.key]) - this.useFork(() => Stream.runForEach( - BrowserStream.fromEventListenerWindow("focus"), - () => runner.forkRefresh, - ), [runner]) + this.useFork(() => runner.refreshOnWindowFocus, [runner]) return React.useMemo(() => ({ state: runner.stateRef, diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 93cef0f..2a75a70 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -1,5 +1,6 @@ +import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, identity, Option, Ref, SubscriptionRef } from "effect" +import { Effect, Fiber, identity, Option, Ref, Stream, SubscriptionRef } from "effect" export interface QueryRunner { @@ -10,6 +11,8 @@ export interface QueryRunner { readonly forkInterrupt: Effect.Effect> readonly forkFetch: Effect.Effect> readonly forkRefresh: Effect.Effect> + + readonly refreshOnWindowFocus: Effect.Effect } @@ -91,6 +94,11 @@ export const make = ( Effect.forkDaemon, ) + const refreshOnWindowFocus = Stream.runForEach( + BrowserStream.fromEventListenerWindow("focus"), + () => forkRefresh, + ) + return { queryRef, stateRef, @@ -99,5 +107,7 @@ export const make = ( forkInterrupt, forkFetch, forkRefresh, + + refreshOnWindowFocus, } }) -- 2.49.1 From 3659d3f34284abf1e37ab19642853bceebf5d254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 5 Mar 2025 01:50:08 +0100 Subject: [PATCH 082/101] Version bump --- packages/extension-lazyref/package.json | 2 +- packages/extension-query/package.json | 2 +- packages/reffuse/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/extension-lazyref/package.json b/packages/extension-lazyref/package.json index d9b9498..5b921aa 100644 --- a/packages/extension-lazyref/package.json +++ b/packages/extension-lazyref/package.json @@ -37,6 +37,6 @@ "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", - "reffuse": "^0.1.2" + "reffuse": "^0.1.3" } } diff --git a/packages/extension-query/package.json b/packages/extension-query/package.json index 5b61105..a41819c 100644 --- a/packages/extension-query/package.json +++ b/packages/extension-query/package.json @@ -39,6 +39,6 @@ "@types/react": "^19.0.0", "effect": "^3.13.0", "react": "^19.0.0", - "reffuse": "^0.1.2" + "reffuse": "^0.1.3" } } diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index 950c3b6..bfe88f7 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -1,6 +1,6 @@ { "name": "reffuse", - "version": "0.1.2", + "version": "0.1.3", "type": "module", "files": [ "./README.md", -- 2.49.1 From d61339ea6a55965c0c30cf5804fc1b4fac3f1a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 5 Mar 2025 02:23:43 +0100 Subject: [PATCH 083/101] Query work --- packages/example/src/routes/query.tsx | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index eb01ac0..07387ac 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -1,9 +1,10 @@ import { R } from "@/reffuse" import { HttpClient } from "@effect/platform" -import { Button, Container, Flex, Text } from "@radix-ui/themes" +import { Button, Container, Flex, Slider, Text } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" import * as AsyncData from "@typed/async-data" -import { Console, Effect, Schema } from "effect" +import { Array, Console, Effect, flow, Option, Schema } from "effect" +import { useState } from "react" export const Route = createFileRoute("/query")({ @@ -11,21 +12,23 @@ export const Route = createFileRoute("/query")({ }) -const Result = Schema.Tuple(Schema.String) +const Result = Schema.Array(Schema.String) function RouteComponent() { const runSync = R.useRunSync() + const [count, setCount] = useState(1) + const query = R.useQuery({ - query: () => Console.log("Querying...").pipe( - Effect.andThen(Effect.sleep("500 millis")), - Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), + query: () => Console.log(`Querying ${ count } IDs...`).pipe( + // Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), Effect.scoped, ), - key: [], + key: ["uuid4", count], }) const [state] = R.useRefState(query.state) @@ -34,6 +37,17 @@ function RouteComponent() { return ( + + {AsyncData.match(state, { NoData: () => "No data yet", -- 2.49.1 From f99d18b8463fd26f7014d2d4e8c2f23754a04977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 03:15:43 +0100 Subject: [PATCH 084/101] Cleanup fix --- packages/example/src/routes/query.tsx | 12 +++++- .../extension-query/src/QueryExtension.ts | 14 +++++-- packages/extension-query/src/QueryRunner.ts | 42 ++++++++++++------- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index 07387ac..79b51a9 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -21,13 +21,23 @@ function RouteComponent() { const query = R.useQuery({ query: () => Console.log(`Querying ${ count } IDs...`).pipe( - // Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Result)), Effect.scoped, ), + // query: () => Console.log(`Creating ${ count } IDs...`).pipe( + // Effect.andThen(Effect.sleep("500 millis")), + // Effect.andThen(pipe( + // Array.range(1, count), + // Array.map(() => makeUuid4), + // Effect.all, + // )), + // Effect.flatMap(Schema.decode(Result)), + // Effect.provide(GetRandomValues.CryptoRandom), + // ), key: ["uuid4", count], }) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 8ad003f..1aa807d 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -21,14 +21,20 @@ export const QueryExtension = ReffuseExtension.make(() => ({ this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, ): UseQueryResult { + const runSync = this.useRunSync() + const runner = this.useMemo(() => QueryRunner.make({ query: props.query() }), []) - this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Ref.set(runner.queryRef, props.query())), - Effect.andThen(runner.forkFetch), - ), [runner, ...props.key]) + React.useEffect(() => { + Ref.set(runner.queryRef, props.query()).pipe( + Effect.andThen(runner.forkFetch), + runSync, + ) + + return () => { runSync(runner.forkInterrupt) } + }, [runner, ...props.key]) this.useFork(() => runner.refreshOnWindowFocus, [runner]) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 2a75a70..e5857bf 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -31,17 +31,28 @@ export const make = ( const interrupt = fiberRef.pipe( Effect.flatMap(Option.match({ - onSome: Fiber.interrupt, + onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( + Effect.andThen(Fiber.interrupt(fiber)) + ), onNone: () => Effect.void, })) ) - const forkInterrupt = Effect.forkDaemon(interrupt) + const forkInterrupt = fiberRef.pipe( + Effect.flatMap(Option.match({ + onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( + Effect.andThen(Fiber.interrupt(fiber).pipe( + Effect.asVoid, + Effect.forkDaemon, + )) + ), + onNone: () => Effect.forkDaemon(Effect.void), + })) + ) const forkFetch = interrupt.pipe( Effect.andThen( - Effect.addFinalizer(() => Ref.set(fiberRef, Option.none())).pipe( - Effect.andThen(Ref.set(stateRef, AsyncData.loading())), + Ref.set(stateRef, AsyncData.loading()).pipe( Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), @@ -49,14 +60,14 @@ export const make = ( }), Effect.provide(context), - Effect.scoped, Effect.fork, ) ), Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber)).pipe( - Effect.andThen(Fiber.join(fiber)) + Effect.andThen(Fiber.join(fiber)), + Effect.andThen(Ref.set(fiberRef, Option.none())), ) ), @@ -65,14 +76,13 @@ export const make = ( const forkRefresh = interrupt.pipe( Effect.andThen( - Effect.addFinalizer(() => Ref.set(fiberRef, Option.none())).pipe( - Effect.andThen(Ref.update(stateRef, previous => { - if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) - return AsyncData.refreshing(previous) - if (AsyncData.isRefreshing(previous)) - return AsyncData.refreshing(previous.previous) - return AsyncData.loading() - })), + Ref.update(stateRef, previous => { + if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) + return AsyncData.refreshing(previous) + if (AsyncData.isRefreshing(previous)) + return AsyncData.refreshing(previous.previous) + return AsyncData.loading() + }).pipe( Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), @@ -80,14 +90,14 @@ export const make = ( }), Effect.provide(context), - Effect.scoped, Effect.fork, ) ), Effect.flatMap(fiber => Ref.set(fiberRef, Option.some(fiber)).pipe( - Effect.andThen(Fiber.join(fiber)) + Effect.andThen(Fiber.join(fiber)), + Effect.andThen(Ref.set(fiberRef, Option.none())), ) ), -- 2.49.1 From 3bc0cc6586ddeff55377ec4a01389ca46d6e4102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 03:31:21 +0100 Subject: [PATCH 085/101] Cleanup --- packages/example/src/routes/query.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query.tsx index 79b51a9..b63f0db 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query.tsx @@ -28,16 +28,6 @@ function RouteComponent() { Effect.flatMap(Schema.decodeUnknown(Result)), Effect.scoped, ), - // query: () => Console.log(`Creating ${ count } IDs...`).pipe( - // Effect.andThen(Effect.sleep("500 millis")), - // Effect.andThen(pipe( - // Array.range(1, count), - // Array.map(() => makeUuid4), - // Effect.all, - // )), - // Effect.flatMap(Schema.decode(Result)), - // Effect.provide(GetRandomValues.CryptoRandom), - // ), key: ["uuid4", count], }) -- 2.49.1 From 7bebc39a87f6d4dd1e4174fe7deaf42e48faeab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 17:22:27 +0100 Subject: [PATCH 086/101] Fix --- packages/extension-query/src/QueryExtension.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 1aa807d..9675327 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, Ref, SubscriptionRef } from "effect" +import { Effect, ExecutionStrategy, Fiber, Ref, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -27,14 +27,10 @@ export const QueryExtension = ReffuseExtension.make(() => ({ query: props.query() }), []) - React.useEffect(() => { - Ref.set(runner.queryRef, props.query()).pipe( - Effect.andThen(runner.forkFetch), - runSync, - ) - - return () => { runSync(runner.forkInterrupt) } - }, [runner, ...props.key]) + this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( + Effect.andThen(Ref.set(runner.queryRef, props.query())), + Effect.andThen(runner.forkFetch), + ), [runner, ...props.key], { finalizerExecutionStrategy: ExecutionStrategy.parallel }) this.useFork(() => runner.refreshOnWindowFocus, [runner]) -- 2.49.1 From 11fd4941c0d589a07789757fdecba1fb6b8f9fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 17:26:08 +0100 Subject: [PATCH 087/101] Fix --- packages/extension-query/src/QueryExtension.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 9675327..526077a 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -21,8 +21,6 @@ export const QueryExtension = ReffuseExtension.make(() => ({ this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, ): UseQueryResult { - const runSync = this.useRunSync() - const runner = this.useMemo(() => QueryRunner.make({ query: props.query() }), []) -- 2.49.1 From fad61afce7e51d72efff1650297c204a5efdcc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 17:32:30 +0100 Subject: [PATCH 088/101] Fix --- packages/extension-query/src/QueryRunner.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index e5857bf..f17d226 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -53,7 +53,8 @@ export const make = ( const forkFetch = interrupt.pipe( Effect.andThen( Ref.set(stateRef, AsyncData.loading()).pipe( - Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.andThen(queryRef), + Effect.flatMap(identity), Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), @@ -83,7 +84,8 @@ export const make = ( return AsyncData.refreshing(previous.previous) return AsyncData.loading() }).pipe( - Effect.andThen(queryRef.pipe(Effect.flatMap(identity))), + Effect.andThen(queryRef), + Effect.flatMap(identity), Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), -- 2.49.1 From d239a11cdcb7c10d4e3634eb8d3878da25985c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 6 Mar 2025 20:00:40 +0100 Subject: [PATCH 089/101] Service query --- .../example/src/query/services/Uuid4Query.ts | 2 +- packages/example/src/routeTree.gen.ts | 83 ++++++++----------- packages/example/src/routes/__root.tsx | 2 +- packages/example/src/routes/query/service.tsx | 27 ++++-- .../routes/{query.tsx => query/usequery.tsx} | 4 +- .../extension-query/src/QueryExtension.ts | 13 ++- 6 files changed, 72 insertions(+), 59 deletions(-) rename packages/example/src/routes/{query.tsx => query/usequery.tsx} (97%) diff --git a/packages/example/src/query/services/Uuid4Query.ts b/packages/example/src/query/services/Uuid4Query.ts index ab9d4cf..08905a2 100644 --- a/packages/example/src/query/services/Uuid4Query.ts +++ b/packages/example/src/query/services/Uuid4Query.ts @@ -3,7 +3,7 @@ import { QueryService } from "@reffuse/extension-query" import { Console, Effect, ParseResult, Schema } from "effect" -export const Result = Schema.Tuple(Schema.String) +export const Result = Schema.Array(Schema.String) export class Uuid4Query extends QueryService.Tag("Uuid4Query") rootRoute, } as any) -const QueryRoute = QueryImport.update({ - id: '/query', - path: '/query', - getParentRoute: () => rootRoute, -} as any) - const PromiseRoute = PromiseImport.update({ id: '/promise', path: '/promise', @@ -71,10 +65,16 @@ const IndexRoute = IndexImport.update({ getParentRoute: () => rootRoute, } as any) +const QueryUsequeryRoute = QueryUsequeryImport.update({ + id: '/query/usequery', + path: '/query/usequery', + getParentRoute: () => rootRoute, +} as any) + const QueryServiceRoute = QueryServiceImport.update({ - id: '/service', - path: '/service', - getParentRoute: () => QueryRoute, + id: '/query/service', + path: '/query/service', + getParentRoute: () => rootRoute, } as any) // Populate the FileRoutesByPath interface @@ -116,13 +116,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PromiseImport parentRoute: typeof rootRoute } - '/query': { - id: '/query' - path: '/query' - fullPath: '/query' - preLoaderRoute: typeof QueryImport - parentRoute: typeof rootRoute - } '/tests': { id: '/tests' path: '/tests' @@ -139,36 +132,33 @@ declare module '@tanstack/react-router' { } '/query/service': { id: '/query/service' - path: '/service' + path: '/query/service' fullPath: '/query/service' preLoaderRoute: typeof QueryServiceImport - parentRoute: typeof QueryImport + parentRoute: typeof rootRoute + } + '/query/usequery': { + id: '/query/usequery' + path: '/query/usequery' + fullPath: '/query/usequery' + preLoaderRoute: typeof QueryUsequeryImport + parentRoute: typeof rootRoute } } } // Create and export the route tree -interface QueryRouteChildren { - QueryServiceRoute: typeof QueryServiceRoute -} - -const QueryRouteChildren: QueryRouteChildren = { - QueryServiceRoute: QueryServiceRoute, -} - -const QueryRouteWithChildren = QueryRoute._addFileChildren(QueryRouteChildren) - export interface FileRoutesByFullPath { '/': typeof IndexRoute '/blank': typeof BlankRoute '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute '/query/service': typeof QueryServiceRoute + '/query/usequery': typeof QueryUsequeryRoute } export interface FileRoutesByTo { @@ -177,10 +167,10 @@ export interface FileRoutesByTo { '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute '/query/service': typeof QueryServiceRoute + '/query/usequery': typeof QueryUsequeryRoute } export interface FileRoutesById { @@ -190,10 +180,10 @@ export interface FileRoutesById { '/count': typeof CountRoute '/lazyref': typeof LazyrefRoute '/promise': typeof PromiseRoute - '/query': typeof QueryRouteWithChildren '/tests': typeof TestsRoute '/time': typeof TimeRoute '/query/service': typeof QueryServiceRoute + '/query/usequery': typeof QueryUsequeryRoute } export interface FileRouteTypes { @@ -204,10 +194,10 @@ export interface FileRouteTypes { | '/count' | '/lazyref' | '/promise' - | '/query' | '/tests' | '/time' | '/query/service' + | '/query/usequery' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -215,10 +205,10 @@ export interface FileRouteTypes { | '/count' | '/lazyref' | '/promise' - | '/query' | '/tests' | '/time' | '/query/service' + | '/query/usequery' id: | '__root__' | '/' @@ -226,10 +216,10 @@ export interface FileRouteTypes { | '/count' | '/lazyref' | '/promise' - | '/query' | '/tests' | '/time' | '/query/service' + | '/query/usequery' fileRoutesById: FileRoutesById } @@ -239,9 +229,10 @@ export interface RootRouteChildren { CountRoute: typeof CountRoute LazyrefRoute: typeof LazyrefRoute PromiseRoute: typeof PromiseRoute - QueryRoute: typeof QueryRouteWithChildren TestsRoute: typeof TestsRoute TimeRoute: typeof TimeRoute + QueryServiceRoute: typeof QueryServiceRoute + QueryUsequeryRoute: typeof QueryUsequeryRoute } const rootRouteChildren: RootRouteChildren = { @@ -250,9 +241,10 @@ const rootRouteChildren: RootRouteChildren = { CountRoute: CountRoute, LazyrefRoute: LazyrefRoute, PromiseRoute: PromiseRoute, - QueryRoute: QueryRouteWithChildren, TestsRoute: TestsRoute, TimeRoute: TimeRoute, + QueryServiceRoute: QueryServiceRoute, + QueryUsequeryRoute: QueryUsequeryRoute, } export const routeTree = rootRoute @@ -270,9 +262,10 @@ export const routeTree = rootRoute "/count", "/lazyref", "/promise", - "/query", "/tests", - "/time" + "/time", + "/query/service", + "/query/usequery" ] }, "/": { @@ -290,12 +283,6 @@ export const routeTree = rootRoute "/promise": { "filePath": "promise.tsx" }, - "/query": { - "filePath": "query.tsx", - "children": [ - "/query/service" - ] - }, "/tests": { "filePath": "tests.tsx" }, @@ -303,8 +290,10 @@ export const routeTree = rootRoute "filePath": "time.tsx" }, "/query/service": { - "filePath": "query/service.tsx", - "parent": "/query" + "filePath": "query/service.tsx" + }, + "/query/usequery": { + "filePath": "query/usequery.tsx" } } } diff --git a/packages/example/src/routes/__root.tsx b/packages/example/src/routes/__root.tsx index a02f201..3253372 100644 --- a/packages/example/src/routes/__root.tsx +++ b/packages/example/src/routes/__root.tsx @@ -20,7 +20,7 @@ function Root() { Count Tests Promise - Query + Query Blank diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index 638dbe3..38a6b38 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -2,8 +2,9 @@ import { QueryContext } from "@/query/reffuse" import { Uuid4Query } from "@/query/services" import { Uuid4QueryService } from "@/query/views/Uuid4QueryService" import { R } from "@/reffuse" +import { HttpClient } from "@effect/platform" import { createFileRoute } from "@tanstack/react-router" -import { Layer } from "effect" +import { Console, Effect, Schema } from "effect" import { useMemo } from "react" @@ -12,12 +13,26 @@ export const Route = createFileRoute("/query/service")({ }) function RouteComponent() { - const context = R.useLayer() + // const context = R.useLayer() - const layer = useMemo(() => Layer.empty.pipe( - Layer.provideMerge(Uuid4Query.Uuid4QueryLive), - Layer.provide(context), - ), [context]) + // const layer = useMemo(() => Layer.empty.pipe( + // Layer.provideMerge(Uuid4Query.Uuid4QueryLive), + // Layer.provide(context), + // ), [context]) + + const query = R.useQuery({ + key: ["uuid4", 10], + query: () => Console.log(`Querying 10 IDs...`).pipe( + Effect.andThen(Effect.sleep("500 millis")), + Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/10`)), + HttpClient.withTracerPropagation(false), + Effect.flatMap(res => res.json), + Effect.flatMap(Schema.decodeUnknown(Uuid4Query.Result)), + Effect.scoped, + ), + }) + + const layer = useMemo(() => query.layer(Uuid4Query.Uuid4Query), [query]) return ( diff --git a/packages/example/src/routes/query.tsx b/packages/example/src/routes/query/usequery.tsx similarity index 97% rename from packages/example/src/routes/query.tsx rename to packages/example/src/routes/query/usequery.tsx index b63f0db..f2c58c8 100644 --- a/packages/example/src/routes/query.tsx +++ b/packages/example/src/routes/query/usequery.tsx @@ -7,7 +7,7 @@ import { Array, Console, Effect, flow, Option, Schema } from "effect" import { useState } from "react" -export const Route = createFileRoute("/query")({ +export const Route = createFileRoute("/query/usequery")({ component: RouteComponent }) @@ -20,6 +20,7 @@ function RouteComponent() { const [count, setCount] = useState(1) const query = R.useQuery({ + key: ["uuid4", count], query: () => Console.log(`Querying ${ count } IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), @@ -28,7 +29,6 @@ function RouteComponent() { Effect.flatMap(Schema.decodeUnknown(Result)), Effect.scoped, ), - key: ["uuid4", count], }) const [state] = R.useRefState(query.state) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 526077a..443d95c 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,18 +1,22 @@ import * as AsyncData from "@typed/async-data" -import { Effect, ExecutionStrategy, Fiber, Ref, SubscriptionRef } from "effect" +import { Context, Effect, ExecutionStrategy, Fiber, Layer, Ref, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" +import * as QueryService from "./QueryService.js" export interface UseQueryProps { - readonly query: () => Effect.Effect readonly key: React.DependencyList + readonly query: () => Effect.Effect } export interface UseQueryResult { readonly state: SubscriptionRef.SubscriptionRef> readonly refresh: Effect.Effect> + readonly layer: ( + tag: Context.TagClass> + ) => Layer.Layer } @@ -35,6 +39,11 @@ export const QueryExtension = ReffuseExtension.make(() => ({ return React.useMemo(() => ({ state: runner.stateRef, refresh: runner.forkRefresh, + + layer: tag => Layer.succeed(tag, { + state: runner.stateRef, + refresh: runner.forkRefresh, + }), }), [runner]) } })) -- 2.49.1 From cabceaffcd7374b30510b99f091986de7449b004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 7 Mar 2025 04:26:39 +0100 Subject: [PATCH 090/101] Key work --- .../extension-query/src/QueryExtension.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 443d95c..fe7dd1e 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Context, Effect, ExecutionStrategy, Fiber, Layer, Ref, SubscriptionRef } from "effect" +import { Array, Context, Effect, ExecutionStrategy, Fiber, Layer, Ref, Schema, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -7,8 +7,9 @@ import * as QueryService from "./QueryService.js" export interface UseQueryProps { - readonly key: React.DependencyList + readonly key: Stream.Stream | readonly unknown[] readonly query: () => Effect.Effect + readonly refreshOnWindowFocus?: boolean } export interface UseQueryResult { @@ -29,12 +30,26 @@ export const QueryExtension = ReffuseExtension.make(() => ({ query: props.query() }), []) - this.useEffect(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Ref.set(runner.queryRef, props.query())), - Effect.andThen(runner.forkFetch), - ), [runner, ...props.key], { finalizerExecutionStrategy: ExecutionStrategy.parallel }) + const key = React.useMemo(() => + (Array.isArray as (self: unknown) => self is readonly unknown[])(props.key) + ? props.key + : props.key, + [props.key]) - this.useFork(() => runner.refreshOnWindowFocus, [runner]) + this.useEffect( + () => Effect.addFinalizer(() => runner.forkInterrupt).pipe( + Effect.andThen(Ref.set(runner.queryRef, props.query())), + Effect.andThen(runner.forkFetch), + ), + + [runner, ...(Array.isArray(props.key) ? props.key : [])], + { finalizerExecutionStrategy: ExecutionStrategy.parallel }, + ) + + this.useFork(() => (props.refreshOnWindowFocus ?? true) + ? runner.refreshOnWindowFocus + : Effect.void, + [props.refreshOnWindowFocus, runner]) return React.useMemo(() => ({ state: runner.stateRef, -- 2.49.1 From 7935293bc3f81f74982e2d8f491b3ebd611792c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 7 Mar 2025 22:23:44 +0100 Subject: [PATCH 091/101] Query work --- .../example/src/query/services/Uuid4Query.ts | 15 +------- packages/example/src/routes/query/service.tsx | 2 +- .../example/src/routes/query/usequery.tsx | 2 +- packages/example/src/routes/tests.tsx | 21 +++++++++-- .../extension-query/src/QueryExtension.ts | 37 ++++++++----------- packages/extension-query/src/QueryRunner.ts | 13 ++++--- packages/extension-query/src/QueryService.ts | 33 ++++++++--------- packages/reffuse/src/ReffuseHelpers.ts | 15 +++++++- 8 files changed, 75 insertions(+), 63 deletions(-) diff --git a/packages/example/src/query/services/Uuid4Query.ts b/packages/example/src/query/services/Uuid4Query.ts index 08905a2..ffc2b36 100644 --- a/packages/example/src/query/services/Uuid4Query.ts +++ b/packages/example/src/query/services/Uuid4Query.ts @@ -1,6 +1,6 @@ -import { HttpClient, HttpClientError } from "@effect/platform" +import { HttpClientError } from "@effect/platform" import { QueryService } from "@reffuse/extension-query" -import { Console, Effect, ParseResult, Schema } from "effect" +import { ParseResult, Schema } from "effect" export const Result = Schema.Array(Schema.String) @@ -9,14 +9,3 @@ export class Uuid4Query extends QueryService.Tag("Uuid4Query")() {} - -export const Uuid4QueryLive = QueryService.layer(Uuid4Query, { - query: Console.log("Querying...").pipe( - Effect.andThen(Effect.sleep("500 millis")), - Effect.andThen(HttpClient.get("https://www.uuidtools.com/api/generate/v4")), - HttpClient.withTracerPropagation(false), - Effect.flatMap(res => res.json), - Effect.flatMap(Schema.decodeUnknown(Result)), - Effect.scoped, - ) -}) diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index 38a6b38..e151872 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -21,7 +21,7 @@ function RouteComponent() { // ), [context]) const query = R.useQuery({ - key: ["uuid4", 10], + key: R.useStreamFromValues(["uuid4", 10]), query: () => Console.log(`Querying 10 IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/10`)), diff --git a/packages/example/src/routes/query/usequery.tsx b/packages/example/src/routes/query/usequery.tsx index f2c58c8..7fe1a35 100644 --- a/packages/example/src/routes/query/usequery.tsx +++ b/packages/example/src/routes/query/usequery.tsx @@ -20,7 +20,7 @@ function RouteComponent() { const [count, setCount] = useState(1) const query = R.useQuery({ - key: ["uuid4", count], + key: R.useStreamFromValues(["uuid4", count]), query: () => Console.log(`Querying ${ count } IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx index 93e791e..884b5f7 100644 --- a/packages/example/src/routes/tests.tsx +++ b/packages/example/src/routes/tests.tsx @@ -1,7 +1,9 @@ import { R } from "@/reffuse" -import { Button } from "@radix-ui/themes" +import { Button, Flex } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" -import { Console, Effect } from "effect" +import { GetRandomValues, makeUuid4 } from "@typed/id" +import { Console, Effect, Stream } from "effect" +import { useState } from "react" export const Route = createFileRoute("/tests")({ @@ -20,12 +22,25 @@ function RouteComponent() { Effect.delay("1 second"), ), []) + const [reactValue, setReactValue] = useState("initial") + const reactValueStream = R.useStreamFromValues([reactValue]) + R.useFork(() => Stream.runForEach(reactValueStream, Console.log), [reactValueStream]) + + const logValue = R.useCallbackSync(Effect.fn(function*(value: string) { yield* Effect.log(value) }), []) + const generateUuid = R.useCallbackSync(() => makeUuid4.pipe( + Effect.provide(GetRandomValues.CryptoRandom), + Effect.map(setReactValue), + ), []) + return ( - + + + + ) } diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index fe7dd1e..cdc0d7e 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,13 +1,13 @@ import * as AsyncData from "@typed/async-data" -import { Array, Context, Effect, ExecutionStrategy, Fiber, Layer, Ref, Schema, Stream, SubscriptionRef } from "effect" +import { Context, Effect, Fiber, Layer, Ref, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" import * as QueryService from "./QueryService.js" -export interface UseQueryProps { - readonly key: Stream.Stream | readonly unknown[] +export interface UseQueryProps { + readonly key: Stream.Stream readonly query: () => Effect.Effect readonly refreshOnWindowFocus?: boolean } @@ -22,29 +22,22 @@ export interface UseQueryResult { export const QueryExtension = ReffuseExtension.make(() => ({ - useQuery( + useQuery( this: ReffuseHelpers.ReffuseHelpers, - props: UseQueryProps, + props: UseQueryProps, ): UseQueryResult { const runner = this.useMemo(() => QueryRunner.make({ - query: props.query() - }), []) + key: props.key, + query: props.query(), + }), [props.key]) - const key = React.useMemo(() => - (Array.isArray as (self: unknown) => self is readonly unknown[])(props.key) - ? props.key - : props.key, - [props.key]) - - this.useEffect( - () => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Ref.set(runner.queryRef, props.query())), - Effect.andThen(runner.forkFetch), - ), - - [runner, ...(Array.isArray(props.key) ? props.key : [])], - { finalizerExecutionStrategy: ExecutionStrategy.parallel }, - ) + this.useFork(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( + Effect.andThen(Stream.runForEach(runner.key, () => + Ref.set(runner.queryRef, props.query()).pipe( + Effect.andThen(runner.forkFetch) + ) + )) + ), [runner]) this.useFork(() => (props.refreshOnWindowFocus ?? true) ? runner.refreshOnWindowFocus diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index f17d226..97e3d35 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -3,7 +3,8 @@ import * as AsyncData from "@typed/async-data" import { Effect, Fiber, identity, Option, Ref, Stream, SubscriptionRef } from "effect" -export interface QueryRunner { +export interface QueryRunner { + readonly key: Stream.Stream readonly queryRef: SubscriptionRef.SubscriptionRef> readonly stateRef: SubscriptionRef.SubscriptionRef> readonly fiberRef: SubscriptionRef.SubscriptionRef>> @@ -16,13 +17,14 @@ export interface QueryRunner { } -export interface MakeProps { +export interface MakeProps { + readonly key: Stream.Stream readonly query: Effect.Effect } -export const make = ( - props: MakeProps -): Effect.Effect, never, R> => Effect.gen(function*() { +export const make = ( + props: MakeProps +): Effect.Effect, never, R> => Effect.gen(function*() { const context = yield* Effect.context() const queryRef = yield* SubscriptionRef.make(props.query) @@ -112,6 +114,7 @@ export const make = ( ) return { + key: props.key, queryRef, stateRef, fiberRef, diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index 6dc92d7..a9a1e24 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -1,6 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Context, Effect, Fiber, Layer, SubscriptionRef } from "effect" -import * as QueryRunner from "./QueryRunner.js" +import { Effect, Fiber, SubscriptionRef } from "effect" export interface QueryService { @@ -13,20 +12,20 @@ export const Tag = (id: Id) => < >() => Effect.Tag(id)>() -export interface LayerProps { - readonly query: Effect.Effect -} +// export interface LayerProps { +// readonly query: Effect.Effect +// } -export const layer = ( - tag: Context.TagClass>, - props: LayerProps, -): Layer.Layer => Layer.effect(tag, Effect.gen(function*() { - const runner = yield* QueryRunner.make({ - query: props.query - }) +// export const layer = ( +// tag: Context.TagClass>, +// props: LayerProps, +// ): Layer.Layer => Layer.effect(tag, Effect.gen(function*() { +// const runner = yield* QueryRunner.make({ +// query: props.query +// }) - return { - state: runner.stateRef, - refresh: runner.forkRefresh, - } -})) +// return { +// state: runner.stateRef, +// refresh: runner.forkRefresh, +// } +// })) diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index bdb8858..4bb0216 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -1,4 +1,4 @@ -import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Layer, Pipeable, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Layer, Pipeable, Queue, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" @@ -407,6 +407,19 @@ export abstract class ReffuseHelpers { return [reactStateValue, setValue] } + + useStreamFromValues( + this: ReffuseHelpers, + values: A, + ): Stream.Stream { + const [queue, stream] = this.useMemo(() => Queue.unbounded().pipe( + Effect.map(queue => [queue, Stream.fromQueue(queue)] as const) + ), []) + + this.useEffect(() => Queue.offer(queue, values), values) + + return stream + } } -- 2.49.1 From 5ac3a932d9c287fe9141b992d0b3978b4b8661bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 7 Mar 2025 23:17:32 +0100 Subject: [PATCH 092/101] Query work --- packages/extension-query/src/QueryExtension.ts | 2 +- packages/extension-query/src/QueryRunner.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index cdc0d7e..8b0c6dd 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -8,7 +8,7 @@ import * as QueryService from "./QueryService.js" export interface UseQueryProps { readonly key: Stream.Stream - readonly query: () => Effect.Effect + readonly query: (key: K) => Effect.Effect readonly refreshOnWindowFocus?: boolean } diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 97e3d35..6fb7da0 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -5,10 +5,12 @@ import { Effect, Fiber, identity, Option, Ref, Stream, SubscriptionRef } from "e export interface QueryRunner { readonly key: Stream.Stream - readonly queryRef: SubscriptionRef.SubscriptionRef> + readonly query: (key: K) => Effect.Effect + readonly stateRef: SubscriptionRef.SubscriptionRef> readonly fiberRef: SubscriptionRef.SubscriptionRef>> + readonly interrupt: Effect.Effect readonly forkInterrupt: Effect.Effect> readonly forkFetch: Effect.Effect> readonly forkRefresh: Effect.Effect> @@ -19,7 +21,7 @@ export interface QueryRunner { export interface MakeProps { readonly key: Stream.Stream - readonly query: Effect.Effect + readonly query: (key: K) => Effect.Effect } export const make = ( @@ -27,7 +29,6 @@ export const make = ( ): Effect.Effect, never, R> => Effect.gen(function*() { const context = yield* Effect.context() - const queryRef = yield* SubscriptionRef.make(props.query) const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) const fiberRef = yield* SubscriptionRef.make(Option.none>()) @@ -86,8 +87,8 @@ export const make = ( return AsyncData.refreshing(previous.previous) return AsyncData.loading() }).pipe( - Effect.andThen(queryRef), - Effect.flatMap(identity), + + Effect.andThen(props.query()), Effect.matchCauseEffect({ onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), @@ -115,7 +116,8 @@ export const make = ( return { key: props.key, - queryRef, + query: props.query, + stateRef, fiberRef, -- 2.49.1 From da2a32001cc6230a8a944f1995859b0d18bc7ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sat, 8 Mar 2025 01:56:50 +0100 Subject: [PATCH 093/101] Query work --- packages/extension-query/src/QueryRunner.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 6fb7da0..106f7e4 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -25,10 +25,11 @@ export interface MakeProps { } export const make = ( - props: MakeProps + { key, query }: MakeProps ): Effect.Effect, never, R> => Effect.gen(function*() { const context = yield* Effect.context() + const currentKeyRef = yield* SubscriptionRef.make(Option.none()) const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) const fiberRef = yield* SubscriptionRef.make(Option.none>()) -- 2.49.1 From c689778cea295dea48cf95ec99406b8668b4bbef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 9 Mar 2025 18:08:52 +0100 Subject: [PATCH 094/101] Working query --- .../example/src/routes/query/usequery.tsx | 2 +- .../extension-query/src/QueryExtension.ts | 22 ++++---- packages/extension-query/src/QueryRunner.ts | 55 ++++++++++++------- packages/extension-query/src/QueryService.ts | 4 +- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/packages/example/src/routes/query/usequery.tsx b/packages/example/src/routes/query/usequery.tsx index 7fe1a35..1f76770 100644 --- a/packages/example/src/routes/query/usequery.tsx +++ b/packages/example/src/routes/query/usequery.tsx @@ -21,7 +21,7 @@ function RouteComponent() { const query = R.useQuery({ key: R.useStreamFromValues(["uuid4", count]), - query: () => Console.log(`Querying ${ count } IDs...`).pipe( + query: ([, count]) => Console.log(`Querying ${ count } IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), HttpClient.withTracerPropagation(false), diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 8b0c6dd..0d0cccd 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,5 +1,5 @@ import * as AsyncData from "@typed/async-data" -import { Context, Effect, Fiber, Layer, Ref, Stream, SubscriptionRef } from "effect" +import { type Cause, Context, Effect, Fiber, Layer, Stream, SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -14,7 +14,7 @@ export interface UseQueryProps { export interface UseQueryResult { readonly state: SubscriptionRef.SubscriptionRef> - readonly refresh: Effect.Effect> + readonly refresh: Effect.Effect> readonly layer: ( tag: Context.TagClass> ) => Layer.Layer @@ -28,16 +28,18 @@ export const QueryExtension = ReffuseExtension.make(() => ({ ): UseQueryResult { const runner = this.useMemo(() => QueryRunner.make({ key: props.key, - query: props.query(), + query: props.query, }), [props.key]) - this.useFork(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - Effect.andThen(Stream.runForEach(runner.key, () => - Ref.set(runner.queryRef, props.query()).pipe( - Effect.andThen(runner.forkFetch) - ) - )) - ), [runner]) + // this.useFork(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( + // Effect.andThen(Stream.runForEach(runner.key, () => + // Ref.set(runner.queryRef, props.query()).pipe( + // Effect.andThen(runner.forkFetch) + // ) + // )) + // ), [runner]) + + this.useFork(() => runner.fetchOnKeyChange, [runner]) this.useFork(() => (props.refreshOnWindowFocus ?? true) ? runner.refreshOnWindowFocus diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 106f7e4..2a517a4 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -1,6 +1,6 @@ import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, identity, Option, Ref, Stream, SubscriptionRef } from "effect" +import { type Cause, Effect, Fiber, identity, Option, Ref, Scope, Stream, SubscriptionRef } from "effect" export interface QueryRunner { @@ -8,13 +8,13 @@ export interface QueryRunner { readonly query: (key: K) => Effect.Effect readonly stateRef: SubscriptionRef.SubscriptionRef> - readonly fiberRef: SubscriptionRef.SubscriptionRef>> + readonly fiberRef: SubscriptionRef.SubscriptionRef>> - readonly interrupt: Effect.Effect - readonly forkInterrupt: Effect.Effect> - readonly forkFetch: Effect.Effect> - readonly forkRefresh: Effect.Effect> + readonly forkInterrupt: Effect.Effect> + readonly forkFetch: Effect.Effect> + readonly forkRefresh: Effect.Effect> + readonly fetchOnKeyChange: Effect.Effect readonly refreshOnWindowFocus: Effect.Effect } @@ -29,9 +29,9 @@ export const make = ( ): Effect.Effect, never, R> => Effect.gen(function*() { const context = yield* Effect.context() - const currentKeyRef = yield* SubscriptionRef.make(Option.none()) + const latestKeyRef = yield* SubscriptionRef.make(Option.none()) const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) - const fiberRef = yield* SubscriptionRef.make(Option.none>()) + const fiberRef = yield* SubscriptionRef.make(Option.none>()) const interrupt = fiberRef.pipe( Effect.flatMap(Option.match({ @@ -57,12 +57,14 @@ export const make = ( const forkFetch = interrupt.pipe( Effect.andThen( Ref.set(stateRef, AsyncData.loading()).pipe( - Effect.andThen(queryRef), + Effect.andThen(latestKeyRef), Effect.flatMap(identity), - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }), + Effect.flatMap(key => query(key).pipe( + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }) + )), Effect.provide(context), Effect.fork, @@ -88,12 +90,14 @@ export const make = ( return AsyncData.refreshing(previous.previous) return AsyncData.loading() }).pipe( - - Effect.andThen(props.query()), - Effect.matchCauseEffect({ - onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), - onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), - }), + Effect.andThen(latestKeyRef), + Effect.flatMap(identity), + Effect.flatMap(key => query(key).pipe( + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }) + )), Effect.provide(context), Effect.fork, @@ -110,14 +114,22 @@ export const make = ( Effect.forkDaemon, ) + const fetchOnKeyChange = Effect.addFinalizer(() => interrupt).pipe( + Effect.andThen(Stream.runForEach(key, latestKey => + Ref.set(latestKeyRef, Option.some(latestKey)).pipe( + Effect.andThen(forkFetch) + ) + )) + ) + const refreshOnWindowFocus = Stream.runForEach( BrowserStream.fromEventListenerWindow("focus"), () => forkRefresh, ) return { - key: props.key, - query: props.query, + key, + query, stateRef, fiberRef, @@ -126,6 +138,7 @@ export const make = ( forkFetch, forkRefresh, + fetchOnKeyChange, refreshOnWindowFocus, } }) diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index a9a1e24..e872672 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -1,10 +1,10 @@ import * as AsyncData from "@typed/async-data" -import { Effect, Fiber, SubscriptionRef } from "effect" +import { type Cause, Effect, Fiber, SubscriptionRef } from "effect" export interface QueryService { readonly state: SubscriptionRef.SubscriptionRef> - readonly refresh: Effect.Effect> + readonly refresh: Effect.Effect> } export const Tag = (id: Id) => < -- 2.49.1 From 1ed73dc3ac9c1fdb59190ab4cd660517258a1d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 9 Mar 2025 18:21:35 +0100 Subject: [PATCH 095/101] Cleanup --- packages/example/src/routes/query/service.tsx | 4 ++-- packages/extension-query/src/QueryExtension.ts | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index e151872..5ce597a 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -22,9 +22,9 @@ function RouteComponent() { const query = R.useQuery({ key: R.useStreamFromValues(["uuid4", 10]), - query: () => Console.log(`Querying 10 IDs...`).pipe( + query: ([, count]) => Console.log(`Querying ${ count } IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), - Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/10`)), + Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), HttpClient.withTracerPropagation(false), Effect.flatMap(res => res.json), Effect.flatMap(Schema.decodeUnknown(Uuid4Query.Result)), diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 0d0cccd..e1f16f0 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -31,14 +31,6 @@ export const QueryExtension = ReffuseExtension.make(() => ({ query: props.query, }), [props.key]) - // this.useFork(() => Effect.addFinalizer(() => runner.forkInterrupt).pipe( - // Effect.andThen(Stream.runForEach(runner.key, () => - // Ref.set(runner.queryRef, props.query()).pipe( - // Effect.andThen(runner.forkFetch) - // ) - // )) - // ), [runner]) - this.useFork(() => runner.fetchOnKeyChange, [runner]) this.useFork(() => (props.refreshOnWindowFocus ?? true) -- 2.49.1 From 1fd2a9ffbe037e0e652331b8c43db5bca000558d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 9 Mar 2025 18:35:48 +0100 Subject: [PATCH 096/101] Cleanup --- packages/extension-query/src/QueryExtension.ts | 6 +++--- packages/extension-query/src/QueryRunner.ts | 2 +- packages/extension-query/src/QueryService.ts | 4 ++-- packages/reffuse/src/ReffuseHelpers.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index e1f16f0..49967b2 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,9 +1,9 @@ -import * as AsyncData from "@typed/async-data" -import { type Cause, Context, Effect, Fiber, Layer, Stream, SubscriptionRef } from "effect" +import type * as AsyncData from "@typed/async-data" +import { type Cause, type Context, Effect, type Fiber, Layer, type Stream, type SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" -import * as QueryService from "./QueryService.js" +import type * as QueryService from "./QueryService.js" export interface UseQueryProps { diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 2a517a4..812edbd 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -1,6 +1,6 @@ import { BrowserStream } from "@effect/platform-browser" import * as AsyncData from "@typed/async-data" -import { type Cause, Effect, Fiber, identity, Option, Ref, Scope, Stream, SubscriptionRef } from "effect" +import { type Cause, Effect, Fiber, identity, Option, Ref, type Scope, Stream, SubscriptionRef } from "effect" export interface QueryRunner { diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index e872672..fd047bc 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -1,5 +1,5 @@ -import * as AsyncData from "@typed/async-data" -import { type Cause, Effect, Fiber, SubscriptionRef } from "effect" +import type * as AsyncData from "@typed/async-data" +import { type Cause, Effect, type Fiber, type SubscriptionRef } from "effect" export interface QueryService { diff --git a/packages/reffuse/src/ReffuseHelpers.ts b/packages/reffuse/src/ReffuseHelpers.ts index 4bb0216..2f4f449 100644 --- a/packages/reffuse/src/ReffuseHelpers.ts +++ b/packages/reffuse/src/ReffuseHelpers.ts @@ -1,4 +1,4 @@ -import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, Layer, Pipeable, Queue, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import { type Context, Effect, ExecutionStrategy, Exit, type Fiber, type Layer, Pipeable, Queue, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import * as React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" -- 2.49.1 From 7021e604ed0f391ff605193f9e5e48082750811c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 9 Mar 2025 19:14:20 +0100 Subject: [PATCH 097/101] Cleanup --- packages/example/src/routes/query/service.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index 5ce597a..71b97a5 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -13,13 +13,6 @@ export const Route = createFileRoute("/query/service")({ }) function RouteComponent() { - // const context = R.useLayer() - - // const layer = useMemo(() => Layer.empty.pipe( - // Layer.provideMerge(Uuid4Query.Uuid4QueryLive), - // Layer.provide(context), - // ), [context]) - const query = R.useQuery({ key: R.useStreamFromValues(["uuid4", 10]), query: ([, count]) => Console.log(`Querying ${ count } IDs...`).pipe( -- 2.49.1 From be8098fb7d7f8b20e6caacfd7bfa6038f7000871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 10 Mar 2025 01:56:11 +0100 Subject: [PATCH 098/101] Query work --- packages/example/src/query/services/Uuid4Query.ts | 1 + packages/example/src/routes/query/service.tsx | 2 +- packages/extension-query/src/QueryExtension.ts | 10 +++++++--- packages/extension-query/src/QueryService.ts | 9 +++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/example/src/query/services/Uuid4Query.ts b/packages/example/src/query/services/Uuid4Query.ts index ffc2b36..a7336bd 100644 --- a/packages/example/src/query/services/Uuid4Query.ts +++ b/packages/example/src/query/services/Uuid4Query.ts @@ -6,6 +6,7 @@ import { ParseResult, Schema } from "effect" export const Result = Schema.Array(Schema.String) export class Uuid4Query extends QueryService.Tag("Uuid4Query")() {} diff --git a/packages/example/src/routes/query/service.tsx b/packages/example/src/routes/query/service.tsx index 71b97a5..6a926a8 100644 --- a/packages/example/src/routes/query/service.tsx +++ b/packages/example/src/routes/query/service.tsx @@ -14,7 +14,7 @@ export const Route = createFileRoute("/query/service")({ function RouteComponent() { const query = R.useQuery({ - key: R.useStreamFromValues(["uuid4", 10]), + key: R.useStreamFromValues(["uuid4", 10 as number]), query: ([, count]) => Console.log(`Querying ${ count } IDs...`).pipe( Effect.andThen(Effect.sleep("500 millis")), Effect.andThen(HttpClient.get(`https://www.uuidtools.com/api/generate/v4/count/${ count }`)), diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index 49967b2..acd5cf9 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -12,11 +12,13 @@ export interface UseQueryProps { readonly refreshOnWindowFocus?: boolean } -export interface UseQueryResult { +export interface UseQueryResult { + readonly keyStream: Stream.Stream readonly state: SubscriptionRef.SubscriptionRef> readonly refresh: Effect.Effect> + readonly layer: ( - tag: Context.TagClass> + tag: Context.TagClass> ) => Layer.Layer } @@ -25,7 +27,7 @@ export const QueryExtension = ReffuseExtension.make(() => ({ useQuery( this: ReffuseHelpers.ReffuseHelpers, props: UseQueryProps, - ): UseQueryResult { + ): UseQueryResult { const runner = this.useMemo(() => QueryRunner.make({ key: props.key, query: props.query, @@ -39,10 +41,12 @@ export const QueryExtension = ReffuseExtension.make(() => ({ [props.refreshOnWindowFocus, runner]) return React.useMemo(() => ({ + keyStream: props.key, state: runner.stateRef, refresh: runner.forkRefresh, layer: tag => Layer.succeed(tag, { + keyStream: props.key, state: runner.stateRef, refresh: runner.forkRefresh, }), diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index fd047bc..8025cb6 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -1,15 +1,16 @@ import type * as AsyncData from "@typed/async-data" -import { type Cause, Effect, type Fiber, type SubscriptionRef } from "effect" +import { type Cause, Effect, type Fiber, type Stream, type SubscriptionRef } from "effect" -export interface QueryService { +export interface QueryService { + readonly keyStream: Stream.Stream readonly state: SubscriptionRef.SubscriptionRef> readonly refresh: Effect.Effect> } export const Tag = (id: Id) => < - Self, A, E = never, ->() => Effect.Tag(id)>() + Self, K extends readonly unknown[], A, E = never, +>() => Effect.Tag(id)>() // export interface LayerProps { -- 2.49.1 From 94a0864132fdccd5e9578bbf48a11d46656c7d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 10 Mar 2025 18:37:45 +0100 Subject: [PATCH 099/101] Query refactoring --- packages/extension-query/src/QueryExtension.ts | 8 ++++---- packages/extension-query/src/QueryRunner.ts | 4 ++-- packages/extension-query/src/QueryService.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index acd5cf9..79c0a89 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -1,5 +1,5 @@ import type * as AsyncData from "@typed/async-data" -import { type Cause, type Context, Effect, type Fiber, Layer, type Stream, type SubscriptionRef } from "effect" +import { type Cause, type Context, Effect, type Fiber, Layer, type Option, type Stream, type SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" import * as QueryRunner from "./QueryRunner.js" @@ -13,7 +13,7 @@ export interface UseQueryProps { } export interface UseQueryResult { - readonly keyStream: Stream.Stream + readonly latestKey: SubscriptionRef.SubscriptionRef> readonly state: SubscriptionRef.SubscriptionRef> readonly refresh: Effect.Effect> @@ -41,12 +41,12 @@ export const QueryExtension = ReffuseExtension.make(() => ({ [props.refreshOnWindowFocus, runner]) return React.useMemo(() => ({ - keyStream: props.key, + latestKey: runner.latestKeyRef, state: runner.stateRef, refresh: runner.forkRefresh, layer: tag => Layer.succeed(tag, { - keyStream: props.key, + latestKey: runner.latestKeyRef, state: runner.stateRef, refresh: runner.forkRefresh, }), diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index 812edbd..a403672 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -4,9 +4,9 @@ import { type Cause, Effect, Fiber, identity, Option, Ref, type Scope, Stream, S export interface QueryRunner { - readonly key: Stream.Stream readonly query: (key: K) => Effect.Effect + readonly latestKeyRef: SubscriptionRef.SubscriptionRef> readonly stateRef: SubscriptionRef.SubscriptionRef> readonly fiberRef: SubscriptionRef.SubscriptionRef>> @@ -128,9 +128,9 @@ export const make = ( ) return { - key, query, + latestKeyRef, stateRef, fiberRef, diff --git a/packages/extension-query/src/QueryService.ts b/packages/extension-query/src/QueryService.ts index 8025cb6..33fce17 100644 --- a/packages/extension-query/src/QueryService.ts +++ b/packages/extension-query/src/QueryService.ts @@ -1,9 +1,9 @@ import type * as AsyncData from "@typed/async-data" -import { type Cause, Effect, type Fiber, type Stream, type SubscriptionRef } from "effect" +import { type Cause, Effect, type Fiber, type Option, type SubscriptionRef } from "effect" export interface QueryService { - readonly keyStream: Stream.Stream + readonly latestKey: SubscriptionRef.SubscriptionRef> readonly state: SubscriptionRef.SubscriptionRef> readonly refresh: Effect.Effect> } -- 2.49.1 From 8772e25ff5cfe893f114369744bdf2c92cad8572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Mon, 10 Mar 2025 18:44:08 +0100 Subject: [PATCH 100/101] CI update --- .gitea/workflows/publish.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml index 83a6528..b71d10c 100644 --- a/.gitea/workflows/publish.yaml +++ b/.gitea/workflows/publish.yaml @@ -31,3 +31,10 @@ jobs: access: public token: ${{ secrets.NPM_TOKEN }} registry: https://registry.npmjs.org + - name: Publish @reffuse/extension-query + uses: JS-DevTools/npm-publish@v3 + with: + package: packages/extension-query + access: public + token: ${{ secrets.NPM_TOKEN }} + registry: https://registry.npmjs.org -- 2.49.1 From f7dd4e51f57d90773a633514bc57fce56d13e1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Tue, 11 Mar 2025 01:36:13 +0100 Subject: [PATCH 101/101] Doc update --- README.md | 1 + packages/extension-lazyref/README.md | 2 +- packages/extension-query/README.md | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0b644b4..bff34c9 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,5 @@ Reffuse is a [Effect-TS](https://effect.website/) integration for React 19+ with This monorepo contains: - [The `reffuse` library](packages/reffuse) - [`@reffuse/extension-lazyref`, a LazyRef integration for Reffuse](packages/extension-lazyref) +- [`@reffuse/extension-query`, TanStack Query style hooks for Reffuse](packages/extension-query) - [An example project](packges/example) diff --git a/packages/extension-lazyref/README.md b/packages/extension-lazyref/README.md index 699855e..fcf0a16 100644 --- a/packages/extension-lazyref/README.md +++ b/packages/extension-lazyref/README.md @@ -4,6 +4,6 @@ Extension to integrate `@typed/lazy-ref` with Reffuse. ## Peer dependencies - `@typed/lazy-ref` -- `reffuse` 0.1.2+ +- `reffuse` 0.1.3+ - `effect` 3.13+ - `react` & `@types/react` 19+ diff --git a/packages/extension-query/README.md b/packages/extension-query/README.md index 699855e..e9fd209 100644 --- a/packages/extension-query/README.md +++ b/packages/extension-query/README.md @@ -1,9 +1,10 @@ -# LazyRef extension for Reffuse +# Reffuse Query -Extension to integrate `@typed/lazy-ref` with Reffuse. +TanStack Query style hooks for Reffuse. ## Peer dependencies -- `@typed/lazy-ref` -- `reffuse` 0.1.2+ +- `reffuse` 0.1.3+ - `effect` 3.13+ +- `@effect/platform` & `@effect/platform-browser` - `react` & `@types/react` 19+ +- `@typed/async-data` -- 2.49.1