@farm.js/core 0.1.0-beta.95 → 0.1.0-beta.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/after.cjs +1 -1
- package/dist/after.mjs +1 -1
- package/dist/agent-runtime.d.mts +3 -2
- package/dist/agent-runtime.d.ts +3 -2
- package/dist/api/route-manager.cjs +43 -4
- package/dist/api/route-manager.d.mts +4 -3
- package/dist/api/route-manager.d.ts +4 -3
- package/dist/api/route-manager.mjs +7 -7
- package/dist/api/runtime.cjs +43 -4
- package/dist/api/runtime.d.mts +1 -1
- package/dist/api/runtime.d.ts +1 -1
- package/dist/api/runtime.mjs +5 -5
- package/dist/api.cjs +352 -109
- package/dist/api.d.mts +7 -6
- package/dist/api.d.ts +7 -6
- package/dist/api.mjs +19 -12
- package/dist/{app-CIIEvA4r.d.ts → app-CIOx3LvY.d.ts} +4 -4
- package/dist/{app-O4AEC1OH.d.mts → app-DBd6437H.d.mts} +4 -4
- package/dist/app-markdown.d.mts +4 -3
- package/dist/app-markdown.d.ts +4 -3
- package/dist/cache.cjs +42 -4
- package/dist/cache.d.mts +68 -1
- package/dist/cache.d.ts +68 -1
- package/dist/cache.mjs +3 -3
- package/dist/{chunk-AXVJCMVF.mjs → chunk-2HDOV47R.mjs} +3 -3
- package/dist/chunk-2HDOV47R.mjs.map +1 -0
- package/dist/{chunk-RBRLLZL5.mjs → chunk-34IAPZBG.mjs} +16 -3
- package/dist/chunk-34IAPZBG.mjs.map +1 -0
- package/dist/{chunk-VV24CC42.mjs → chunk-35NPLKQJ.mjs} +2 -2
- package/dist/{chunk-D7QH7MDU.mjs → chunk-3TWQERDE.mjs} +5 -4
- package/dist/chunk-3TWQERDE.mjs.map +1 -0
- package/dist/{chunk-RWYRFCLG.mjs → chunk-4X57GXQA.mjs} +2 -2
- package/dist/{chunk-KOTSX5JH.mjs → chunk-52BR7LTX.mjs} +30 -21
- package/dist/chunk-52BR7LTX.mjs.map +1 -0
- package/dist/{chunk-SALMKQXH.mjs → chunk-6EJHNHH4.mjs} +80 -27
- package/dist/chunk-6EJHNHH4.mjs.map +1 -0
- package/dist/{chunk-ZFNK77WN.mjs → chunk-6JNGOC37.mjs} +2 -2
- package/dist/{after.cjs.map → chunk-6JNGOC37.mjs.map} +1 -1
- package/dist/{chunk-MOW47IF5.mjs → chunk-6UYVU46O.mjs} +2 -2
- package/dist/{chunk-7MABZJIM.mjs → chunk-7PYVLJ4J.mjs} +1 -1
- package/dist/chunk-7PYVLJ4J.mjs.map +1 -0
- package/dist/{chunk-FLHLPB57.mjs → chunk-D7F7YZ7L.mjs} +93 -67
- package/dist/chunk-D7F7YZ7L.mjs.map +1 -0
- package/dist/chunk-DU3PKDVQ.mjs +35 -0
- package/dist/chunk-DU3PKDVQ.mjs.map +1 -0
- package/dist/{chunk-SCFX4UTD.mjs → chunk-EHTUKVSW.mjs} +1 -1
- package/dist/chunk-EHTUKVSW.mjs.map +1 -0
- package/dist/{chunk-KWCNQUH5.mjs → chunk-EPDIF432.mjs} +526 -50
- package/dist/chunk-EPDIF432.mjs.map +1 -0
- package/dist/{chunk-A3636IHN.mjs → chunk-FP5Q67FO.mjs} +167 -96
- package/dist/chunk-FP5Q67FO.mjs.map +1 -0
- package/dist/{chunk-HHZAOTQD.mjs → chunk-GJ7W6LNK.mjs} +7 -6
- package/dist/chunk-GJ7W6LNK.mjs.map +1 -0
- package/dist/{chunk-RLGUZ3HS.mjs → chunk-I3OOUWO5.mjs} +3 -3
- package/dist/{chunk-75CGAL6E.mjs → chunk-IZBX2TEU.mjs} +217 -105
- package/dist/chunk-IZBX2TEU.mjs.map +1 -0
- package/dist/{chunk-22VG4DFJ.mjs → chunk-J3MPQ4MQ.mjs} +2 -2
- package/dist/{chunk-22VG4DFJ.mjs.map → chunk-J3MPQ4MQ.mjs.map} +1 -1
- package/dist/{chunk-2LS3KKE7.mjs → chunk-JV7JUD7Q.mjs} +4 -4
- package/dist/{chunk-Q3OX763A.mjs → chunk-LXDASSTE.mjs} +2 -2
- package/dist/{chunk-ZRBCBOEX.mjs → chunk-N2FY2QZ7.mjs} +28 -3
- package/dist/chunk-N2FY2QZ7.mjs.map +1 -0
- package/dist/{chunk-MRVJCLYQ.mjs → chunk-PSQ7N4XP.mjs} +4 -2
- package/dist/chunk-PSQ7N4XP.mjs.map +1 -0
- package/dist/{chunk-HVG3HLQZ.mjs → chunk-Q7WGOOAI.mjs} +3 -3
- package/dist/{chunk-WTYAPO5I.mjs → chunk-RCNWMEBT.mjs} +3 -2
- package/dist/{chunk-WTYAPO5I.mjs.map → chunk-RCNWMEBT.mjs.map} +1 -1
- package/dist/{chunk-3INDBMUU.mjs → chunk-TGDIACZT.mjs} +2 -2
- package/dist/{chunk-WB75GIX2.mjs → chunk-TQTB33JS.mjs} +14 -3
- package/dist/chunk-TQTB33JS.mjs.map +1 -0
- package/dist/{chunk-MH27UH72.mjs → chunk-TT3E2JOF.mjs} +3 -3
- package/dist/{chunk-UWRGX3J3.mjs → chunk-UMUWR5XA.mjs} +2 -2
- package/dist/{chunk-XTLLHCWU.mjs → chunk-V4VRLVLW.mjs} +52 -31
- package/dist/chunk-V4VRLVLW.mjs.map +1 -0
- package/dist/{chunk-EXCGBERG.mjs → chunk-WD2EBM3I.mjs} +79 -17
- package/dist/chunk-WD2EBM3I.mjs.map +1 -0
- package/dist/{chunk-DLBUAJTK.mjs → chunk-WMJGA32P.mjs} +74 -5
- package/dist/chunk-WMJGA32P.mjs.map +1 -0
- package/dist/{chunk-TKQCJMY7.mjs → chunk-X4SFHKFH.mjs} +7 -4
- package/dist/{chunk-TKQCJMY7.mjs.map → chunk-X4SFHKFH.mjs.map} +1 -1
- package/dist/{chunk-Q7GPJZCO.mjs → chunk-YIBV77KZ.mjs} +26 -7
- package/dist/chunk-YIBV77KZ.mjs.map +1 -0
- package/dist/client/lifecycle.mjs +2 -2
- package/dist/{client-mcMC334J.d.mts → client-DWoLZ3QU.d.mts} +52 -5
- package/dist/{client-d5ONQ-Pd.d.ts → client-DuQuQC1h.d.ts} +52 -5
- package/dist/client-cache-BMxuFqwH.d.ts +18 -0
- package/dist/client-cache-CCK-fCe0.d.mts +18 -0
- package/dist/{client-plugins-BvClItiL.d.mts → client-plugins-B6-07YmP.d.mts} +52 -99
- package/dist/{client-plugins-B9Sq-iMg.d.ts → client-plugins-By6MVUX-.d.ts} +52 -99
- package/dist/client-plugins.cjs +1 -1
- package/dist/client-plugins.d.mts +3 -2
- package/dist/client-plugins.d.ts +3 -2
- package/dist/client-plugins.mjs +2 -2
- package/dist/client.cjs +1046 -211
- package/dist/client.d.mts +136 -18
- package/dist/client.d.ts +136 -18
- package/dist/client.mjs +32 -15
- package/dist/config.d.mts +3 -2
- package/dist/config.d.ts +3 -2
- package/dist/{devtools-S52RRRMN.mjs → devtools-XWZX6CCL.mjs} +5 -5
- package/dist/{devtools-client-3XRTBND5.mjs → devtools-client-Z7QQA3Q2.mjs} +56 -17
- package/dist/devtools-client-Z7QQA3Q2.mjs.map +1 -0
- package/dist/{devtools-ui-NJKFORTG.mjs → devtools-ui-2HG5M4EL.mjs} +3 -1
- package/dist/devtools-ui-2HG5M4EL.mjs.map +1 -0
- package/dist/docs.cjs +24 -5
- package/dist/docs.mjs +5 -5
- package/dist/i18n/server.cjs +13 -2
- package/dist/i18n/server.d.mts +2 -2
- package/dist/i18n/server.d.ts +2 -2
- package/dist/i18n/server.mjs +1 -1
- package/dist/index.cjs +1928 -894
- package/dist/index.d.mts +139 -21
- package/dist/index.d.ts +139 -21
- package/dist/index.mjs +57 -34
- package/dist/index.mjs.map +1 -1
- package/dist/integration-api-BT024nuJ.d.mts +97 -0
- package/dist/integration-api-BT024nuJ.d.ts +97 -0
- package/dist/integrations.d.mts +3 -2
- package/dist/integrations.d.ts +3 -2
- package/dist/internal/build-runtime.cjs +764 -547
- package/dist/internal/build-runtime.d.mts +5 -4
- package/dist/internal/build-runtime.d.ts +5 -4
- package/dist/internal/build-runtime.mjs +16 -16
- package/dist/internal/client-runtime.cjs +1 -1
- package/dist/internal/client-runtime.mjs +2 -2
- package/dist/internal/config-runtime.cjs +4 -1
- package/dist/internal/config-runtime.d.mts +4 -3
- package/dist/internal/config-runtime.d.ts +4 -3
- package/dist/internal/config-runtime.mjs +4 -4
- package/dist/internal/product-telemetry-runtime.cjs +1 -1
- package/dist/internal/product-telemetry-runtime.mjs +1 -1
- package/dist/internal/production-runtime.cjs +29 -3
- package/dist/internal/production-runtime.d.mts +8 -7
- package/dist/internal/production-runtime.d.ts +8 -7
- package/dist/internal/production-runtime.mjs +5 -5
- package/dist/{metadata-route-yV4U6X8h.d.ts → metadata-route-8_V3UonT.d.ts} +1 -1
- package/dist/{metadata-route-p4K1l92V.d.mts → metadata-route-CWP_HjGU.d.mts} +1 -1
- package/dist/middleware.cjs +28 -2
- package/dist/middleware.d.mts +5 -4
- package/dist/middleware.d.ts +5 -4
- package/dist/middleware.mjs +4 -4
- package/dist/navigation.cjs +3 -1
- package/dist/navigation.mjs +3 -3
- package/dist/observability.cjs +27 -2
- package/dist/observability.mjs +1 -1
- package/dist/plugin.cjs +528 -349
- package/dist/plugin.d.mts +3 -2
- package/dist/plugin.d.ts +3 -2
- package/dist/plugin.mjs +13 -13
- package/dist/{production-runtime-IkB0Qj4i.d.mts → production-runtime-BGRH1dKG.d.mts} +1 -1
- package/dist/{production-runtime-0JTch4_d.d.ts → production-runtime-CdmzsDax.d.ts} +1 -1
- package/dist/query/client.cjs +68 -29
- package/dist/query/client.mjs +69 -30
- package/dist/query/client.mjs.map +1 -1
- package/dist/{render-plan-Dc8CjNI7.d.ts → render-plan-0GeHiGVZ.d.ts} +1 -1
- package/dist/{render-plan-CU31j-Jk.d.mts → render-plan-DLxJYAA5.d.mts} +1 -1
- package/dist/renderer-client.cjs +169 -26
- package/dist/renderer-client.d.mts +7 -6
- package/dist/renderer-client.d.ts +7 -6
- package/dist/renderer-client.mjs +16 -19
- package/dist/renderer-client.mjs.map +1 -1
- package/dist/{request-BXa1KY8i.d.mts → request-BCNXSXLh.d.mts} +1 -1
- package/dist/{request-CUUBujZt.d.ts → request-BstWbZ6O.d.ts} +1 -1
- package/dist/request.d.mts +4 -3
- package/dist/request.d.ts +4 -3
- package/dist/{route-Y8lfz1wF.d.ts → route-4pd-EVtw.d.ts} +45 -50
- package/dist/{route-Cq3aObmj.d.mts → route-CvEr4Uc9.d.mts} +45 -50
- package/dist/routes.cjs +27 -2
- package/dist/routes.d.mts +3 -2
- package/dist/routes.d.ts +3 -2
- package/dist/routes.mjs +4 -4
- package/dist/{runtime-j1S3sDTh.d.ts → runtime-BgDQzBiu.d.ts} +1 -0
- package/dist/{runtime-DDwvDtS4.d.mts → runtime-CV2UCV-5.d.mts} +1 -0
- package/dist/server-action-security.mjs +2 -2
- package/dist/server-fn-client.cjs +102 -26
- package/dist/server-fn-client.d.mts +6 -0
- package/dist/server-fn-client.d.ts +6 -0
- package/dist/server-fn-client.mjs +2 -1
- package/dist/server-fn.cjs +42 -4
- package/dist/server-fn.mjs +5 -5
- package/dist/server-plugins.d.mts +4 -3
- package/dist/server-plugins.d.ts +4 -3
- package/dist/server-query-client.cjs +195 -34
- package/dist/server-query-client.d.mts +3 -3
- package/dist/server-query-client.d.ts +3 -3
- package/dist/server-query-client.mjs +7 -7
- package/dist/{server-query-runtime-3zAj77yv.d.ts → server-query-runtime-DXRNhX_3.d.ts} +2 -0
- package/dist/{server-query-runtime-B50KAcj5.d.mts → server-query-runtime-aP52iuL5.d.mts} +2 -0
- package/dist/server-query.cjs +44 -5
- package/dist/server-query.d.mts +4 -0
- package/dist/server-query.d.ts +4 -0
- package/dist/server-query.mjs +7 -7
- package/dist/server.cjs +553 -370
- package/dist/server.d.mts +11 -10
- package/dist/server.d.ts +11 -10
- package/dist/server.mjs +17 -17
- package/dist/{spa-router-CyLkwst6.d.mts → spa-router-BeyAVSc6.d.mts} +1 -1
- package/dist/{spa-router-BkqGXaV_.d.ts → spa-router-COgu4txb.d.ts} +1 -1
- package/dist/testing.cjs +27 -2
- package/dist/testing.d.mts +3 -2
- package/dist/testing.d.ts +3 -2
- package/dist/testing.mjs +9 -9
- package/dist/{utils-NKR6SoNv.d.mts → utils-DL2VwDQl.d.mts} +1 -1
- package/dist/{utils-B2OHrb9F.d.ts → utils-DkU2c_1B.d.ts} +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.mjs +1 -1
- package/dist/vite.cjs +536 -353
- package/dist/vite.d.mts +3 -2
- package/dist/vite.d.ts +3 -2
- package/dist/vite.mjs +17 -13
- package/package.json +17 -17
- package/types/client.d.ts +115 -10
- package/dist/agent-runtime.cjs.map +0 -1
- package/dist/api/route-manager.cjs.map +0 -1
- package/dist/api/runtime.cjs.map +0 -1
- package/dist/api.cjs.map +0 -1
- package/dist/app-markdown.cjs.map +0 -1
- package/dist/cache.cjs.map +0 -1
- package/dist/chunk-75CGAL6E.mjs.map +0 -1
- package/dist/chunk-7MABZJIM.mjs.map +0 -1
- package/dist/chunk-A3636IHN.mjs.map +0 -1
- package/dist/chunk-AXVJCMVF.mjs.map +0 -1
- package/dist/chunk-D7QH7MDU.mjs.map +0 -1
- package/dist/chunk-DLBUAJTK.mjs.map +0 -1
- package/dist/chunk-EXCGBERG.mjs.map +0 -1
- package/dist/chunk-FLHLPB57.mjs.map +0 -1
- package/dist/chunk-HHZAOTQD.mjs.map +0 -1
- package/dist/chunk-KOTSX5JH.mjs.map +0 -1
- package/dist/chunk-KWCNQUH5.mjs.map +0 -1
- package/dist/chunk-MRVJCLYQ.mjs.map +0 -1
- package/dist/chunk-Q7GPJZCO.mjs.map +0 -1
- package/dist/chunk-RBRLLZL5.mjs.map +0 -1
- package/dist/chunk-SALMKQXH.mjs.map +0 -1
- package/dist/chunk-SCFX4UTD.mjs.map +0 -1
- package/dist/chunk-WB75GIX2.mjs.map +0 -1
- package/dist/chunk-XTLLHCWU.mjs.map +0 -1
- package/dist/chunk-ZFNK77WN.mjs.map +0 -1
- package/dist/chunk-ZRBCBOEX.mjs.map +0 -1
- package/dist/client/lifecycle.cjs.map +0 -1
- package/dist/client-cache-CopR_MaI.d.mts +0 -6
- package/dist/client-cache-Djy_TlE8.d.ts +0 -6
- package/dist/client-plugins.cjs.map +0 -1
- package/dist/client.cjs.map +0 -1
- package/dist/config.cjs.map +0 -1
- package/dist/cron.cjs.map +0 -1
- package/dist/deferred.cjs.map +0 -1
- package/dist/deployment.cjs.map +0 -1
- package/dist/devtools-client-3XRTBND5.mjs.map +0 -1
- package/dist/devtools-ui-NJKFORTG.mjs.map +0 -1
- package/dist/docs.cjs.map +0 -1
- package/dist/env-types.cjs.map +0 -1
- package/dist/env.cjs.map +0 -1
- package/dist/environment/vite.cjs.map +0 -1
- package/dist/environment.cjs.map +0 -1
- package/dist/font.cjs.map +0 -1
- package/dist/headers.cjs.map +0 -1
- package/dist/i18n/client.cjs.map +0 -1
- package/dist/i18n/index.cjs.map +0 -1
- package/dist/i18n/server.cjs.map +0 -1
- package/dist/image/server.cjs.map +0 -1
- package/dist/image/sharp.cjs.map +0 -1
- package/dist/image.cjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/instrumentation.cjs.map +0 -1
- package/dist/integrations.cjs.map +0 -1
- package/dist/internal/build-runtime.cjs.map +0 -1
- package/dist/internal/client-runtime.cjs.map +0 -1
- package/dist/internal/config-runtime.cjs.map +0 -1
- package/dist/internal/isolated-boundary.cjs.map +0 -1
- package/dist/internal/metadata-image-runtime.cjs.map +0 -1
- package/dist/internal/product-telemetry-runtime.cjs.map +0 -1
- package/dist/internal/production-node-env.cjs.map +0 -1
- package/dist/internal/production-runtime.cjs.map +0 -1
- package/dist/markdown.cjs.map +0 -1
- package/dist/middleware.cjs.map +0 -1
- package/dist/navigation.cjs.map +0 -1
- package/dist/observability.cjs.map +0 -1
- package/dist/plugin.cjs.map +0 -1
- package/dist/query/client.cjs.map +0 -1
- package/dist/query/index.cjs.map +0 -1
- package/dist/query/parsers.cjs.map +0 -1
- package/dist/query/server.cjs.map +0 -1
- package/dist/renderer/react/client.cjs.map +0 -1
- package/dist/renderer/react/server.cjs.map +0 -1
- package/dist/renderer/react/vite.cjs.map +0 -1
- package/dist/renderer-client.cjs.map +0 -1
- package/dist/renderer.cjs.map +0 -1
- package/dist/request.cjs.map +0 -1
- package/dist/router.cjs.map +0 -1
- package/dist/routes.cjs.map +0 -1
- package/dist/server-action-security.cjs.map +0 -1
- package/dist/server-fn-client.cjs.map +0 -1
- package/dist/server-fn.cjs.map +0 -1
- package/dist/server-plugins.cjs.map +0 -1
- package/dist/server-query-client.cjs.map +0 -1
- package/dist/server-query.cjs.map +0 -1
- package/dist/server.cjs.map +0 -1
- package/dist/storage.cjs.map +0 -1
- package/dist/testing.cjs.map +0 -1
- package/dist/theme/client.cjs.map +0 -1
- package/dist/theme/index.cjs.map +0 -1
- package/dist/theme/runtime.cjs.map +0 -1
- package/dist/theme/server.cjs.map +0 -1
- package/dist/version.cjs.map +0 -1
- package/dist/vite.cjs.map +0 -1
- package/dist/workflows.cjs.map +0 -1
- /package/dist/{chunk-VV24CC42.mjs.map → chunk-35NPLKQJ.mjs.map} +0 -0
- /package/dist/{chunk-RWYRFCLG.mjs.map → chunk-4X57GXQA.mjs.map} +0 -0
- /package/dist/{chunk-MOW47IF5.mjs.map → chunk-6UYVU46O.mjs.map} +0 -0
- /package/dist/{chunk-RLGUZ3HS.mjs.map → chunk-I3OOUWO5.mjs.map} +0 -0
- /package/dist/{chunk-2LS3KKE7.mjs.map → chunk-JV7JUD7Q.mjs.map} +0 -0
- /package/dist/{chunk-Q3OX763A.mjs.map → chunk-LXDASSTE.mjs.map} +0 -0
- /package/dist/{chunk-HVG3HLQZ.mjs.map → chunk-Q7WGOOAI.mjs.map} +0 -0
- /package/dist/{chunk-3INDBMUU.mjs.map → chunk-TGDIACZT.mjs.map} +0 -0
- /package/dist/{chunk-MH27UH72.mjs.map → chunk-TT3E2JOF.mjs.map} +0 -0
- /package/dist/{chunk-UWRGX3J3.mjs.map → chunk-UMUWR5XA.mjs.map} +0 -0
- /package/dist/{devtools-S52RRRMN.mjs.map → devtools-XWZX6CCL.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/query/client.ts","../../src/query/sync.ts"],"sourcesContent":["/**\n * Farm.js Client-Side Query State Management\n *\n * Type-safe URL search parameter state management - Like useState, but stored in the URL query string.\n * Client-only hooks for managing query parameters in the browser.\n * Inspired by nuqs implementation patterns.\n */\n\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport {\n notifyHistoryChange,\n subscribeHistoryChange,\n writeFarmURLSearchHistory,\n} from \"../client/history-sync\";\nimport { _resolveCurrentRequest } from \"../server/request-bridge\";\nimport { emitter } from \"./sync\";\nexport { parseRouteParams, loadRouteParams, type RouteParamsInput } from \"./params\";\n\nimport { asString as asStringClient, asInteger as asIntegerClient, type Parser } from \"./parsers\";\n\nexport {\n asString,\n asInteger,\n asFloat,\n asBoolean,\n asArrayOf,\n asJson,\n asIsoDate,\n asIsoDateTime,\n createParser,\n type ArrayParserOptions,\n type Parser,\n type inferParserType,\n} from \"./parsers\";\n\nexport type UrlUpdateType = \"push\" | \"replace\";\nexport type HistoryMethod = \"pushState\" | \"replaceState\";\n\nexport interface Options {\n history?: HistoryMethod;\n shallow?: boolean;\n scroll?: boolean;\n throttleMs?: number;\n}\n\nconst getCurrentSearchParams = (): URLSearchParams => {\n if (typeof window !== \"undefined\") return new URLSearchParams(window.location.search);\n\n // Server rendering used to see an empty query string here, so a hook read one\n // value on the server and another in the browser. React reports that as a\n // hydration mismatch and discards the server rendered markup for the branch.\n const request = _resolveCurrentRequest();\n if (!request) return new URLSearchParams();\n try {\n return new URL(request.url).searchParams;\n } catch {\n return new URLSearchParams();\n }\n};\n\nconst readSearchParam = (searchParams: URLSearchParams, key: string): string => {\n const values = searchParams.getAll(key);\n return values.length > 1 ? values.join(\",\") : (values[0] ?? \"\");\n};\n\nconst throttleTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\nfunction getUpdateKey(updates: Record<string, unknown>): string {\n return JSON.stringify(Object.keys(updates).sort());\n}\n\nconst compareStructuredValues = (\n current: unknown,\n next: unknown,\n seen = new WeakMap<object, object>(),\n): boolean | undefined => {\n if (Object.is(current, next)) return true;\n if (current === null || next === null || typeof current !== typeof next) return false;\n if (typeof current !== \"object\" || typeof next !== \"object\") return false;\n if (current instanceof Date || next instanceof Date) {\n return current instanceof Date && next instanceof Date && current.getTime() === next.getTime();\n }\n if (Array.isArray(current) || Array.isArray(next)) {\n if (!Array.isArray(current) || !Array.isArray(next) || current.length !== next.length) {\n return false;\n }\n const knownNext = seen.get(current);\n if (knownNext) return knownNext === next;\n seen.set(current, next);\n for (let index = 0; index < current.length; index++) {\n const equal = compareStructuredValues(current[index], next[index], seen);\n if (equal !== true) return equal;\n }\n return true;\n }\n\n const currentPrototype = Object.getPrototypeOf(current);\n const nextPrototype = Object.getPrototypeOf(next);\n if (currentPrototype !== nextPrototype) return false;\n if (currentPrototype !== Object.prototype && currentPrototype !== null) return undefined;\n\n const knownNext = seen.get(current);\n if (knownNext) return knownNext === next;\n seen.set(current, next);\n\n const currentKeys = Object.keys(current);\n const nextKeys = Object.keys(next);\n if (\n currentKeys.length !== nextKeys.length ||\n currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(next, key))\n ) {\n return false;\n }\n for (const key of currentKeys) {\n const equal = compareStructuredValues(\n (current as Record<string, unknown>)[key],\n (next as Record<string, unknown>)[key],\n seen,\n );\n if (equal !== true) return equal;\n }\n return true;\n};\n\nconst areParsedValuesEqual = <T>(parser: Parser<T>, current: T | null, next: T | null) => {\n if (Object.is(current, next)) return true;\n const structuredResult = compareStructuredValues(current, next);\n if (structuredResult === false) return false;\n if (current === null || next === null) return false;\n\n try {\n return parser.serialize(current) === parser.serialize(next);\n } catch {\n return structuredResult === true;\n }\n};\n\nconst applyChange = (\n searchParams: URLSearchParams,\n updates: Record<string, string | null>,\n keepExisting = true,\n): URLSearchParams => {\n const newParams = keepExisting ? new URLSearchParams(searchParams) : new URLSearchParams();\n\n Object.entries(updates).forEach(([key, value]) => {\n if (value === null || value === undefined || value === \"\") {\n newParams.delete(key);\n } else {\n newParams.set(key, value);\n }\n });\n\n return newParams;\n};\n\nconst commitURLUpdate = (\n updates: Record<string, string | null>,\n options: Options,\n emitUpdate: boolean,\n) => {\n const { history = \"pushState\", shallow = true, scroll = false } = options;\n const url = new URL(window.location.href);\n const newSearchParams = applyChange(url.searchParams, updates);\n const newSearch = newSearchParams.toString();\n const newUrl = url.pathname + (newSearch ? `?${newSearch}` : \"\") + url.hash;\n const currentUrl = url.pathname + url.search + url.hash;\n\n if (newUrl === currentUrl) return;\n\n const historyAction = history === \"replaceState\" ? \"replace\" : \"push\";\n if (!writeFarmURLSearchHistory(historyAction, newUrl)) {\n const historyState = window.history.state;\n const nextHistoryState =\n historyState && typeof historyState === \"object\" && \"path\" in historyState\n ? { ...historyState, path: newUrl }\n : historyState;\n window.history[history](nextHistoryState, \"\", newUrl);\n }\n\n if (emitUpdate) {\n const actualSearchParams = new URLSearchParams(window.location.search);\n emitter.emitUpdate(actualSearchParams);\n }\n\n if (shallow) notifyHistoryChange(\"url-search\");\n\n if (scroll) {\n window.scrollTo(0, 0);\n }\n};\n\nconst updateURL = (\n updates: Record<string, string | null>,\n options: Options = {},\n emitUpdate = true,\n): (() => void) | undefined => {\n if (typeof window === \"undefined\") return;\n\n const { throttleMs } = options;\n if (!throttleMs || throttleMs <= 0) {\n commitURLUpdate(updates, options, emitUpdate);\n return;\n }\n\n const throttleKey = getUpdateKey(updates);\n const existingTimeout = throttleTimers.get(throttleKey);\n if (existingTimeout) {\n clearTimeout(existingTimeout);\n throttleTimers.delete(throttleKey);\n }\n\n const currentUrl = new URL(window.location.href);\n const nextSearch = applyChange(currentUrl.searchParams, updates).toString();\n if (nextSearch === currentUrl.searchParams.toString()) return;\n\n const timeout = setTimeout(() => {\n if (throttleTimers.get(throttleKey) === timeout) {\n throttleTimers.delete(throttleKey);\n }\n commitURLUpdate(updates, options, emitUpdate);\n }, throttleMs);\n\n throttleTimers.set(throttleKey, timeout);\n return () => {\n if (throttleTimers.get(throttleKey) !== timeout) return;\n clearTimeout(timeout);\n throttleTimers.delete(throttleKey);\n };\n};\n\nexport function useQueryState<TParser extends Parser<any>>(\n key: string,\n parser: TParser,\n options?: Options,\n): [\n NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n];\nexport function useQueryState<T>(\n key: string,\n parser: Parser<T>,\n options?: Options,\n): [T | null, (value: T | null) => void];\nexport function useQueryState<TParser extends Parser<any>>(\n key: string,\n parser: TParser,\n options?: Options,\n): [\n NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n] {\n type T = NonNullable<ReturnType<TParser[\"parse\"]>>;\n const [state, setState] = useState<T | null>(() => {\n const searchParams = getCurrentSearchParams();\n const parsed = parser.parse(readSearchParam(searchParams, key));\n return parsed;\n });\n\n const stateRef = useRef(state);\n const stateKeyRef = useRef(key);\n const isInternalUpdateRef = useRef(false);\n const cancelPendingUpdateRef = useRef<(() => void) | undefined>(undefined);\n stateRef.current = state;\n\n const setValue = useCallback(\n (value: T | null) => {\n isInternalUpdateRef.current = true;\n\n setState(value);\n stateRef.current = value;\n\n const serialized = value === null ? null : parser.serialize(value);\n\n emitter.emitKey(key, { state: value, query: serialized });\n\n cancelPendingUpdateRef.current?.();\n cancelPendingUpdateRef.current = updateURL({ [key]: serialized }, options, true);\n\n setTimeout(() => {\n isInternalUpdateRef.current = false;\n }, 10);\n },\n [key, parser, options],\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const onPopState = () => {\n const searchParams = getCurrentSearchParams();\n const parsed = parser.parse(readSearchParam(searchParams, key));\n const sourceChanged = stateKeyRef.current !== key;\n stateKeyRef.current = key;\n if (sourceChanged || !areParsedValuesEqual(parser, stateRef.current, parsed)) {\n setState(parsed);\n stateRef.current = parsed;\n }\n };\n\n const onEmitterUpdate = (searchParams: URLSearchParams) => {\n if (isInternalUpdateRef.current) {\n return;\n }\n\n const parsed = parser.parse(readSearchParam(searchParams, key));\n if (!areParsedValuesEqual(parser, stateRef.current, parsed)) {\n setState(parsed);\n stateRef.current = parsed;\n }\n };\n\n const onKeyUpdate = (payload: { state: any; query: string | null }) => {\n if (isInternalUpdateRef.current) {\n return;\n }\n\n if (!areParsedValuesEqual(parser, stateRef.current, payload.state)) {\n setState(payload.state);\n stateRef.current = payload.state;\n }\n };\n\n // Page-state writes with an href can change the query string without a\n // popstate, so listen through the shared history channel (real\n // back/forward events included). Self-updates no-op via the Object.is\n // comparison above.\n onPopState();\n const unsubscribeHistory = subscribeHistoryChange(onPopState);\n emitter.on(\"update\", onEmitterUpdate);\n emitter.onKey(key, onKeyUpdate);\n\n return () => {\n unsubscribeHistory();\n emitter.off(\"update\", onEmitterUpdate);\n emitter.offKey(key, onKeyUpdate);\n };\n }, [key, parser]);\n\n useEffect(\n () => () => {\n cancelPendingUpdateRef.current?.();\n cancelPendingUpdateRef.current = undefined;\n },\n [key],\n );\n\n return [state, setValue];\n}\n\nexport function useQueryStates<T extends Record<string, Parser<any>>>(\n parsers: T,\n options: Options = {},\n): [\n { [K in keyof T]: ReturnType<T[K][\"parse\"]> },\n (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => void,\n] {\n const keys = Object.keys(parsers);\n const watchKeys = JSON.stringify(keys);\n\n const [state, setState] = useState<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> }>(() => {\n const searchParams = getCurrentSearchParams();\n const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n\n Object.entries(parsers).forEach(([key, parser]) => {\n result[key as keyof T] = parser.parse(readSearchParam(searchParams, key));\n });\n\n return result;\n });\n\n const stateRef = useRef(state);\n const pendingUpdatesRef = useRef(new Map<string, () => void>());\n stateRef.current = state;\n\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => {\n const newState = { ...stateRef.current, ...updates };\n setState(newState);\n stateRef.current = newState;\n\n Object.entries(updates).forEach(([key, value]) => {\n const parser = parsers[key];\n if (parser) {\n const serialized = value === null ? null : parser.serialize(value);\n emitter.emitKey(key, { state: value, query: serialized });\n }\n });\n\n const urlUpdates: Record<string, string | null> = {};\n Object.entries(updates).forEach(([key, value]) => {\n const parser = parsers[key];\n if (parser) {\n const serialized = value === null ? null : parser.serialize(value);\n urlUpdates[key] = serialized;\n }\n });\n\n const updateKey = getUpdateKey(urlUpdates);\n pendingUpdatesRef.current.get(updateKey)?.();\n const cancelPendingUpdate = updateURL(urlUpdates, options, true);\n if (cancelPendingUpdate) {\n pendingUpdatesRef.current.set(updateKey, cancelPendingUpdate);\n } else {\n pendingUpdatesRef.current.delete(updateKey);\n }\n },\n [parsers, options],\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const applyChange = (searchParams: URLSearchParams) => {\n const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n const currentKeys = Object.keys(stateRef.current);\n let hasChanged =\n currentKeys.length !== keys.length ||\n currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(parsers, key));\n\n Object.entries(parsers).forEach(([key, parser]) => {\n const parsed = parser.parse(readSearchParam(searchParams, key));\n const currentValue = stateRef.current[key as keyof T];\n\n if (!areParsedValuesEqual(parser, currentValue, parsed)) {\n hasChanged = true;\n }\n result[key as keyof T] = parsed;\n });\n\n if (hasChanged) {\n setState(result);\n stateRef.current = result;\n }\n };\n\n const onPopState = () => {\n const searchParams = getCurrentSearchParams();\n applyChange(searchParams);\n };\n\n const onEmitterUpdate = (searchParams: URLSearchParams) => {\n applyChange(searchParams);\n };\n\n applyChange(getCurrentSearchParams());\n const unsubscribeHistory = subscribeHistoryChange(onPopState);\n emitter.on(\"update\", onEmitterUpdate);\n\n return () => {\n unsubscribeHistory();\n emitter.off(\"update\", onEmitterUpdate);\n };\n }, [watchKeys, parsers]);\n\n useEffect(\n () => () => {\n for (const cancelPendingUpdate of pendingUpdatesRef.current.values()) {\n cancelPendingUpdate();\n }\n pendingUpdatesRef.current.clear();\n },\n [watchKeys],\n );\n\n return [state, setValues];\n}\n\nexport function usePagination(options?: {\n defaultPage?: number;\n defaultLimit?: number;\n pageKey?: string;\n limitKey?: string;\n}) {\n const {\n defaultPage = 1,\n defaultLimit = 10,\n pageKey = \"page\",\n limitKey = \"limit\",\n } = options || {};\n\n const [page, setPage] = useQueryState(pageKey, asIntegerClient.withDefault!(defaultPage));\n const [limit, setLimit] = useQueryState(limitKey, asIntegerClient.withDefault!(defaultLimit));\n\n const currentPage = page ?? defaultPage;\n const currentLimit = limit ?? defaultLimit;\n const offset = ((currentPage as number) - 1) * (currentLimit as number);\n\n return {\n page: currentPage,\n setPage,\n limit: currentLimit,\n setLimit,\n offset,\n resetPagination: () => {\n setPage(defaultPage);\n setLimit(defaultLimit);\n },\n };\n}\n\nexport function useSearchFilters<T extends Record<string, any>>(options?: {\n searchKey?: string;\n defaultFilters?: T;\n filterKeys?: (keyof T)[];\n}) {\n const {\n searchKey = \"search\",\n defaultFilters = {} as T,\n filterKeys = Object.keys(defaultFilters) as (keyof T)[],\n } = options || {};\n\n const [search, setSearch] = useQueryState(searchKey, asStringClient);\n\n const filterParsers = filterKeys.reduce(\n (acc, key) => {\n acc[key as string] = asStringClient;\n return acc;\n },\n {} as Record<string, Parser<string>>,\n );\n\n const [filters, setFilters] = useQueryStates(filterParsers);\n\n const clearFilters = () => {\n setSearch(null);\n const clearedFilters = filterKeys.reduce(\n (acc, key) => {\n acc[key as string] = null;\n return acc;\n },\n {} as Record<string, null>,\n );\n setFilters(clearedFilters);\n };\n\n return {\n search,\n setSearch,\n filters: filters as T,\n setFilters,\n clearFilters,\n };\n}\n","/**\n * Cross-hook synchronization system for query state\n * Inspired by nuqs implementation\n */\n\ntype Listener = (searchParams: URLSearchParams) => void;\ntype KeyListener = (payload: { state: any; query: string | null }) => void;\n\nclass Emitter {\n private listeners: Map<string, Set<Listener>> = new Map();\n private keyListeners: Map<string, Set<KeyListener>> = new Map();\n\n /**\n * Emit a global update event (all hooks should sync)\n */\n emitUpdate(searchParams: URLSearchParams): void {\n const listeners = this.listeners.get(\"update\") || new Set();\n listeners.forEach((listener) => listener(searchParams));\n }\n\n /**\n * Emit a key-specific update (for cross-hook sync)\n */\n emitKey(key: string, payload: { state: any; query: string | null }): void {\n const listeners = this.keyListeners.get(key) || new Set();\n listeners.forEach((listener) => listener(payload));\n }\n\n /**\n * Subscribe to global updates\n */\n on(event: \"update\", listener: Listener): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n /**\n * Subscribe to key-specific updates\n */\n onKey(key: string, listener: KeyListener): void {\n if (!this.keyListeners.has(key)) {\n this.keyListeners.set(key, new Set());\n }\n this.keyListeners.get(key)!.add(listener);\n }\n\n /**\n * Unsubscribe from global updates\n */\n off(event: \"update\", listener: Listener): void {\n const listeners = this.listeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * Unsubscribe from key-specific updates\n */\n offKey(key: string, listener: KeyListener): void {\n const listeners = this.keyListeners.get(key);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n}\n\nexport const emitter = new Emitter();\n"],"mappings":"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","names":["knownNext","applyChange"]}
|
|
1
|
+
{"version":3,"sources":["../../src/query/client.ts","../../src/query/sync.ts"],"sourcesContent":["/**\n * Farm.js Client-Side Query State Management\n *\n * Type-safe URL search parameter state management - Like useState, but stored in the URL query string.\n * Client-only hooks for managing query parameters in the browser.\n * Inspired by nuqs implementation patterns.\n */\n\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport {\n notifyHistoryChange,\n subscribeHistoryChange,\n writeFarmURLSearchHistory,\n} from \"../client/history-sync\";\nimport { _resolveCurrentRequest } from \"../server/request-bridge\";\nimport { emitter, type KeyUpdate } from \"./sync\";\nexport { parseRouteParams, loadRouteParams, type RouteParamsInput } from \"./params\";\n\nimport { asString as asStringClient, asInteger as asIntegerClient, type Parser } from \"./parsers\";\n\nexport {\n asString,\n asInteger,\n asFloat,\n asBoolean,\n asArrayOf,\n asJson,\n asIsoDate,\n asIsoDateTime,\n createParser,\n type ArrayParserOptions,\n type Parser,\n type inferParserType,\n} from \"./parsers\";\n\nexport type UrlUpdateType = \"push\" | \"replace\";\nexport type HistoryMethod = \"pushState\" | \"replaceState\";\n\nexport interface Options {\n history?: HistoryMethod;\n shallow?: boolean;\n scroll?: boolean;\n throttleMs?: number;\n}\n\nconst getCurrentSearchParams = (): URLSearchParams => {\n if (typeof window !== \"undefined\") {\n discardDepartedURLUpdates();\n let params = new URLSearchParams(window.location.search);\n // Draft values belong to the existing throttle queue, not to a parser's\n // identity. Inline parsers and newly mounted consumers see the same draft.\n for (const pending of throttleTimers.values()) {\n if (pending.href === window.location.href) params = applyChange(params, pending.updates);\n }\n return params;\n }\n\n // Server rendering used to see an empty query string here, so a hook read one\n // value on the server and another in the browser. React reports that as a\n // hydration mismatch and discards the server rendered markup for the branch.\n const request = _resolveCurrentRequest();\n if (!request) return new URLSearchParams();\n try {\n return new URL(request.url).searchParams;\n } catch {\n return new URLSearchParams();\n }\n};\n\nconst readSearchParam = (searchParams: URLSearchParams, key: string): string => {\n const values = searchParams.getAll(key);\n return values.length > 1 ? values.join(\",\") : (values[0] ?? \"\");\n};\n\nconst throttleTimers = new Map<\n string,\n {\n timer: ReturnType<typeof setTimeout>;\n updates: Record<string, string | null>;\n href: string;\n }\n>();\n\nfunction discardDepartedURLUpdates(): void {\n for (const [key, pending] of throttleTimers) {\n if (pending.href === window.location.href) continue;\n clearTimeout(pending.timer);\n throttleTimers.delete(key);\n }\n}\n\nfunction getUpdateKey(updates: Record<string, unknown>): string {\n return JSON.stringify(Object.keys(updates).sort());\n}\n\nfunction supersedeQueuedKeys(updates: Record<string, string | null>): void {\n const keys = Object.keys(updates);\n for (const [queueKey, pending] of throttleTimers) {\n for (const key of keys) delete pending.updates[key];\n if (Object.keys(pending.updates).length > 0) continue;\n clearTimeout(pending.timer);\n throttleTimers.delete(queueKey);\n }\n}\n\nconst compareStructuredValues = (\n current: unknown,\n next: unknown,\n seen = new WeakMap<object, object>(),\n): boolean | undefined => {\n if (Object.is(current, next)) return true;\n if (current === null || next === null || typeof current !== typeof next) return false;\n if (typeof current !== \"object\" || typeof next !== \"object\") return false;\n if (current instanceof Date || next instanceof Date) {\n return current instanceof Date && next instanceof Date && current.getTime() === next.getTime();\n }\n if (Array.isArray(current) || Array.isArray(next)) {\n if (!Array.isArray(current) || !Array.isArray(next) || current.length !== next.length) {\n return false;\n }\n const knownNext = seen.get(current);\n if (knownNext) return knownNext === next;\n seen.set(current, next);\n for (let index = 0; index < current.length; index++) {\n const equal = compareStructuredValues(current[index], next[index], seen);\n if (equal !== true) return equal;\n }\n return true;\n }\n\n const currentPrototype = Object.getPrototypeOf(current);\n const nextPrototype = Object.getPrototypeOf(next);\n if (currentPrototype !== nextPrototype) return false;\n if (currentPrototype !== Object.prototype && currentPrototype !== null) return undefined;\n\n const knownNext = seen.get(current);\n if (knownNext) return knownNext === next;\n seen.set(current, next);\n\n const currentKeys = Object.keys(current);\n const nextKeys = Object.keys(next);\n if (\n currentKeys.length !== nextKeys.length ||\n currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(next, key))\n ) {\n return false;\n }\n for (const key of currentKeys) {\n const equal = compareStructuredValues(\n (current as Record<string, unknown>)[key],\n (next as Record<string, unknown>)[key],\n seen,\n );\n if (equal !== true) return equal;\n }\n return true;\n};\n\nconst areParsedValuesEqual = <T>(parser: Parser<T>, current: T | null, next: T | null) => {\n if (Object.is(current, next)) return true;\n const structuredResult = compareStructuredValues(current, next);\n if (structuredResult === false) return false;\n if (current === null || next === null) return false;\n\n try {\n return parser.serialize(current) === parser.serialize(next);\n } catch {\n return structuredResult === true;\n }\n};\n\nconst applyChange = (\n searchParams: URLSearchParams,\n updates: Record<string, string | null>,\n keepExisting = true,\n): URLSearchParams => {\n const newParams = keepExisting ? new URLSearchParams(searchParams) : new URLSearchParams();\n\n Object.entries(updates).forEach(([key, value]) => {\n if (value === null || value === undefined || value === \"\") {\n newParams.delete(key);\n } else {\n newParams.set(key, value);\n }\n });\n\n return newParams;\n};\n\nconst commitURLUpdate = (\n updates: Record<string, string | null>,\n options: Options,\n emitUpdate: boolean,\n) => {\n const { history = \"pushState\", shallow = true, scroll = false } = options;\n const url = new URL(window.location.href);\n const newSearchParams = applyChange(url.searchParams, updates);\n const newSearch = newSearchParams.toString();\n const newUrl = url.pathname + (newSearch ? `?${newSearch}` : \"\") + url.hash;\n const currentUrl = url.pathname + url.search + url.hash;\n\n if (newUrl === currentUrl) return;\n\n const historyAction = history === \"replaceState\" ? \"replace\" : \"push\";\n if (!writeFarmURLSearchHistory(historyAction, newUrl)) {\n const historyState = window.history.state;\n const nextHistoryState =\n historyState && typeof historyState === \"object\" && \"path\" in historyState\n ? { ...historyState, path: newUrl }\n : historyState;\n window.history[history](nextHistoryState, \"\", newUrl);\n }\n\n if (emitUpdate) {\n // Composing one queued key must not discard drafts for other keys. Only\n // carry drafts forward across this write, never across unrelated navigation.\n for (const pending of throttleTimers.values()) {\n if (pending.href === url.href) pending.href = window.location.href;\n }\n emitter.emitUpdate(getCurrentSearchParams());\n }\n\n if (shallow) notifyHistoryChange(\"url-search\");\n\n if (scroll) {\n window.scrollTo(0, 0);\n }\n};\n\nconst updateURL = (\n updates: Record<string, string | null>,\n options: Options = {},\n emitUpdate = true,\n): (() => boolean) | undefined => {\n if (typeof window === \"undefined\") return;\n\n discardDepartedURLUpdates();\n\n const { throttleMs } = options;\n // Latest intent owns each key, including immediate writes and URL no-ops.\n // Keep unrelated keys in an older batch scheduled with their original owner.\n supersedeQueuedKeys(updates);\n if (!throttleMs || throttleMs <= 0) {\n commitURLUpdate(updates, options, emitUpdate);\n return;\n }\n\n const throttleKey = getUpdateKey(updates);\n\n const currentUrl = new URL(window.location.href);\n const nextSearch = applyChange(currentUrl.searchParams, updates).toString();\n if (nextSearch === currentUrl.searchParams.toString()) return;\n\n const timeout = setTimeout(() => {\n const pending = throttleTimers.get(throttleKey);\n if (pending?.timer !== timeout) return;\n throttleTimers.delete(throttleKey);\n if (pending.href !== window.location.href) return;\n commitURLUpdate(updates, options, emitUpdate);\n }, throttleMs);\n\n throttleTimers.set(throttleKey, { timer: timeout, updates, href: currentUrl.href });\n return () => {\n if (throttleTimers.get(throttleKey)?.timer !== timeout) return false;\n clearTimeout(timeout);\n throttleTimers.delete(throttleKey);\n return true;\n };\n};\n\nexport function useQueryState<TParser extends Parser<any>>(\n key: string,\n parser: TParser,\n options?: Options,\n): [\n NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n];\nexport function useQueryState<T>(\n key: string,\n parser: Parser<T>,\n options?: Options,\n): [T | null, (value: T | null) => void];\nexport function useQueryState<TParser extends Parser<any>>(\n key: string,\n parser: TParser,\n options?: Options,\n): [\n NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n] {\n type T = NonNullable<ReturnType<TParser[\"parse\"]>>;\n const [state, setState] = useState<T | null>(() => {\n const searchParams = getCurrentSearchParams();\n const parsed = parser.parse(readSearchParam(searchParams, key));\n return parsed;\n });\n\n const stateRef = useRef(state);\n const stateKeyRef = useRef(key);\n const cancelPendingUpdateRef = useRef<(() => boolean) | undefined>(undefined);\n stateRef.current = state;\n\n const setValue = useCallback(\n (value: T | null) => {\n setState(value);\n stateRef.current = value;\n\n const serialized = value === null ? null : parser.serialize(value);\n\n emitter.emitKey(key, { state: value, query: serialized, source: stateRef });\n\n cancelPendingUpdateRef.current?.();\n cancelPendingUpdateRef.current = updateURL({ [key]: serialized }, options, true);\n },\n [key, parser, options],\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const onPopState = () => {\n const searchParams = getCurrentSearchParams();\n const parsed = parser.parse(readSearchParam(searchParams, key));\n const sourceChanged = stateKeyRef.current !== key;\n stateKeyRef.current = key;\n if (sourceChanged || !areParsedValuesEqual(parser, stateRef.current, parsed)) {\n setState(parsed);\n stateRef.current = parsed;\n }\n };\n\n const onEmitterUpdate = (searchParams: URLSearchParams) => {\n const parsed = parser.parse(readSearchParam(searchParams, key));\n if (!areParsedValuesEqual(parser, stateRef.current, parsed)) {\n setState(parsed);\n stateRef.current = parsed;\n }\n };\n\n const onKeyUpdate = (payload: KeyUpdate) => {\n // Skip only this hook's synchronous echo, never a peer's newer edit.\n // The ref identity is stable across renders and is not serialized.\n if (payload.source === stateRef) {\n return;\n }\n\n // Consumers may use different parsers for the same URL key.\n const parsed = parser.parse(payload.query ?? \"\");\n if (!areParsedValuesEqual(parser, stateRef.current, parsed)) {\n setState(parsed);\n stateRef.current = parsed;\n }\n };\n\n // Page-state writes with an href can change the query string without a\n // popstate, so listen through the shared history channel (real\n // back/forward events included). Self-updates no-op via the Object.is\n // comparison above.\n onPopState();\n const unsubscribeHistory = subscribeHistoryChange(onPopState);\n emitter.on(\"update\", onEmitterUpdate);\n emitter.onKey(key, onKeyUpdate);\n\n return () => {\n unsubscribeHistory();\n emitter.off(\"update\", onEmitterUpdate);\n emitter.offKey(key, onKeyUpdate);\n };\n }, [key, parser]);\n\n useEffect(\n () => () => {\n const canceledPendingWrite = cancelPendingUpdateRef.current?.() ?? false;\n cancelPendingUpdateRef.current = undefined;\n // A throttled write is discarded on unmount, but its value was already\n // broadcast to peers via emitKey. Peers that adopted the optimistic draft\n // get no other reconciliation signal (unmount fires no history event), so\n // tell them to re-read the URL, which no longer carries this draft.\n if (canceledPendingWrite && typeof window !== \"undefined\") {\n emitter.emitUpdate(getCurrentSearchParams());\n }\n },\n [key],\n );\n\n return [state, setValue];\n}\n\nexport function useQueryStates<T extends Record<string, Parser<any>>>(\n parsers: T,\n options: Options = {},\n): [\n { [K in keyof T]: ReturnType<T[K][\"parse\"]> },\n (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => void,\n] {\n const keys = Object.keys(parsers);\n const watchKeys = JSON.stringify(keys);\n\n const [state, setState] = useState<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> }>(() => {\n const searchParams = getCurrentSearchParams();\n const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n\n Object.entries(parsers).forEach(([key, parser]) => {\n result[key as keyof T] = parser.parse(readSearchParam(searchParams, key));\n });\n\n return result;\n });\n\n const stateRef = useRef(state);\n const pendingUpdatesRef = useRef(new Map<string, () => boolean>());\n stateRef.current = state;\n\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => {\n const newState = { ...stateRef.current, ...updates };\n setState(newState);\n stateRef.current = newState;\n\n Object.entries(updates).forEach(([key, value]) => {\n const parser = parsers[key];\n if (parser) {\n const serialized = value === null ? null : parser.serialize(value);\n emitter.emitKey(key, { state: value, query: serialized, source: stateRef });\n }\n });\n\n const urlUpdates: Record<string, string | null> = {};\n Object.entries(updates).forEach(([key, value]) => {\n const parser = parsers[key];\n if (parser) {\n const serialized = value === null ? null : parser.serialize(value);\n urlUpdates[key] = serialized;\n }\n });\n\n const updateKey = getUpdateKey(urlUpdates);\n pendingUpdatesRef.current.get(updateKey)?.();\n const cancelPendingUpdate = updateURL(urlUpdates, options, true);\n if (cancelPendingUpdate) {\n pendingUpdatesRef.current.set(updateKey, cancelPendingUpdate);\n } else {\n pendingUpdatesRef.current.delete(updateKey);\n }\n },\n [parsers, options],\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const applyChange = (searchParams: URLSearchParams) => {\n const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n const currentKeys = Object.keys(stateRef.current);\n let hasChanged =\n currentKeys.length !== keys.length ||\n currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(parsers, key));\n\n Object.entries(parsers).forEach(([key, parser]) => {\n const parsed = parser.parse(readSearchParam(searchParams, key));\n const currentValue = stateRef.current[key as keyof T];\n\n if (!areParsedValuesEqual(parser, currentValue, parsed)) {\n hasChanged = true;\n }\n result[key as keyof T] = parsed;\n });\n\n if (hasChanged) {\n setState(result);\n stateRef.current = result;\n }\n };\n\n const onPopState = () => {\n const searchParams = getCurrentSearchParams();\n applyChange(searchParams);\n };\n\n const onEmitterUpdate = (searchParams: URLSearchParams) => {\n applyChange(searchParams);\n };\n\n applyChange(getCurrentSearchParams());\n const unsubscribeHistory = subscribeHistoryChange(onPopState);\n emitter.on(\"update\", onEmitterUpdate);\n const unsubscribeKeys = Object.entries(parsers).map(([key, parser]) => {\n const onKeyUpdate = (payload: KeyUpdate) => {\n if (payload.source === stateRef) return;\n const parsed = parser.parse(payload.query ?? \"\");\n if (areParsedValuesEqual(parser, stateRef.current[key as keyof T], parsed)) return;\n\n // Update only this key, preserving local drafts for the other fields.\n const next = { ...stateRef.current, [key]: parsed };\n stateRef.current = next;\n setState(next);\n };\n emitter.onKey(key, onKeyUpdate);\n return () => emitter.offKey(key, onKeyUpdate);\n });\n\n return () => {\n unsubscribeHistory();\n emitter.off(\"update\", onEmitterUpdate);\n for (const unsubscribe of unsubscribeKeys) unsubscribe();\n };\n }, [watchKeys, parsers]);\n\n useEffect(\n () => () => {\n let canceledPendingWrite = false;\n for (const cancelPendingUpdate of pendingUpdatesRef.current.values()) {\n if (cancelPendingUpdate()) canceledPendingWrite = true;\n }\n pendingUpdatesRef.current.clear();\n // Discarded throttled writes were already broadcast to peers via emitKey;\n // reconcile any peer that adopted a now-cancelled draft (see useQueryState).\n if (canceledPendingWrite && typeof window !== \"undefined\") {\n emitter.emitUpdate(getCurrentSearchParams());\n }\n },\n [watchKeys],\n );\n\n return [state, setValues];\n}\n\nexport function usePagination(options?: {\n defaultPage?: number;\n defaultLimit?: number;\n pageKey?: string;\n limitKey?: string;\n}) {\n const {\n defaultPage = 1,\n defaultLimit = 10,\n pageKey = \"page\",\n limitKey = \"limit\",\n } = options || {};\n\n const [page, setPage] = useQueryState(pageKey, asIntegerClient.withDefault!(defaultPage));\n const [limit, setLimit] = useQueryState(limitKey, asIntegerClient.withDefault!(defaultLimit));\n\n const currentPage = page ?? defaultPage;\n const currentLimit = limit ?? defaultLimit;\n const offset = ((currentPage as number) - 1) * (currentLimit as number);\n\n return {\n page: currentPage,\n setPage,\n limit: currentLimit,\n setLimit,\n offset,\n resetPagination: () => {\n setPage(defaultPage);\n setLimit(defaultLimit);\n },\n };\n}\n\nexport function useSearchFilters<T extends Record<string, any>>(options?: {\n searchKey?: string;\n defaultFilters?: T;\n filterKeys?: (keyof T)[];\n}) {\n const {\n searchKey = \"search\",\n defaultFilters = {} as T,\n filterKeys = Object.keys(defaultFilters) as (keyof T)[],\n } = options || {};\n\n const [search, setSearch] = useQueryState(searchKey, asStringClient);\n\n const filterParsers = filterKeys.reduce(\n (acc, key) => {\n acc[key as string] = asStringClient;\n return acc;\n },\n {} as Record<string, Parser<string>>,\n );\n\n const [filters, setFilters] = useQueryStates(filterParsers);\n\n const clearFilters = () => {\n setSearch(null);\n const clearedFilters = filterKeys.reduce(\n (acc, key) => {\n acc[key as string] = null;\n return acc;\n },\n {} as Record<string, null>,\n );\n setFilters(clearedFilters);\n };\n\n return {\n search,\n setSearch,\n filters: filters as T,\n setFilters,\n clearFilters,\n };\n}\n","/**\n * Cross-hook synchronization system for query state\n * Inspired by nuqs implementation\n */\n\ntype Listener = (searchParams: URLSearchParams) => void;\nexport type KeyUpdate = { state: any; query: string | null; source?: object };\ntype KeyListener = (payload: KeyUpdate) => void;\n\nclass Emitter {\n private listeners: Map<string, Set<Listener>> = new Map();\n private keyListeners: Map<string, Set<KeyListener>> = new Map();\n\n /**\n * Emit a global update event (all hooks should sync)\n */\n emitUpdate(searchParams: URLSearchParams): void {\n const listeners = this.listeners.get(\"update\") || new Set();\n listeners.forEach((listener) => listener(searchParams));\n }\n\n /**\n * Emit a key-specific update (for cross-hook sync)\n */\n emitKey(key: string, payload: KeyUpdate): void {\n const listeners = this.keyListeners.get(key) || new Set();\n listeners.forEach((listener) => listener(payload));\n }\n\n /**\n * Subscribe to global updates\n */\n on(event: \"update\", listener: Listener): void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n }\n\n /**\n * Subscribe to key-specific updates\n */\n onKey(key: string, listener: KeyListener): void {\n if (!this.keyListeners.has(key)) {\n this.keyListeners.set(key, new Set());\n }\n this.keyListeners.get(key)!.add(listener);\n }\n\n /**\n * Unsubscribe from global updates\n */\n off(event: \"update\", listener: Listener): void {\n const listeners = this.listeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * Unsubscribe from key-specific updates\n */\n offKey(key: string, listener: KeyListener): void {\n const listeners = this.keyListeners.get(key);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n}\n\nexport const emitter = new Emitter();\n"],"mappings":"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","names":["knownNext","applyChange"]}
|
package/dist/renderer-client.cjs
CHANGED
|
@@ -1398,7 +1398,9 @@ var _SPARouter = class _SPARouter {
|
|
|
1398
1398
|
if (this.onNavigate) {
|
|
1399
1399
|
await this.onNavigate(pageData);
|
|
1400
1400
|
}
|
|
1401
|
-
if (
|
|
1401
|
+
if (window.location.hash) {
|
|
1402
|
+
getHashTargetElement(window.location.hash)?.scrollIntoView();
|
|
1403
|
+
} else if (this.options.scrollRestoration) {
|
|
1402
1404
|
this.restoreScrollPosition(window.location.pathname + window.location.search);
|
|
1403
1405
|
}
|
|
1404
1406
|
if (clientNavigation) {
|
|
@@ -1723,7 +1725,13 @@ function recordFarmEventTrace(event) {
|
|
|
1723
1725
|
activeSpan.addEvent(event.type, toEventAttributes(event), event.timestamp);
|
|
1724
1726
|
}
|
|
1725
1727
|
const error = event.type === "request.error" ? void 0 : getEventError(event);
|
|
1726
|
-
if (error !== void 0)
|
|
1728
|
+
if (error !== void 0) {
|
|
1729
|
+
if (event.type === "render.error") {
|
|
1730
|
+
recordSpanException(activeSpan, error);
|
|
1731
|
+
} else {
|
|
1732
|
+
recordSpanError(activeSpan, error);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1727
1735
|
}
|
|
1728
1736
|
const completedTraceContext = recordCompletedEventSpan(event, activeContext);
|
|
1729
1737
|
return traceContext ?? completedTraceContext;
|
|
@@ -1820,12 +1828,26 @@ function getCompletedSpanDescriptor(event) {
|
|
|
1820
1828
|
}
|
|
1821
1829
|
}
|
|
1822
1830
|
__name(getCompletedSpanDescriptor, "getCompletedSpanDescriptor");
|
|
1831
|
+
function hashFarmCacheKey(value) {
|
|
1832
|
+
let hash = 2166136261;
|
|
1833
|
+
for (let index = 0; index < value.length; index++) {
|
|
1834
|
+
hash ^= value.charCodeAt(index);
|
|
1835
|
+
hash = Math.imul(hash, 16777619);
|
|
1836
|
+
}
|
|
1837
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1838
|
+
}
|
|
1839
|
+
__name(hashFarmCacheKey, "hashFarmCacheKey");
|
|
1823
1840
|
function toEventAttributes(event) {
|
|
1824
1841
|
const attributes = {};
|
|
1842
|
+
const redactKey = typeof event.type === "string" && event.type.startsWith("cache.");
|
|
1825
1843
|
for (const [key, value] of Object.entries(event)) {
|
|
1826
1844
|
if (key === "timestamp" || key === "level" || key === "error" || key === "traceId" || key === "spanId" || key === "traceSampled" || value === void 0) {
|
|
1827
1845
|
continue;
|
|
1828
1846
|
}
|
|
1847
|
+
if (redactKey && key === "key" && typeof value === "string") {
|
|
1848
|
+
attributes["farm.key_hash"] = hashFarmCacheKey(value);
|
|
1849
|
+
continue;
|
|
1850
|
+
}
|
|
1829
1851
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1830
1852
|
attributes[`farm.${key}`] = value;
|
|
1831
1853
|
} else if (Array.isArray(value)) {
|
|
@@ -1845,9 +1867,14 @@ function getEventError(event) {
|
|
|
1845
1867
|
return "error" in event ? event.error : void 0;
|
|
1846
1868
|
}
|
|
1847
1869
|
__name(getEventError, "getEventError");
|
|
1848
|
-
function
|
|
1870
|
+
function recordSpanException(span, error) {
|
|
1849
1871
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
1850
1872
|
span.recordException(normalized);
|
|
1873
|
+
return normalized;
|
|
1874
|
+
}
|
|
1875
|
+
__name(recordSpanException, "recordSpanException");
|
|
1876
|
+
function recordSpanError(span, error) {
|
|
1877
|
+
const normalized = recordSpanException(span, error);
|
|
1851
1878
|
span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: normalized.message });
|
|
1852
1879
|
}
|
|
1853
1880
|
__name(recordSpanError, "recordSpanError");
|
|
@@ -2659,6 +2686,31 @@ function stableSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
|
2659
2686
|
__name(stableSerialize, "stableSerialize");
|
|
2660
2687
|
|
|
2661
2688
|
// src/client-cache.ts
|
|
2689
|
+
var invalidationTrackers = /* @__PURE__ */ new WeakMap();
|
|
2690
|
+
function trackFarmClientCacheInvalidations(cache) {
|
|
2691
|
+
let trackers = invalidationTrackers.get(cache);
|
|
2692
|
+
if (!trackers) {
|
|
2693
|
+
trackers = /* @__PURE__ */ new Set();
|
|
2694
|
+
invalidationTrackers.set(cache, trackers);
|
|
2695
|
+
}
|
|
2696
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2697
|
+
trackers.add(keys);
|
|
2698
|
+
return {
|
|
2699
|
+
has(key) {
|
|
2700
|
+
const resolved = cache.resolveKey(key);
|
|
2701
|
+
for (const invalidated of keys) {
|
|
2702
|
+
if (cache.resolveKey(invalidated) === resolved) return true;
|
|
2703
|
+
}
|
|
2704
|
+
return false;
|
|
2705
|
+
},
|
|
2706
|
+
dispose() {
|
|
2707
|
+
if (!trackers.delete(keys)) return;
|
|
2708
|
+
keys.clear();
|
|
2709
|
+
if (trackers.size === 0) invalidationTrackers.delete(cache);
|
|
2710
|
+
}
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
__name(trackFarmClientCacheInvalidations, "trackFarmClientCacheInvalidations");
|
|
2662
2714
|
var cacheFinalizer = typeof FinalizationRegistry === "function" ? new FinalizationRegistry((unsubscribe) => unsubscribe()) : void 0;
|
|
2663
2715
|
function subscribeWeakCache(reference) {
|
|
2664
2716
|
const unsubscribe = subscribeFarmCacheInvalidation((key) => {
|
|
@@ -2674,6 +2726,7 @@ function subscribeWeakCache(reference) {
|
|
|
2674
2726
|
return dispose;
|
|
2675
2727
|
}
|
|
2676
2728
|
__name(subscribeWeakCache, "subscribeWeakCache");
|
|
2729
|
+
var DEFAULT_GC_SWEEP_INTERVAL_MS = 3e4;
|
|
2677
2730
|
var _FarmClientDataCache = class _FarmClientDataCache {
|
|
2678
2731
|
constructor(options = {}) {
|
|
2679
2732
|
this.entries = /* @__PURE__ */ new Map();
|
|
@@ -2681,6 +2734,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2681
2734
|
this.invalidatedAt = /* @__PURE__ */ new Map();
|
|
2682
2735
|
this.listeners = /* @__PURE__ */ new Map();
|
|
2683
2736
|
this.inflight = /* @__PURE__ */ new Map();
|
|
2737
|
+
this.gcSweepIntervalMs = options.gcSweepIntervalMs ?? DEFAULT_GC_SWEEP_INTERVAL_MS;
|
|
2684
2738
|
if (options.subscribeToInvalidation !== false) {
|
|
2685
2739
|
if (typeof WeakRef === "function") {
|
|
2686
2740
|
const reference = new WeakRef(this);
|
|
@@ -2697,6 +2751,10 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2697
2751
|
get size() {
|
|
2698
2752
|
return this.entries.size;
|
|
2699
2753
|
}
|
|
2754
|
+
/** @internal Attach or detach the persistence engine's observation sink. */
|
|
2755
|
+
attachPersistence(sink) {
|
|
2756
|
+
this.persistence = sink;
|
|
2757
|
+
}
|
|
2700
2758
|
resolveKey(key) {
|
|
2701
2759
|
let resolved = key;
|
|
2702
2760
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2712,6 +2770,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2712
2770
|
if (!entry) return void 0;
|
|
2713
2771
|
if (entry.gcAt !== void 0 && now >= entry.gcAt) {
|
|
2714
2772
|
this.entries.delete(resolved);
|
|
2773
|
+
this.persistence?.onDelete(resolved);
|
|
2715
2774
|
this.emit(resolved);
|
|
2716
2775
|
return void 0;
|
|
2717
2776
|
}
|
|
@@ -2725,6 +2784,8 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2725
2784
|
this.invalidatedAt.delete(resolved);
|
|
2726
2785
|
}
|
|
2727
2786
|
this.entries.set(resolved, nextEntry);
|
|
2787
|
+
if (nextEntry.gcAt !== void 0) this.scheduleGcSweep();
|
|
2788
|
+
this.persistence?.onSet(resolved, nextEntry);
|
|
2728
2789
|
this.emit(resolved);
|
|
2729
2790
|
return this;
|
|
2730
2791
|
}
|
|
@@ -2732,6 +2793,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2732
2793
|
const resolved = this.resolveKey(key);
|
|
2733
2794
|
const deleted = this.entries.delete(resolved);
|
|
2734
2795
|
this.inflight.delete(resolved);
|
|
2796
|
+
if (deleted) this.persistence?.onDelete(resolved);
|
|
2735
2797
|
this.emit(resolved);
|
|
2736
2798
|
return deleted;
|
|
2737
2799
|
}
|
|
@@ -2741,11 +2803,16 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2741
2803
|
this.aliases.clear();
|
|
2742
2804
|
this.invalidatedAt.clear();
|
|
2743
2805
|
this.inflight.clear();
|
|
2806
|
+
this.persistence?.onClear();
|
|
2744
2807
|
for (const key of keys) this.emit(key);
|
|
2745
2808
|
}
|
|
2746
2809
|
dispose() {
|
|
2747
2810
|
this.unsubscribeInvalidation?.();
|
|
2748
2811
|
this.unsubscribeInvalidation = void 0;
|
|
2812
|
+
if (this.gcTimer !== void 0) {
|
|
2813
|
+
clearTimeout(this.gcTimer);
|
|
2814
|
+
this.gcTimer = void 0;
|
|
2815
|
+
}
|
|
2749
2816
|
this.clear();
|
|
2750
2817
|
}
|
|
2751
2818
|
isStale(key, now = Date.now()) {
|
|
@@ -2754,6 +2821,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2754
2821
|
}
|
|
2755
2822
|
invalidate(key, now = Date.now()) {
|
|
2756
2823
|
const resolved = this.resolveKey(key);
|
|
2824
|
+
for (const keys of invalidationTrackers.get(this) ?? []) keys.add(resolved);
|
|
2757
2825
|
this.invalidatedAt.set(resolved, now);
|
|
2758
2826
|
const entry = this.entries.get(resolved);
|
|
2759
2827
|
if (entry) {
|
|
@@ -2773,8 +2841,9 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2773
2841
|
const resolvedInvalidatedAt = this.invalidatedAt.get(resolved);
|
|
2774
2842
|
if (aliasEntry && !this.entries.has(resolved)) {
|
|
2775
2843
|
this.entries.set(resolved, aliasEntry);
|
|
2844
|
+
this.persistence?.onSet(resolved, aliasEntry);
|
|
2776
2845
|
}
|
|
2777
|
-
this.entries.delete(alias);
|
|
2846
|
+
if (this.entries.delete(alias)) this.persistence?.onDelete(alias);
|
|
2778
2847
|
this.invalidatedAt.delete(alias);
|
|
2779
2848
|
const invalidatedAt = [aliasInvalidatedAt, resolvedInvalidatedAt].reduce(
|
|
2780
2849
|
(latest, value) => value === void 0 ? latest : latest === void 0 ? value : Math.max(latest, value),
|
|
@@ -2814,7 +2883,9 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2814
2883
|
listeners2.add(listener);
|
|
2815
2884
|
return () => {
|
|
2816
2885
|
listeners2.delete(listener);
|
|
2817
|
-
if (listeners2.size === 0
|
|
2886
|
+
if (listeners2.size === 0 && this.listeners.get(key) === listeners2) {
|
|
2887
|
+
this.listeners.delete(key);
|
|
2888
|
+
}
|
|
2818
2889
|
};
|
|
2819
2890
|
}
|
|
2820
2891
|
getInflight(key) {
|
|
@@ -2826,6 +2897,30 @@ var _FarmClientDataCache = class _FarmClientDataCache {
|
|
|
2826
2897
|
deleteInflight(key) {
|
|
2827
2898
|
this.inflight.delete(this.resolveKey(key));
|
|
2828
2899
|
}
|
|
2900
|
+
scheduleGcSweep() {
|
|
2901
|
+
if (this.gcSweepIntervalMs === false || this.gcTimer !== void 0) return;
|
|
2902
|
+
const timer = setTimeout(() => {
|
|
2903
|
+
this.gcTimer = void 0;
|
|
2904
|
+
this.sweepExpiredEntries();
|
|
2905
|
+
}, this.gcSweepIntervalMs);
|
|
2906
|
+
timer.unref?.();
|
|
2907
|
+
this.gcTimer = timer;
|
|
2908
|
+
}
|
|
2909
|
+
sweepExpiredEntries(now = Date.now()) {
|
|
2910
|
+
const watched = /* @__PURE__ */ new Set();
|
|
2911
|
+
for (const key of this.listeners.keys()) watched.add(this.resolveKey(key));
|
|
2912
|
+
let remaining = false;
|
|
2913
|
+
for (const [key, entry] of this.entries) {
|
|
2914
|
+
if (entry.gcAt === void 0) continue;
|
|
2915
|
+
if (now < entry.gcAt || entry.fetching || this.inflight.has(key) || watched.has(key)) {
|
|
2916
|
+
remaining = true;
|
|
2917
|
+
continue;
|
|
2918
|
+
}
|
|
2919
|
+
this.entries.delete(key);
|
|
2920
|
+
this.persistence?.onDelete(key);
|
|
2921
|
+
}
|
|
2922
|
+
if (remaining) this.scheduleGcSweep();
|
|
2923
|
+
}
|
|
2829
2924
|
emit(key, event) {
|
|
2830
2925
|
this.notifyListeners(key, event);
|
|
2831
2926
|
for (const [alias, target] of this.aliases) {
|
|
@@ -2850,6 +2945,21 @@ function getFarmClientDataCache() {
|
|
|
2850
2945
|
}
|
|
2851
2946
|
__name(getFarmClientDataCache, "getFarmClientDataCache");
|
|
2852
2947
|
|
|
2948
|
+
// src/client-revalidation.ts
|
|
2949
|
+
function attachRevalidationListeners(refresh, options = {}) {
|
|
2950
|
+
if (typeof window === "undefined") return () => {
|
|
2951
|
+
};
|
|
2952
|
+
const onFocus = options.refetchOnWindowFocus === false ? void 0 : refresh;
|
|
2953
|
+
const onOnline = options.refetchOnReconnect === false ? void 0 : refresh;
|
|
2954
|
+
if (onFocus) window.addEventListener("focus", onFocus);
|
|
2955
|
+
if (onOnline) window.addEventListener("online", onOnline);
|
|
2956
|
+
return () => {
|
|
2957
|
+
if (onFocus) window.removeEventListener("focus", onFocus);
|
|
2958
|
+
if (onOnline) window.removeEventListener("online", onOnline);
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
__name(attachRevalidationListeners, "attachRevalidationListeners");
|
|
2962
|
+
|
|
2853
2963
|
// src/server-query-runtime.ts
|
|
2854
2964
|
var FARM_SERVER_QUERY_CLIENT_STATE = /* @__PURE__ */ Symbol.for("farm.serverQueryClientState");
|
|
2855
2965
|
var serverQueryClientGlobal = globalThis;
|
|
@@ -2857,9 +2967,30 @@ var serverQueryClientState = serverQueryClientGlobal[FARM_SERVER_QUERY_CLIENT_ST
|
|
|
2857
2967
|
functionIds: /* @__PURE__ */ new WeakMap(),
|
|
2858
2968
|
nextFunctionId: 0,
|
|
2859
2969
|
active: [],
|
|
2860
|
-
latestOwners: /* @__PURE__ */ new Map()
|
|
2970
|
+
latestOwners: /* @__PURE__ */ new Map(),
|
|
2971
|
+
owners: /* @__PURE__ */ new Set()
|
|
2861
2972
|
});
|
|
2862
2973
|
serverQueryClientState.latestOwners ?? (serverQueryClientState.latestOwners = /* @__PURE__ */ new Map());
|
|
2974
|
+
serverQueryClientState.owners ?? (serverQueryClientState.owners = /* @__PURE__ */ new Set());
|
|
2975
|
+
function isServerQueryOwnerSuperseded(owner, key) {
|
|
2976
|
+
const cache = getFarmClientDataCache();
|
|
2977
|
+
const resolved = cache.resolveKey(key);
|
|
2978
|
+
for (const superseded of owner.supersededKeys ?? []) {
|
|
2979
|
+
if (cache.resolveKey(superseded) === resolved) return true;
|
|
2980
|
+
}
|
|
2981
|
+
return false;
|
|
2982
|
+
}
|
|
2983
|
+
__name(isServerQueryOwnerSuperseded, "isServerQueryOwnerSuperseded");
|
|
2984
|
+
function claimServerQueryKey(owner, key) {
|
|
2985
|
+
if (isServerQueryOwnerSuperseded(owner, key)) return false;
|
|
2986
|
+
const resolved = getFarmClientDataCache().resolveKey(key);
|
|
2987
|
+
for (const older of serverQueryClientState.owners) {
|
|
2988
|
+
if (older === owner) break;
|
|
2989
|
+
older.supersededKeys.add(resolved);
|
|
2990
|
+
}
|
|
2991
|
+
return true;
|
|
2992
|
+
}
|
|
2993
|
+
__name(claimServerQueryKey, "claimServerQueryKey");
|
|
2863
2994
|
var RAW_SERVER_QUERY_SYMBOL = /* @__PURE__ */ Symbol.for("farm.server-query");
|
|
2864
2995
|
function assertNotRawServerQueryInBrowser(query) {
|
|
2865
2996
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
@@ -2873,6 +3004,10 @@ function assertNotRawServerQueryInBrowser(query) {
|
|
|
2873
3004
|
);
|
|
2874
3005
|
}
|
|
2875
3006
|
__name(assertNotRawServerQueryInBrowser, "assertNotRawServerQueryInBrowser");
|
|
3007
|
+
function isCurrentServerQueryOwner(provisionalKey, owner) {
|
|
3008
|
+
return serverQueryClientState.latestOwners.get(provisionalKey) === owner && !isServerQueryOwnerSuperseded(owner, provisionalKey);
|
|
3009
|
+
}
|
|
3010
|
+
__name(isCurrentServerQueryOwner, "isCurrentServerQueryOwner");
|
|
2876
3011
|
function createServerQueryCallKey(query, input) {
|
|
2877
3012
|
let id = serverQueryClientState.functionIds.get(query);
|
|
2878
3013
|
if (!id) {
|
|
@@ -2888,12 +3023,14 @@ async function fetchServerQuery(query, input, options = {}) {
|
|
|
2888
3023
|
const entry = cache.get(provisionalKey);
|
|
2889
3024
|
const stale = cache.isStale(provisionalKey);
|
|
2890
3025
|
const inflight = cache.getInflight(provisionalKey);
|
|
2891
|
-
if (
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
3026
|
+
if (!options.force && entry && stale && (entry.status !== "pending" || entry.updatedAt !== 0) && entry.status !== "error" && (options.swr ?? true)) {
|
|
3027
|
+
if (!inflight) {
|
|
3028
|
+
void executeServerQuery(query, input, provisionalKey, options).catch(() => void 0);
|
|
3029
|
+
}
|
|
2895
3030
|
return entry.data;
|
|
2896
3031
|
}
|
|
3032
|
+
if (inflight && !options.force) return inflight;
|
|
3033
|
+
if (!options.force && entry && !stale && entry.status !== "error") return entry.data;
|
|
2897
3034
|
return executeServerQuery(query, input, provisionalKey, options);
|
|
2898
3035
|
}
|
|
2899
3036
|
__name(fetchServerQuery, "fetchServerQuery");
|
|
@@ -2902,8 +3039,13 @@ async function executeServerQuery(query, input, provisionalKey, options) {
|
|
|
2902
3039
|
const cache = getFarmClientDataCache();
|
|
2903
3040
|
const inflight = cache.getInflight(provisionalKey);
|
|
2904
3041
|
if (inflight && !options.force) return inflight;
|
|
2905
|
-
const owner = {
|
|
3042
|
+
const owner = {
|
|
3043
|
+
invalidations: trackFarmClientCacheInvalidations(cache),
|
|
3044
|
+
supersededKeys: /* @__PURE__ */ new Set()
|
|
3045
|
+
};
|
|
2906
3046
|
serverQueryClientState.latestOwners.set(provisionalKey, owner);
|
|
3047
|
+
serverQueryClientState.owners.add(owner);
|
|
3048
|
+
claimServerQueryKey(owner, provisionalKey);
|
|
2907
3049
|
const previous = cache.get(provisionalKey);
|
|
2908
3050
|
cache.set(provisionalKey, {
|
|
2909
3051
|
data: previous?.data,
|
|
@@ -2928,12 +3070,12 @@ async function executeServerQuery(query, input, provisionalKey, options) {
|
|
|
2928
3070
|
}
|
|
2929
3071
|
const data = await pending;
|
|
2930
3072
|
const transported = cache.get(provisionalKey);
|
|
2931
|
-
if (
|
|
3073
|
+
if (isCurrentServerQueryOwner(provisionalKey, owner) && (!transported || transported.fetching)) {
|
|
2932
3074
|
const updatedAt = Date.now();
|
|
2933
3075
|
cache.set(provisionalKey, {
|
|
2934
3076
|
data,
|
|
2935
3077
|
updatedAt,
|
|
2936
|
-
staleAt: options.staleTime === false ? Number.POSITIVE_INFINITY : updatedAt + (options.staleTime ?? 0),
|
|
3078
|
+
staleAt: owner.invalidations.has(provisionalKey) ? 0 : options.staleTime === false ? Number.POSITIVE_INFINITY : updatedAt + (options.staleTime ?? 0),
|
|
2937
3079
|
status: "success",
|
|
2938
3080
|
error: null,
|
|
2939
3081
|
fetching: false
|
|
@@ -2942,7 +3084,7 @@ async function executeServerQuery(query, input, provisionalKey, options) {
|
|
|
2942
3084
|
return data;
|
|
2943
3085
|
} catch (cause) {
|
|
2944
3086
|
const error = normalizeServerQueryError(cause);
|
|
2945
|
-
if (
|
|
3087
|
+
if (isCurrentServerQueryOwner(provisionalKey, owner)) {
|
|
2946
3088
|
const current = cache.get(provisionalKey);
|
|
2947
3089
|
cache.set(provisionalKey, {
|
|
2948
3090
|
data: current?.data,
|
|
@@ -2957,12 +3099,17 @@ async function executeServerQuery(query, input, provisionalKey, options) {
|
|
|
2957
3099
|
}
|
|
2958
3100
|
throw error;
|
|
2959
3101
|
} finally {
|
|
3102
|
+
const invalidated = isCurrentServerQueryOwner(provisionalKey, owner) && owner.invalidations.has(provisionalKey);
|
|
3103
|
+
owner.invalidations.dispose();
|
|
3104
|
+
serverQueryClientState.owners.delete(owner);
|
|
3105
|
+
owner.supersededKeys.clear();
|
|
2960
3106
|
if (cache.getInflight(provisionalKey) === promise) {
|
|
2961
3107
|
cache.deleteInflight(provisionalKey);
|
|
2962
3108
|
}
|
|
2963
3109
|
if (serverQueryClientState.latestOwners.get(provisionalKey) === owner) {
|
|
2964
3110
|
serverQueryClientState.latestOwners.delete(provisionalKey);
|
|
2965
3111
|
}
|
|
3112
|
+
if (invalidated) cache.invalidate(provisionalKey);
|
|
2966
3113
|
}
|
|
2967
3114
|
})();
|
|
2968
3115
|
cache.setInflight(provisionalKey, promise);
|
|
@@ -3190,19 +3337,15 @@ function createRendererQuery(query, input, options = {}) {
|
|
|
3190
3337
|
for (const listener of listeners2) listener();
|
|
3191
3338
|
});
|
|
3192
3339
|
if (!cache.get(key) || cache.isStale(key)) void run().catch(() => void 0);
|
|
3193
|
-
|
|
3194
|
-
|
|
3340
|
+
cleanupBrowser = attachRevalidationListeners(
|
|
3341
|
+
() => {
|
|
3195
3342
|
if (cache.isStale(key)) void run().catch(() => void 0);
|
|
3196
|
-
},
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
if (onFocus) window.removeEventListener("focus", onFocus);
|
|
3203
|
-
if (onOnline) window.removeEventListener("online", onOnline);
|
|
3204
|
-
}, "cleanupBrowser");
|
|
3205
|
-
}
|
|
3343
|
+
},
|
|
3344
|
+
{
|
|
3345
|
+
refetchOnWindowFocus: options.refetchOnWindowFocus,
|
|
3346
|
+
refetchOnReconnect: options.refetchOnReconnect
|
|
3347
|
+
}
|
|
3348
|
+
);
|
|
3206
3349
|
}, "ensureStarted");
|
|
3207
3350
|
return {
|
|
3208
3351
|
getSnapshot() {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { FarmRouterRouteInput } from './router.mjs';
|
|
2
|
-
import { F as FarmNavigationState, a as FarmNavigateOptions } from './spa-router-
|
|
3
|
-
import { F as FarmClientCacheStatus } from './client-cache-
|
|
2
|
+
import { F as FarmNavigationState, a as FarmNavigateOptions } from './spa-router-BeyAVSc6.mjs';
|
|
3
|
+
import { F as FarmClientCacheStatus } from './client-cache-CCK-fCe0.mjs';
|
|
4
4
|
import { ServerFn } from './server-fn.mjs';
|
|
5
5
|
import { ServerQuery } from './server-query.mjs';
|
|
6
|
-
import { S as ServerQueryFetchOptions } from './server-query-runtime-
|
|
6
|
+
import { S as ServerQueryFetchOptions } from './server-query-runtime-aP52iuL5.mjs';
|
|
7
7
|
import { F as FarmThemeSnapshot, a as FarmThemePreference } from './types-DQnyD3VD.mjs';
|
|
8
8
|
import { F as FarmI18nClientSnapshot, a as FarmTranslator, b as FarmI18nLocale } from './types-CnH8DOqo.mjs';
|
|
9
9
|
import './lifecycle-De0vQG45.mjs';
|
|
10
10
|
import './island-CfGru1MO.mjs';
|
|
11
|
-
import './render-plan-
|
|
12
|
-
import './client-plugins-
|
|
13
|
-
import './route-
|
|
11
|
+
import './render-plan-DLxJYAA5.mjs';
|
|
12
|
+
import './client-plugins-B6-07YmP.mjs';
|
|
13
|
+
import './route-CvEr4Uc9.mjs';
|
|
14
14
|
import './cache.mjs';
|
|
15
15
|
import './renderer.mjs';
|
|
16
16
|
import 'http';
|
|
@@ -18,6 +18,7 @@ import './types-Cc8l9IqS.mjs';
|
|
|
18
18
|
import 'db0';
|
|
19
19
|
import 'unstorage';
|
|
20
20
|
import 'react';
|
|
21
|
+
import './integration-api-BT024nuJ.mjs';
|
|
21
22
|
import '@farming-labs/orm';
|
|
22
23
|
import './types-CKwggz9n.mjs';
|
|
23
24
|
import '@farming-labs/docs';
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { FarmRouterRouteInput } from './router.js';
|
|
2
|
-
import { F as FarmNavigationState, a as FarmNavigateOptions } from './spa-router-
|
|
3
|
-
import { F as FarmClientCacheStatus } from './client-cache-
|
|
2
|
+
import { F as FarmNavigationState, a as FarmNavigateOptions } from './spa-router-COgu4txb.js';
|
|
3
|
+
import { F as FarmClientCacheStatus } from './client-cache-BMxuFqwH.js';
|
|
4
4
|
import { ServerFn } from './server-fn.js';
|
|
5
5
|
import { ServerQuery } from './server-query.js';
|
|
6
|
-
import { S as ServerQueryFetchOptions } from './server-query-runtime-
|
|
6
|
+
import { S as ServerQueryFetchOptions } from './server-query-runtime-DXRNhX_3.js';
|
|
7
7
|
import { F as FarmThemeSnapshot, a as FarmThemePreference } from './types-DQnyD3VD.js';
|
|
8
8
|
import { F as FarmI18nClientSnapshot, a as FarmTranslator, b as FarmI18nLocale } from './types-CnH8DOqo.js';
|
|
9
9
|
import './lifecycle-De0vQG45.js';
|
|
10
10
|
import './island-CfGru1MO.js';
|
|
11
|
-
import './render-plan-
|
|
12
|
-
import './client-plugins-
|
|
13
|
-
import './route-
|
|
11
|
+
import './render-plan-0GeHiGVZ.js';
|
|
12
|
+
import './client-plugins-By6MVUX-.js';
|
|
13
|
+
import './route-4pd-EVtw.js';
|
|
14
14
|
import './cache.js';
|
|
15
15
|
import './renderer.js';
|
|
16
16
|
import 'http';
|
|
@@ -18,6 +18,7 @@ import './types-Cc8l9IqS.js';
|
|
|
18
18
|
import 'db0';
|
|
19
19
|
import 'unstorage';
|
|
20
20
|
import 'react';
|
|
21
|
+
import './integration-api-BT024nuJ.js';
|
|
21
22
|
import '@farming-labs/orm';
|
|
22
23
|
import './types-CKwggz9n.js';
|
|
23
24
|
import '@farming-labs/docs';
|