@rangojs/router 0.16.0 → 0.18.0
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/README.md +255 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -0
- package/dist/types/browser/navigation-transaction.d.ts +6 -0
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/scroll-restoration.d.ts +7 -0
- package/dist/types/cache/cache-exec-scope.d.ts +18 -1
- package/dist/types/cache/cache-key-utils.d.ts +17 -2
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +132 -19
- package/dist/types/cache/cache-tag.d.ts +92 -7
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +54 -13
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +110 -21
- package/dist/types/cache/tag-invalidation.d.ts +30 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +220 -44
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.rsc.d.ts +4 -5
- package/dist/types/components/DefaultDocument.d.ts +5 -2
- package/dist/types/context-var.d.ts +6 -5
- package/dist/types/escape-script.d.ts +1 -1
- package/dist/types/handles/MetaTags.d.ts +5 -4
- package/dist/types/handles/Scripts.d.ts +8 -7
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/handles/script.d.ts +17 -16
- package/dist/types/href-client.d.ts +1 -1
- package/dist/types/html.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +3 -2
- package/dist/types/loader-store.d.ts +7 -4
- package/dist/types/prerender/build-shell-capture.d.ts +11 -4
- package/dist/types/reverse.d.ts +36 -4
- package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
- package/dist/types/route-definition/helpers-types.d.ts +33 -9
- package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
- package/dist/types/route-types.d.ts +1 -1
- package/dist/types/router/debug-manifest.d.ts +3 -2
- package/dist/types/router/error-handling.d.ts +20 -0
- package/dist/types/router/handler-context.d.ts +6 -0
- package/dist/types/router/instrument.d.ts +8 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +9 -3
- package/dist/types/router/router-context.d.ts +3 -1
- package/dist/types/router/router-interfaces.d.ts +24 -2
- package/dist/types/router/router-options.d.ts +8 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +66 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
- package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
- package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
- package/dist/types/router/segment-wrappers.d.ts +1 -1
- package/dist/types/rsc/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-route-handler.d.ts +1 -1
- package/dist/types/rsc/rsc-rendering.d.ts +1 -2
- package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
- package/dist/types/rsc/shell-capture.d.ts +151 -19
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/context.d.ts +139 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +182 -53
- package/dist/types/ssr/index.d.ts +24 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- package/dist/types/testing/generated-routes.d.ts +2 -2
- package/dist/types/testing/internal/context.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +32 -6
- package/dist/types/testing/run-loader.d.ts +18 -3
- package/dist/types/testing/serve-shell-request.d.ts +132 -0
- package/dist/types/testing/shell-status.d.ts +23 -10
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
- package/dist/types/testing/vitest.d.ts +35 -1
- package/dist/types/theme/ThemeScript.d.ts +3 -3
- package/dist/types/types/cache-types.d.ts +14 -10
- package/dist/types/types/handler-context.d.ts +28 -1
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/pattern-types.d.ts +22 -18
- package/dist/types/urls/response-types.d.ts +3 -12
- package/dist/types/use-loader.d.ts +12 -3
- package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
- package/dist/types/vite/rango.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1420 -1348
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +75 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +306 -124
- package/skills/caching/SKILL.md +530 -98
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +65 -38
- package/skills/cloudflare/SKILL.md +87 -20
- package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
- package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
- package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
- package/skills/comparison/SKILL.md +5 -0
- package/skills/comparison/references/framework-comparison.md +75 -57
- package/skills/composability/SKILL.md +38 -29
- package/skills/css/SKILL.md +10 -13
- package/skills/debug-manifest/SKILL.md +74 -31
- package/skills/defer-hydration/SKILL.md +52 -31
- package/skills/deployment-caching/SKILL.md +11 -3
- package/skills/document-cache/SKILL.md +98 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +55 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +34 -17
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +39 -15
- package/skills/hooks/urls.md +7 -5
- package/skills/host-router/SKILL.md +64 -12
- package/skills/i18n/SKILL.md +60 -34
- package/skills/intercept/SKILL.md +161 -26
- package/skills/layout/SKILL.md +106 -50
- package/skills/links/SKILL.md +51 -19
- package/skills/loader/SKILL.md +386 -128
- package/skills/middleware/SKILL.md +129 -26
- package/skills/migrate-nextjs/SKILL.md +156 -70
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +51 -39
- package/skills/migrate-react-router/component-migration.md +28 -7
- package/skills/migrate-react-router/data-and-actions.md +21 -6
- package/skills/migrate-react-router/route-mapping.md +19 -10
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +92 -14
- package/skills/parallel/SKILL.md +88 -47
- package/skills/ppr/SKILL.md +866 -379
- package/skills/prerender/SKILL.md +210 -108
- package/skills/rango/SKILL.md +115 -65
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +170 -60
- package/skills/router-setup/SKILL.md +420 -240
- package/skills/scripts/SKILL.md +39 -21
- package/skills/server-actions/SKILL.md +231 -59
- package/skills/shell-manifest/SKILL.md +28 -14
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +73 -33
- package/skills/testing/cache-prerender.md +60 -33
- package/skills/testing/client-components.md +59 -6
- package/skills/testing/e2e-parity.md +12 -2
- package/skills/testing/flight.md +19 -11
- package/skills/testing/handles.md +8 -5
- package/skills/testing/loader.md +26 -6
- package/skills/testing/middleware.md +8 -3
- package/skills/testing/predicates.md +120 -0
- package/skills/testing/render-handler.md +70 -22
- package/skills/testing/response-routes.md +11 -4
- package/skills/testing/reverse-and-types.md +20 -14
- package/skills/testing/serve-shell-request.md +188 -0
- package/skills/testing/server-actions.md +12 -3
- package/skills/testing/server-tree.md +9 -0
- package/skills/testing/setup.md +9 -5
- package/skills/theme/SKILL.md +155 -30
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +137 -50
- package/skills/typesafety/generated-files-and-cli.md +26 -14
- package/skills/typesafety/params-and-search.md +44 -19
- package/skills/typesafety/route-types.md +50 -14
- package/skills/use-cache/SKILL.md +224 -83
- package/skills/vercel/SKILL.md +35 -13
- package/skills/view-transitions/SKILL.md +42 -21
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- package/src/browser/index.ts +2 -2
- package/src/browser/navigation-bridge.ts +3 -4
- package/src/browser/navigation-transaction.ts +22 -2
- package/src/browser/partial-update.ts +35 -25
- package/src/browser/react/ScrollRestoration.tsx +6 -6
- package/src/browser/rsc-router.tsx +6 -1
- package/src/browser/scroll-restoration.ts +53 -6
- package/src/cache/cache-exec-scope.ts +37 -4
- package/src/cache/cache-key-utils.ts +23 -8
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +264 -68
- package/src/cache/cache-scope.ts +419 -43
- package/src/cache/cache-tag.ts +375 -11
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +990 -348
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +133 -28
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +108 -22
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +225 -44
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- package/src/client.rsc.tsx +10 -9
- package/src/client.tsx +5 -4
- package/src/components/DefaultDocument.tsx +7 -2
- package/src/context-var.ts +6 -5
- package/src/escape-script.ts +1 -1
- package/src/handles/MetaTags.tsx +13 -11
- package/src/handles/Scripts.tsx +11 -10
- package/src/handles/meta.ts +2 -2
- package/src/handles/script.ts +17 -16
- package/src/href-client.ts +1 -1
- package/src/html.ts +12 -0
- package/src/index.rsc.ts +5 -0
- package/src/index.ts +1 -0
- package/src/loader-store.ts +7 -4
- package/src/prerender/build-shell-capture.ts +73 -22
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +121 -33
- package/src/route-definition/helpers-types.ts +33 -9
- package/src/route-definition/resolve-handler-use.ts +121 -6
- package/src/route-types.ts +0 -3
- package/src/router/debug-manifest.ts +10 -2
- package/src/router/error-handling.ts +51 -15
- package/src/router/handler-context.ts +71 -28
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +141 -43
- package/src/router/loader-resolution.ts +115 -39
- package/src/router/match-api.ts +40 -26
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +110 -10
- package/src/router/match-middleware/cache-store.ts +48 -101
- package/src/router/middleware-types.ts +9 -6
- package/src/router/middleware.ts +75 -13
- package/src/router/prerender-match.ts +59 -19
- package/src/router/route-snapshot.ts +11 -1
- package/src/router/router-context.ts +2 -0
- package/src/router/router-interfaces.ts +25 -2
- package/src/router/router-options.ts +8 -5
- package/src/router/segment-resolution/fresh.ts +62 -21
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +407 -76
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +208 -56
- package/src/router/segment-resolution/mask-nested.ts +138 -44
- package/src/router/segment-resolution/revalidation.ts +61 -16
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/full-payload.ts +25 -1
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/progressive-enhancement.ts +3 -2
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-cache-serve.ts +9 -6
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +608 -225
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +73 -6
- package/src/rsc/shell-capture.ts +1068 -296
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +18 -0
- package/src/server/context.ts +300 -32
- package/src/server/cookie-store.ts +87 -61
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +297 -67
- package/src/ssr/index.tsx +136 -44
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +14 -0
- package/src/testing/generated-routes.ts +2 -2
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/internal/flight-client-globals.ts +7 -5
- package/src/testing/render-route.tsx +85 -24
- package/src/testing/run-loader.ts +68 -6
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +28 -1
- package/src/types/loader-types.ts +8 -6
- package/src/urls/pattern-types.ts +22 -18
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
- package/src/vite/router-discovery.ts +14 -4
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getCurrentLoaderBodyId, isInsideLoaderScope } from "./context.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Handle data structure: handleName -> segmentId -> entries[]
|
|
3
5
|
*
|
|
@@ -45,6 +47,24 @@ function createLateHandlePushError(
|
|
|
45
47
|
return error;
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Per-slot flags, parallel to one handle/segment values array. Allocated on
|
|
52
|
+
* the array's first flagged slot; positions past its length are unflagged.
|
|
53
|
+
*/
|
|
54
|
+
interface SlotTag {
|
|
55
|
+
/** Pushed inside a DSL loader scope; captureHandles drops it. */
|
|
56
|
+
loader?: boolean;
|
|
57
|
+
/** A loader-cache replay of this loader's recorded push (pushReplayed). */
|
|
58
|
+
replayOf?: string;
|
|
59
|
+
/** Pushed by this loader's live run after it replaced its replayed slots. */
|
|
60
|
+
liveOf?: string;
|
|
61
|
+
/** Pushed by this loader's body and kept in records (push `owner`). */
|
|
62
|
+
owner?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Shared by every plain DSL-loader push; tags are never mutated in place.
|
|
66
|
+
const LOADER_SLOT: SlotTag = Object.freeze({ loader: true });
|
|
67
|
+
|
|
48
68
|
function cloneHandleData(data: HandleData): HandleData {
|
|
49
69
|
const clone: HandleData = {};
|
|
50
70
|
for (const handleName in data) {
|
|
@@ -116,8 +136,35 @@ export interface HandleStore {
|
|
|
116
136
|
* Push handle data for a specific handle and segment.
|
|
117
137
|
* Multiple pushes to the same handle/segment accumulate in an array.
|
|
118
138
|
* Each push triggers an emission on the stream.
|
|
139
|
+
*
|
|
140
|
+
* `loaderPush` overrides the push-time DSL-loader tag
|
|
141
|
+
* (isInsideLoaderScope()) that getDataForSegment(id, true) excludes. The
|
|
142
|
+
* PPR shell capture passes false for the bake-lane pushes its record keeps
|
|
143
|
+
* (shell-capture.ts deriveShellCaptureContext), with `owner` set to the
|
|
144
|
+
* pushing loader's id so the record can restore them through pushReplayed
|
|
145
|
+
* (getRecordOwners).
|
|
119
146
|
*/
|
|
120
|
-
push(
|
|
147
|
+
push(
|
|
148
|
+
handleName: string,
|
|
149
|
+
segmentId: string,
|
|
150
|
+
data: unknown,
|
|
151
|
+
loaderPush?: boolean,
|
|
152
|
+
owner?: string,
|
|
153
|
+
): void;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* push() a loader-cache HIT's replayed value, recorded from `loaderId`'s
|
|
157
|
+
* body (loader-cache.ts replayLoaderHandles). If that loader then runs live
|
|
158
|
+
* in this request, its first push removes every value replayed for it and
|
|
159
|
+
* takes the first one's position (later live pushes follow it), so the
|
|
160
|
+
* handle output stays live without a duplicate.
|
|
161
|
+
*/
|
|
162
|
+
pushReplayed(
|
|
163
|
+
handleName: string,
|
|
164
|
+
segmentId: string,
|
|
165
|
+
data: unknown,
|
|
166
|
+
loaderId: string,
|
|
167
|
+
): void;
|
|
121
168
|
|
|
122
169
|
/**
|
|
123
170
|
* Get all collected handle data after all handlers have settled.
|
|
@@ -151,8 +198,23 @@ export interface HandleStore {
|
|
|
151
198
|
/**
|
|
152
199
|
* Get handle data for a specific segment (for caching).
|
|
153
200
|
* Returns data in format: { handleName: [values...] }
|
|
201
|
+
*
|
|
202
|
+
* `excludeLoaderPushes` drops values tagged as DSL-loader pushes at push
|
|
203
|
+
* time (see push); see captureHandles.
|
|
204
|
+
*/
|
|
205
|
+
getDataForSegment(
|
|
206
|
+
segmentId: string,
|
|
207
|
+
excludeLoaderPushes?: boolean,
|
|
208
|
+
): Record<string, unknown[]>;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The push `owner` of each value in getDataForSegment(segmentId, true),
|
|
212
|
+
* index-aligned per handle (null: no owner). Handles without an owned
|
|
213
|
+
* value are omitted; undefined when none has one.
|
|
154
214
|
*/
|
|
155
|
-
|
|
215
|
+
getRecordOwners(
|
|
216
|
+
segmentId: string,
|
|
217
|
+
): Record<string, (string | null)[]> | undefined;
|
|
156
218
|
|
|
157
219
|
/**
|
|
158
220
|
* Replay cached handle data back into the store (for cache hits).
|
|
@@ -186,6 +248,88 @@ export interface HandleStore {
|
|
|
186
248
|
*/
|
|
187
249
|
export function createHandleStore(): HandleStore {
|
|
188
250
|
const data: HandleData = {};
|
|
251
|
+
// SlotTag arrays, keyed by the per-handle/segment values array. Positional
|
|
252
|
+
// (not value identity) so primitive values are covered too.
|
|
253
|
+
// replaySegmentData installs fresh arrays, so restored values are untagged.
|
|
254
|
+
const slotTags = new WeakMap<unknown[], (SlotTag | undefined)[]>();
|
|
255
|
+
// Replayed loaders that have not pushed live yet: loaderId -> the arrays
|
|
256
|
+
// holding their replayed slots.
|
|
257
|
+
const pendingReplays = new Map<string, Set<unknown[]>>();
|
|
258
|
+
// Replayed loaders whose live run already replaced those slots.
|
|
259
|
+
const replacedReplays = new Set<string>();
|
|
260
|
+
|
|
261
|
+
// Aligned to `values` so a mid-array insert or removal keeps positions.
|
|
262
|
+
function tagsFor(values: unknown[]): (SlotTag | undefined)[] {
|
|
263
|
+
let tags = slotTags.get(values);
|
|
264
|
+
if (!tags) slotTags.set(values, (tags = []));
|
|
265
|
+
if (tags.length < values.length) tags.length = values.length;
|
|
266
|
+
return tags;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function insertSlot(
|
|
270
|
+
values: unknown[],
|
|
271
|
+
at: number | undefined,
|
|
272
|
+
value: unknown,
|
|
273
|
+
tag: SlotTag | undefined,
|
|
274
|
+
): void {
|
|
275
|
+
if (at === undefined || at >= values.length) {
|
|
276
|
+
values.push(value);
|
|
277
|
+
if (tag) tagsFor(values)[values.length - 1] = tag;
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const tags = tagsFor(values);
|
|
281
|
+
values.splice(at, 0, value);
|
|
282
|
+
tags.splice(at, 0, tag);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Remove `loaderId`'s replayed slots; returns the first one's position.
|
|
286
|
+
function removeReplayedSlots(
|
|
287
|
+
values: unknown[],
|
|
288
|
+
loaderId: string,
|
|
289
|
+
): number | undefined {
|
|
290
|
+
const tags = slotTags.get(values);
|
|
291
|
+
if (!tags) return undefined;
|
|
292
|
+
let first: number | undefined;
|
|
293
|
+
let kept = 0;
|
|
294
|
+
for (let i = 0; i < values.length; i++) {
|
|
295
|
+
if (tags[i]?.replayOf === loaderId) {
|
|
296
|
+
first ??= kept;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
values[kept] = values[i];
|
|
300
|
+
tags[kept] = tags[i];
|
|
301
|
+
kept++;
|
|
302
|
+
}
|
|
303
|
+
values.length = kept;
|
|
304
|
+
tags.length = kept;
|
|
305
|
+
return first;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Where a live push by a replayed loader lands in `values`: its first push
|
|
309
|
+
// removes all of its replayed slots and takes the first one's position in
|
|
310
|
+
// this array; later pushes follow its previous live push. undefined appends.
|
|
311
|
+
function liveReplacementIndex(
|
|
312
|
+
loaderId: string,
|
|
313
|
+
values: unknown[],
|
|
314
|
+
): number | undefined {
|
|
315
|
+
const pending = pendingReplays.get(loaderId);
|
|
316
|
+
if (pending) {
|
|
317
|
+
pendingReplays.delete(loaderId);
|
|
318
|
+
replacedReplays.add(loaderId);
|
|
319
|
+
let at: number | undefined;
|
|
320
|
+
for (const replayed of pending) {
|
|
321
|
+
const first = removeReplayedSlots(replayed, loaderId);
|
|
322
|
+
if (replayed === values) at = first;
|
|
323
|
+
}
|
|
324
|
+
return at;
|
|
325
|
+
}
|
|
326
|
+
const tags = slotTags.get(values);
|
|
327
|
+
if (!tags) return undefined;
|
|
328
|
+
for (let i = tags.length - 1; i >= 0; i--) {
|
|
329
|
+
if (tags[i]?.liveOf === loaderId) return i + 1;
|
|
330
|
+
}
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
189
333
|
|
|
190
334
|
// Settlement barriers: `settled` (handler lane) resolves when sealed AND
|
|
191
335
|
// handler inflight === 0. `fullySettled` additionally waits for the
|
|
@@ -320,7 +464,13 @@ export function createHandleStore(): HandleStore {
|
|
|
320
464
|
});
|
|
321
465
|
},
|
|
322
466
|
|
|
323
|
-
push(
|
|
467
|
+
push(
|
|
468
|
+
handleName: string,
|
|
469
|
+
segmentId: string,
|
|
470
|
+
value: unknown,
|
|
471
|
+
loaderPush?: boolean,
|
|
472
|
+
owner?: string,
|
|
473
|
+
): void {
|
|
324
474
|
if (completed) {
|
|
325
475
|
const error = createLateHandlePushError(handleName, segmentId);
|
|
326
476
|
if (this.onError) this.onError(error);
|
|
@@ -333,13 +483,58 @@ export function createHandleStore(): HandleStore {
|
|
|
333
483
|
if (!data[handleName][segmentId]) {
|
|
334
484
|
data[handleName][segmentId] = [];
|
|
335
485
|
}
|
|
336
|
-
data[handleName][segmentId]
|
|
486
|
+
const values = data[handleName][segmentId];
|
|
487
|
+
const loader = (loaderPush ?? isInsideLoaderScope()) || undefined;
|
|
488
|
+
let at: number | undefined;
|
|
489
|
+
let liveOf: string | undefined;
|
|
490
|
+
if (pendingReplays.size > 0 || replacedReplays.size > 0) {
|
|
491
|
+
const bodyId = getCurrentLoaderBodyId();
|
|
492
|
+
if (
|
|
493
|
+
bodyId !== undefined &&
|
|
494
|
+
(pendingReplays.has(bodyId) || replacedReplays.has(bodyId))
|
|
495
|
+
) {
|
|
496
|
+
at = liveReplacementIndex(bodyId, values);
|
|
497
|
+
liveOf = bodyId;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
insertSlot(
|
|
501
|
+
values,
|
|
502
|
+
at,
|
|
503
|
+
value,
|
|
504
|
+
liveOf || owner
|
|
505
|
+
? { loader, liveOf, owner }
|
|
506
|
+
: loader
|
|
507
|
+
? LOADER_SLOT
|
|
508
|
+
: undefined,
|
|
509
|
+
);
|
|
337
510
|
|
|
338
511
|
// Bump the version; each consumer's cursor decides when to clone+yield.
|
|
339
512
|
version++;
|
|
340
513
|
signalEmission();
|
|
341
514
|
},
|
|
342
515
|
|
|
516
|
+
pushReplayed(
|
|
517
|
+
handleName: string,
|
|
518
|
+
segmentId: string,
|
|
519
|
+
value: unknown,
|
|
520
|
+
loaderId: string,
|
|
521
|
+
): void {
|
|
522
|
+
const before = data[handleName]?.[segmentId]?.length ?? 0;
|
|
523
|
+
// Through this.push: active captures see the replay like a live push.
|
|
524
|
+
this.push(handleName, segmentId, value);
|
|
525
|
+
const values = data[handleName]?.[segmentId];
|
|
526
|
+
// A diverting capture kept it out of the store.
|
|
527
|
+
if (!values || values.length !== before + 1) return;
|
|
528
|
+
const tags = tagsFor(values);
|
|
529
|
+
tags[values.length - 1] = {
|
|
530
|
+
...tags[values.length - 1],
|
|
531
|
+
replayOf: loaderId,
|
|
532
|
+
};
|
|
533
|
+
let arrays = pendingReplays.get(loaderId);
|
|
534
|
+
if (!arrays) pendingReplays.set(loaderId, (arrays = new Set()));
|
|
535
|
+
arrays.add(values);
|
|
536
|
+
},
|
|
537
|
+
|
|
343
538
|
getData(): Promise<HandleData> {
|
|
344
539
|
sealInternal();
|
|
345
540
|
return this.settled.then(() => cloneHandleData(data));
|
|
@@ -417,12 +612,42 @@ export function createHandleStore(): HandleStore {
|
|
|
417
612
|
}
|
|
418
613
|
},
|
|
419
614
|
|
|
420
|
-
getDataForSegment(
|
|
615
|
+
getDataForSegment(
|
|
616
|
+
segmentId: string,
|
|
617
|
+
excludeLoaderPushes?: boolean,
|
|
618
|
+
): Record<string, unknown[]> {
|
|
421
619
|
const result: Record<string, unknown[]> = {};
|
|
422
620
|
for (const handleName in data) {
|
|
423
|
-
|
|
424
|
-
|
|
621
|
+
const values = data[handleName][segmentId];
|
|
622
|
+
if (!values) continue;
|
|
623
|
+
const tags = excludeLoaderPushes ? slotTags.get(values) : undefined;
|
|
624
|
+
if (!tags) {
|
|
625
|
+
result[handleName] = [...values];
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const kept = values.filter((_, i) => !tags[i]?.loader);
|
|
629
|
+
if (kept.length > 0) result[handleName] = kept;
|
|
630
|
+
}
|
|
631
|
+
return result;
|
|
632
|
+
},
|
|
633
|
+
|
|
634
|
+
getRecordOwners(
|
|
635
|
+
segmentId: string,
|
|
636
|
+
): Record<string, (string | null)[]> | undefined {
|
|
637
|
+
let result: Record<string, (string | null)[]> | undefined;
|
|
638
|
+
for (const handleName in data) {
|
|
639
|
+
const values = data[handleName][segmentId];
|
|
640
|
+
const tags = values && slotTags.get(values);
|
|
641
|
+
if (!tags) continue;
|
|
642
|
+
const owners: (string | null)[] = [];
|
|
643
|
+
let owned = false;
|
|
644
|
+
for (let i = 0; i < values.length; i++) {
|
|
645
|
+
if (tags[i]?.loader) continue;
|
|
646
|
+
const owner = tags[i]?.owner ?? null;
|
|
647
|
+
if (owner) owned = true;
|
|
648
|
+
owners.push(owner);
|
|
425
649
|
}
|
|
650
|
+
if (owned) (result ??= {})[handleName] = owners;
|
|
426
651
|
}
|
|
427
652
|
return result;
|
|
428
653
|
},
|