@rangojs/router 0.20.0 → 0.22.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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +29 -4
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/build-shell-capture.d.ts +8 -6
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +12 -6
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/build-shell-capture.ts +11 -9
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -24,6 +24,14 @@ import { join, resolve } from "node:path";
|
|
|
24
24
|
import { jsonParseExpression } from "../utils/manifest-utils.js";
|
|
25
25
|
import { writeBuildAssetModule } from "../utils/prerender-utils.js";
|
|
26
26
|
import { buildShellManifestKey } from "../../prerender/shell-manifest-key.js";
|
|
27
|
+
import {
|
|
28
|
+
resolveVersionsFrom,
|
|
29
|
+
type RouterVersionsTable,
|
|
30
|
+
} from "../../router-versions.js";
|
|
31
|
+
import {
|
|
32
|
+
environmentOutDir,
|
|
33
|
+
type BuilderLike,
|
|
34
|
+
} from "./router-versions-phase.js";
|
|
27
35
|
// Type-only: the producer stages exactly the record shape the runtime
|
|
28
36
|
// read-through consumes, so the contract cannot drift (the KEY half of that
|
|
29
37
|
// contract is shell-manifest-key.ts). No runtime coupling — the RSC-runtime
|
|
@@ -35,30 +43,22 @@ import { createRangoDebugger, NS } from "../debug.js";
|
|
|
35
43
|
const debug = createRangoDebugger(NS.prerender);
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
46
|
+
* @param versionsTable The versions the shipped build serves with
|
|
47
|
+
* (router-versions-phase.ts), `undefined` outside a build. Never the temp
|
|
48
|
+
* server's own version-plugin stamp, which is a dev Date.now() and would
|
|
49
|
+
* fail the serve-side isValidShellHit gate forever.
|
|
40
50
|
*/
|
|
41
|
-
interface BuilderLike {
|
|
42
|
-
config?: {
|
|
43
|
-
base?: string;
|
|
44
|
-
plugins?: readonly unknown[];
|
|
45
|
-
};
|
|
46
|
-
environments?: Record<
|
|
47
|
-
string,
|
|
48
|
-
{ config?: { build?: { outDir?: string } } } | undefined
|
|
49
|
-
>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
51
|
export async function runShellPrerenderPhase(
|
|
53
52
|
s: DiscoveryState,
|
|
54
53
|
builder: BuilderLike | undefined,
|
|
54
|
+
versionsTable: RouterVersionsTable | undefined,
|
|
55
55
|
): Promise<void> {
|
|
56
56
|
// The kept temp server (and the buildEnv deferred with it) is OWNED by the
|
|
57
57
|
// callers — the buildApp post hook's finally on success, buildEnd on an
|
|
58
58
|
// aborted build — so this function stays a pure producer: it only tears
|
|
59
59
|
// down the globals it installs itself.
|
|
60
60
|
const tempServer = s.shellPhaseTempServer;
|
|
61
|
-
if (!
|
|
61
|
+
if (!versionsTable || !s.shellCandidates?.length || !tempServer) return;
|
|
62
62
|
|
|
63
63
|
const candidates: ShellPrerenderCandidate[] = s.shellCandidates;
|
|
64
64
|
const startTotal = performance.now();
|
|
@@ -87,21 +87,6 @@ export async function runShellPrerenderPhase(
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
// The MAIN build's version (the value folded into the shipped worker) —
|
|
91
|
-
// never the temp server's own version-plugin stamp, which is a different
|
|
92
|
-
// Date.now() and would fail the serve-side isValidShellHit gate forever.
|
|
93
|
-
const versionPlugin = (builder?.config?.plugins ?? []).find(
|
|
94
|
-
(p: any) => p?.name === "@rangojs/router:version",
|
|
95
|
-
) as { api?: { getBuildVersion?: () => string } } | undefined;
|
|
96
|
-
const buildVersion = versionPlugin?.api?.getBuildVersion?.();
|
|
97
|
-
if (!buildVersion) {
|
|
98
|
-
console.warn(
|
|
99
|
-
"[rango] shell prerender: main build version unavailable; skipping — " +
|
|
100
|
-
"routes keep runtime shell capture.",
|
|
101
|
-
);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
90
|
// In-realm prerender store over the retained phase-A payloads, so the
|
|
106
91
|
// capture's match() re-enters withCacheLookup and REPLAYS the build-time
|
|
107
92
|
// segments (globalThis is shared between the plugin process and the temp
|
|
@@ -130,9 +115,7 @@ export async function runShellPrerenderPhase(
|
|
|
130
115
|
);
|
|
131
116
|
|
|
132
117
|
// Built client bootstrap: the prelude must embed the BUILT entry URL.
|
|
133
|
-
const clientOutDir =
|
|
134
|
-
builder?.environments?.client?.config?.build?.outDir ??
|
|
135
|
-
resolve(s.projectRoot, "dist/client");
|
|
118
|
+
const clientOutDir = environmentOutDir(builder, s.projectRoot, "client");
|
|
136
119
|
const clientAssetsDir = join(clientOutDir, "assets");
|
|
137
120
|
const entryFile = existsSync(clientAssetsDir)
|
|
138
121
|
? readdirSync(clientAssetsDir).find((f) => /^index-.*\.js$/.test(f))
|
|
@@ -223,10 +206,10 @@ export async function runShellPrerenderPhase(
|
|
|
223
206
|
const staged: Array<{ key: string; value: string }> = [];
|
|
224
207
|
let skipCount = 0;
|
|
225
208
|
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
// would be ambiguous
|
|
229
|
-
// entries rather than bake a wrong-router shell.
|
|
209
|
+
// A candidate names no router (the sweep below gives it to the first one
|
|
210
|
+
// whose match lands on its route): two candidates on one pathname (two
|
|
211
|
+
// routers prerendering the same path) would be ambiguous — decline ALL of
|
|
212
|
+
// that pathname's entries rather than bake a wrong-router shell.
|
|
230
213
|
const pathCounts = new Map<string, number>();
|
|
231
214
|
for (const cand of candidates) {
|
|
232
215
|
pathCounts.set(cand.urlPath, (pathCounts.get(cand.urlPath) ?? 0) + 1);
|
|
@@ -245,8 +228,14 @@ export async function runShellPrerenderPhase(
|
|
|
245
228
|
const mainKey = `${cand.routeName}/${cand.paramHash}`;
|
|
246
229
|
let handled = false;
|
|
247
230
|
const mismatches: string[] = [];
|
|
248
|
-
for (const [, routerInstance] of registry) {
|
|
231
|
+
for (const [routerId, routerInstance] of registry) {
|
|
249
232
|
if (typeof routerInstance.match !== "function") continue;
|
|
233
|
+
// The build's table always holds the whole-build pair.
|
|
234
|
+
const versions = resolveVersionsFrom(
|
|
235
|
+
versionsTable,
|
|
236
|
+
routerId,
|
|
237
|
+
routerInstance.version,
|
|
238
|
+
)!;
|
|
250
239
|
try {
|
|
251
240
|
const res = await captureMod.captureShellForBuild({
|
|
252
241
|
router: routerInstance,
|
|
@@ -259,7 +248,7 @@ export async function runShellPrerenderPhase(
|
|
|
259
248
|
maxSnapshotBytes: policy.maxSnapshotBytes,
|
|
260
249
|
captureTimeout: policy.captureTimeout,
|
|
261
250
|
buildEnv: s.resolvedBuildEnv,
|
|
262
|
-
|
|
251
|
+
versions,
|
|
263
252
|
captureShellHTML,
|
|
264
253
|
debug: !!debug,
|
|
265
254
|
});
|
|
@@ -293,7 +282,7 @@ export async function runShellPrerenderPhase(
|
|
|
293
282
|
tags: res.tags,
|
|
294
283
|
};
|
|
295
284
|
staged.push({
|
|
296
|
-
key: buildShellManifestKey(cand.urlPath),
|
|
285
|
+
key: buildShellManifestKey(routerId, cand.urlPath),
|
|
297
286
|
value: JSON.stringify(value),
|
|
298
287
|
});
|
|
299
288
|
console.log(
|
|
@@ -323,10 +312,11 @@ export async function runShellPrerenderPhase(
|
|
|
323
312
|
}
|
|
324
313
|
|
|
325
314
|
if (staged.length > 0) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
315
|
+
writeShellManifest(
|
|
316
|
+
s,
|
|
317
|
+
environmentOutDir(builder, s.projectRoot, "rsc"),
|
|
318
|
+
staged,
|
|
319
|
+
);
|
|
330
320
|
}
|
|
331
321
|
|
|
332
322
|
const totalElapsed = (performance.now() - startTotal).toFixed(0);
|
|
@@ -10,6 +10,7 @@ import type { ScanFilter } from "../../build/generate-route-types.js";
|
|
|
10
10
|
import type { ClientUrlProjection } from "../../client-urls/server-projection.js";
|
|
11
11
|
|
|
12
12
|
export const VIRTUAL_ROUTES_MANIFEST_ID = "virtual:rsc-router/routes-manifest";
|
|
13
|
+
export const VIRTUAL_LOADER_MANIFEST_ID = "virtual:rsc-router/loader-manifest";
|
|
13
14
|
|
|
14
15
|
export interface PluginOptions {
|
|
15
16
|
enableBuildPrerender?: boolean;
|
|
@@ -60,7 +61,12 @@ export interface PrecomputedEntry {
|
|
|
60
61
|
|
|
61
62
|
export interface ChunkInfo {
|
|
62
63
|
fileName: string;
|
|
63
|
-
exports: Array<{
|
|
64
|
+
exports: Array<{
|
|
65
|
+
name: string;
|
|
66
|
+
handlerId: string;
|
|
67
|
+
passthrough: boolean;
|
|
68
|
+
onDemand: boolean;
|
|
69
|
+
}>;
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
export interface PerRouterManifestEntry {
|
|
@@ -147,8 +153,31 @@ export interface DiscoveryState {
|
|
|
147
153
|
* buildEnd (aborted build).
|
|
148
154
|
*/
|
|
149
155
|
shellPhaseTempServer: import("vite").ViteDevServer | null;
|
|
156
|
+
/**
|
|
157
|
+
* Inputs of the per-router cache versions (build-versions.ts), recorded by
|
|
158
|
+
* generateBundle. plugin-rsc builds the RSC and SSR environments twice (a
|
|
159
|
+
* scan pass, then the real pass); each pass overwrites its slot, so the
|
|
160
|
+
* buildApp post hook reads the real pass.
|
|
161
|
+
*/
|
|
162
|
+
serverBuildGraph: import("./build-versions.js").ServerBuildGraph | null;
|
|
163
|
+
clientBuildGraph: import("./build-versions.js").ClientBuildGraph | null;
|
|
164
|
+
ssrBundle: import("./build-versions.js").BundleFiles | null;
|
|
165
|
+
/** Per environment, the chunk files holding the version module. */
|
|
166
|
+
versionModuleFiles: Map<string, string[]>;
|
|
167
|
+
/** Prerender and Static payloads the build rendered, by content digest. */
|
|
168
|
+
buildData: import("./build-versions.js").BuildDataRecord[];
|
|
150
169
|
handlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
151
170
|
staticHandlerChunkInfoMap: Map<string, ChunkInfo>;
|
|
171
|
+
/**
|
|
172
|
+
* handlerId ($$id) -> route name for every route the evaluated source marks
|
|
173
|
+
* onDemand. Written during discovery (buildStart), consumed by the
|
|
174
|
+
* generateBundle chunk scan (extractHandlerExportsFromChunk) as the
|
|
175
|
+
* authoritative onDemand set driving producer retention — the same source
|
|
176
|
+
* that sets the runtime od trie flag, so any truthy onDemand spelling
|
|
177
|
+
* (literal, spread, imported const) both marks the route and retains its
|
|
178
|
+
* producer.
|
|
179
|
+
*/
|
|
180
|
+
onDemandHandlerIds: Map<string, string>;
|
|
152
181
|
rscEntryFileName: string | null;
|
|
153
182
|
resolvedPrerenderModules: Map<string, string[]> | undefined;
|
|
154
183
|
resolvedStaticModules: Map<string, string[]> | undefined;
|
|
@@ -204,8 +233,14 @@ export function createDiscoveryState(
|
|
|
204
233
|
shellCandidates: null,
|
|
205
234
|
prerenderPayloadValues: null,
|
|
206
235
|
shellPhaseTempServer: null,
|
|
236
|
+
serverBuildGraph: null,
|
|
237
|
+
clientBuildGraph: null,
|
|
238
|
+
ssrBundle: null,
|
|
239
|
+
versionModuleFiles: new Map(),
|
|
240
|
+
buildData: [],
|
|
207
241
|
handlerChunkInfoMap: new Map(),
|
|
208
242
|
staticHandlerChunkInfoMap: new Map(),
|
|
243
|
+
onDemandHandlerIds: new Map(),
|
|
209
244
|
rscEntryFileName: null,
|
|
210
245
|
resolvedPrerenderModules: undefined,
|
|
211
246
|
resolvedStaticModules: undefined,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { dirname, basename, join } from "node:path";
|
|
10
10
|
import { jsonParseExpression } from "../utils/manifest-utils.js";
|
|
11
|
+
import { compareStrings } from "../utils/compare-strings.js";
|
|
11
12
|
import { VIRTUAL_ROUTES_MANIFEST_ID } from "./state.js";
|
|
12
13
|
import type { DiscoveryState } from "./state.js";
|
|
13
14
|
|
|
@@ -111,8 +112,12 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
|
|
|
111
112
|
|
|
112
113
|
if (hasClientUrlModules) {
|
|
113
114
|
lines.push(`clearClientUrlProjections();`);
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
// Sorted: the map fills in transform order, which varies between runs,
|
|
116
|
+
// and this module's bytes feed cache versions (build-versions.ts).
|
|
117
|
+
const projections = [...(state.clientUrlProjectionMap ?? [])].sort(
|
|
118
|
+
([a], [b]) => compareStrings(a, b),
|
|
119
|
+
);
|
|
120
|
+
for (const [referenceId, projection] of projections) {
|
|
116
121
|
lines.push(
|
|
117
122
|
`setClientUrlProjection(${JSON.stringify(referenceId)}, ${jsonParseExpression(projection)});`,
|
|
118
123
|
);
|
|
@@ -9,17 +9,104 @@ import { randomBytes } from "node:crypto";
|
|
|
9
9
|
// via plugin-rsc's `defineEncryptionKey` so build-time-encrypted bound args
|
|
10
10
|
// decrypt at runtime.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
// buildStart) and the main build share one key.
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
|
|
12
|
+
// Resolved once per process so the temp server (created during the main
|
|
13
|
+
// build's buildStart) and the main build share one key. Source order:
|
|
14
|
+
// rango({ encryptionKey }), then RANGO_ENCRYPTION_KEY, then a key generated for
|
|
15
|
+
// this build. Only the first two are stable across builds.
|
|
16
|
+
//
|
|
17
|
+
// The key is part of the cache version of every router whose server code
|
|
18
|
+
// encrypts with it (discovery/build-versions.ts adds the emitted key file to
|
|
19
|
+
// that router's hash): a payload cached under the old key carries bound args
|
|
20
|
+
// the new build cannot decrypt. So a generated key gives those routers a new
|
|
21
|
+
// version on every build, which is correct and also means their cache is
|
|
22
|
+
// cleared on every deploy.
|
|
23
|
+
|
|
24
|
+
/** AES key sizes Web Crypto imports for AES-GCM, in bytes. */
|
|
25
|
+
const AES_KEY_BYTES: ReadonlySet<number> = new Set([16, 24, 32]);
|
|
26
|
+
|
|
27
|
+
const EXPECTED =
|
|
28
|
+
"a base64-encoded AES key of 16, 24 or 32 bytes (openssl rand -base64 32)";
|
|
29
|
+
|
|
30
|
+
interface ResolvedEncryptionKey {
|
|
31
|
+
key: string;
|
|
32
|
+
/** True when the consumer supplied the key (option or env variable). */
|
|
33
|
+
stable: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let resolvedKey: ResolvedEncryptionKey | undefined;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Throws unless `value` is the base64 form of an AES key (16, 24 or 32 bytes).
|
|
40
|
+
* `source` names where the value came from, for the message.
|
|
41
|
+
*/
|
|
42
|
+
export function assertValidEncryptionKey(value: unknown, source: string): void {
|
|
43
|
+
if (typeof value !== "string") {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`[rango] ${source} must be a string, received ${typeof value}. Expected ${EXPECTED}.`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
if (value === "") {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`[rango] ${source} is an empty string. Unset it to generate a key per build, ` +
|
|
51
|
+
`or set it to ${EXPECTED}.`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const bytes = /^[A-Za-z0-9+/]+={0,2}$/.test(value)
|
|
55
|
+
? Buffer.from(value, "base64")
|
|
56
|
+
: undefined;
|
|
57
|
+
// Buffer.from tolerates malformed base64 by dropping what it cannot decode;
|
|
58
|
+
// the round-trip rejects those inputs instead of using a shorter key.
|
|
59
|
+
if (
|
|
60
|
+
!bytes ||
|
|
61
|
+
bytes.toString("base64").replace(/=+$/, "") !== value.replace(/=+$/, "")
|
|
62
|
+
) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`[rango] ${source} is not valid base64. Expected ${EXPECTED}.`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (!AES_KEY_BYTES.has(bytes.length)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`[rango] ${source} decodes to ${bytes.length} bytes. Expected ${EXPECTED}.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the build's encryption key from rango({ encryptionKey }) or the
|
|
76
|
+
* RANGO_ENCRYPTION_KEY fallback, validating whichever is set. Called by
|
|
77
|
+
* rango() at config time, before any plugin-rsc instance reads the key, so an
|
|
78
|
+
* invalid key fails the config load instead of the first encrypted action.
|
|
79
|
+
* A key generated earlier in the process is kept when neither source is set:
|
|
80
|
+
* the discovery temp server must encrypt with the main build's key.
|
|
81
|
+
*/
|
|
82
|
+
export function configureEncryptionKey(option: string | undefined): void {
|
|
83
|
+
if (option !== undefined) {
|
|
84
|
+
assertValidEncryptionKey(option, "rango({ encryptionKey })");
|
|
85
|
+
resolvedKey = { key: option, stable: true };
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const fromEnv = process.env.RANGO_ENCRYPTION_KEY;
|
|
89
|
+
if (fromEnv !== undefined) {
|
|
90
|
+
assertValidEncryptionKey(fromEnv, "RANGO_ENCRYPTION_KEY");
|
|
91
|
+
resolvedKey = { key: fromEnv, stable: true };
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (resolvedKey && !resolvedKey.stable) return;
|
|
95
|
+
resolvedKey = { key: randomBytes(32).toString("base64"), stable: false };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function resolved(): ResolvedEncryptionKey {
|
|
99
|
+
if (!resolvedKey) configureEncryptionKey(undefined);
|
|
100
|
+
return resolvedKey!;
|
|
101
|
+
}
|
|
18
102
|
|
|
19
103
|
export function buildEncryptionKey(): string {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
104
|
+
return resolved().key;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** False when this build generated its own key (it differs on every build). */
|
|
108
|
+
export function isEncryptionKeyStable(): boolean {
|
|
109
|
+
return resolved().stable;
|
|
23
110
|
}
|
|
24
111
|
|
|
25
112
|
// The value plugin-rsc inlines as `export default () => (<expr>)`. A JSON string
|
|
@@ -27,3 +114,8 @@ export function buildEncryptionKey(): string {
|
|
|
27
114
|
export function defineEncryptionKeyExpr(): string {
|
|
28
115
|
return JSON.stringify(buildEncryptionKey());
|
|
29
116
|
}
|
|
117
|
+
|
|
118
|
+
/** @internal Test seam: forget the process-wide key. */
|
|
119
|
+
export function resetEncryptionKeyForTests(): void {
|
|
120
|
+
resolvedKey = undefined;
|
|
121
|
+
}
|
|
@@ -12,37 +12,59 @@ import type { Connect } from "vite";
|
|
|
12
12
|
* runs on the module regardless of how (or whether) the define is delivered, in
|
|
13
13
|
* both dev and build and for every environment, so the discovery plugin uses this
|
|
14
14
|
* to replace the module with the resolved literal.
|
|
15
|
+
*
|
|
16
|
+
* internal-suspense-audit.ts takes the same path for INTERNAL_RANGO_SUSPENSE_AUDIT,
|
|
17
|
+
* the repo-only switch of the dev suspense audit.
|
|
15
18
|
*/
|
|
16
19
|
|
|
20
|
+
// The router's flag modules, by file name: each exports one boolean named after
|
|
21
|
+
// the env var it is baked from.
|
|
22
|
+
const FLAG_MODULE =
|
|
23
|
+
/\/(internal-debug|internal-suspense-audit)\.[cm]?[jt]sx?(\?|$)/;
|
|
24
|
+
const FLAG_NAMES: Record<string, string> = {
|
|
25
|
+
"internal-debug": "INTERNAL_RANGO_DEBUG",
|
|
26
|
+
"internal-suspense-audit": "INTERNAL_RANGO_SUSPENSE_AUDIT",
|
|
27
|
+
};
|
|
28
|
+
|
|
17
29
|
/**
|
|
18
|
-
*
|
|
19
|
-
* (`/@rangojs/router/`, incl.
|
|
20
|
-
* (`/packages/rangojs-router/`).
|
|
21
|
-
* consumer file that merely sits
|
|
22
|
-
* Accepts module ids and dev-server
|
|
30
|
+
* The env var a router flag module is baked from, or undefined. Scoped to the
|
|
31
|
+
* router's own modules: the published package (`/@rangojs/router/`, incl.
|
|
32
|
+
* pnpm's nested layout) or the monorepo workspace (`/packages/rangojs-router/`).
|
|
33
|
+
* The package-anchored path avoids matching a consumer file that merely sits
|
|
34
|
+
* under a directory named `rangojs-router`. Accepts module ids and dev-server
|
|
35
|
+
* URLs (`/@fs/...internal-debug.ts?v=abc`).
|
|
23
36
|
*/
|
|
24
|
-
|
|
25
|
-
if (!id.includes("internal-
|
|
37
|
+
function routerFlagName(id: string): string | undefined {
|
|
38
|
+
if (!id.includes("internal-")) return undefined;
|
|
26
39
|
const norm = id.replace(/\\/g, "/");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
if (
|
|
41
|
+
!norm.includes("/@rangojs/router/") &&
|
|
42
|
+
!norm.includes("/packages/rangojs-router/")
|
|
43
|
+
) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const match = FLAG_MODULE.exec(norm);
|
|
47
|
+
return match ? FLAG_NAMES[match[1]!] : undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A router flag module: internal-debug.ts or internal-suspense-audit.ts. */
|
|
51
|
+
export function isRouterInternalDebugId(id: string): boolean {
|
|
52
|
+
return routerFlagName(id) !== undefined;
|
|
32
53
|
}
|
|
33
54
|
|
|
34
55
|
/**
|
|
35
|
-
* Transform: replace
|
|
36
|
-
* Returns null for any
|
|
56
|
+
* Transform: replace a router flag module with the resolved literal.
|
|
57
|
+
* Returns null for any other module.
|
|
37
58
|
*/
|
|
38
59
|
export function injectClientDebugFlag(
|
|
39
60
|
id: string,
|
|
40
61
|
): { code: string; map: null } | null {
|
|
41
62
|
// Cheap early-out: this hook runs on every module in every environment.
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
const name = routerFlagName(id);
|
|
64
|
+
if (name === undefined) return null;
|
|
65
|
+
// Emit the whole module: each flag module has a single export, kept in sync.
|
|
44
66
|
return {
|
|
45
|
-
code: `export const
|
|
67
|
+
code: `export const ${name} = ${!!process.env[name]};\n`,
|
|
46
68
|
map: null,
|
|
47
69
|
};
|
|
48
70
|
}
|
|
@@ -63,9 +85,9 @@ export function injectClientDebugFlag(
|
|
|
63
85
|
* immune -- workspace source is outside node_modules and served no-cache --
|
|
64
86
|
* which is why this bit only npm consumers.
|
|
65
87
|
*
|
|
66
|
-
*
|
|
67
|
-
* are byte-identical across flag states), so forcing revalidation for
|
|
68
|
-
*
|
|
88
|
+
* The two flag modules are the only flag-varying modules in the graph (their
|
|
89
|
+
* importers are byte-identical across flag states), so forcing revalidation for
|
|
90
|
+
* them is sufficient and costs a conditional request each per session. The
|
|
69
91
|
* middleware is unconditional (not gated on the flag) so an already-poisoned
|
|
70
92
|
* cache heals in both directions. Alternatives that do not work: a plugin
|
|
71
93
|
* `resolveId` appending a flag query never fires in Vite 8 dev for
|
package/src/vite/plugin-types.ts
CHANGED
|
@@ -239,6 +239,34 @@ interface RangoBaseOptions {
|
|
|
239
239
|
prerender?: {
|
|
240
240
|
onError?: "fail" | "warn";
|
|
241
241
|
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The key inline server actions encrypt their bound arguments with:
|
|
245
|
+
* base64-encoded 32 bytes (`openssl rand -base64 32`). Pass it from the
|
|
246
|
+
* environment, never as a literal in the config file:
|
|
247
|
+
*
|
|
248
|
+
* ```ts
|
|
249
|
+
* rango({ encryptionKey: process.env.RANGO_ENCRYPTION_KEY })
|
|
250
|
+
* ```
|
|
251
|
+
*
|
|
252
|
+
* Why set it: the key is part of the cache version of every router whose
|
|
253
|
+
* server code encrypts with it, because a payload cached under one key
|
|
254
|
+
* carries arguments another key cannot decrypt. Without a stable key rango
|
|
255
|
+
* generates one per build, so those routers get a new version, and a cleared
|
|
256
|
+
* cache, on every deploy. With a stable key their cache survives a deploy
|
|
257
|
+
* that does not change their server code. It also lets a build decrypt
|
|
258
|
+
* arguments an earlier build encrypted (a cached or prerendered payload, an
|
|
259
|
+
* open tab).
|
|
260
|
+
*
|
|
261
|
+
* Validated when `rango()` is called: a value that is not base64 or does not
|
|
262
|
+
* decode to an AES key size (16, 24 or 32 bytes) throws. `undefined` (the
|
|
263
|
+
* variable is unset) falls back to the `RANGO_ENCRYPTION_KEY` environment
|
|
264
|
+
* variable, then to a generated key. Rotating the key clears the cache of
|
|
265
|
+
* the routers that use it.
|
|
266
|
+
*
|
|
267
|
+
* @default process.env.RANGO_ENCRYPTION_KEY, else a key generated per build
|
|
268
|
+
*/
|
|
269
|
+
encryptionKey?: string;
|
|
242
270
|
}
|
|
243
271
|
|
|
244
272
|
/**
|
|
@@ -5,11 +5,9 @@ import { resolveRscEntryFromConfig } from "../utils/shared-utils.js";
|
|
|
5
5
|
import { RSC_ENTRY_BOOTSTRAP_IMPORTS } from "./virtual-entries.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Plugin that auto-injects
|
|
9
|
-
* custom entry.rsc
|
|
10
|
-
*
|
|
11
|
-
* automatically. It also ensures the routes-manifest and loader-manifest
|
|
12
|
-
* virtual modules are always imported.
|
|
8
|
+
* Plugin that auto-injects the routes-manifest and loader-manifest imports
|
|
9
|
+
* into a custom entry.rsc file (the Cloudflare preset, where the consumer owns
|
|
10
|
+
* the worker entry).
|
|
13
11
|
*
|
|
14
12
|
* The loader-manifest import is what makes fetchable loaders resolvable on a
|
|
15
13
|
* custom worker entry. The virtual RSC entry (getVirtualEntryRSC) imports the
|
|
@@ -23,13 +21,13 @@ import { RSC_ENTRY_BOOTSTRAP_IMPORTS } from "./virtual-entries.js";
|
|
|
23
21
|
* manifest, hence the production-only failure this fixes.
|
|
24
22
|
* @internal
|
|
25
23
|
*/
|
|
26
|
-
export function
|
|
24
|
+
export function createEntryBootstrapInjectorPlugin(
|
|
27
25
|
rscEntryPath: string | undefined,
|
|
28
26
|
): Plugin {
|
|
29
27
|
let resolvedEntryPath = "";
|
|
30
28
|
|
|
31
29
|
return {
|
|
32
|
-
name: "@rangojs/router:
|
|
30
|
+
name: "@rangojs/router:entry-bootstrap-injector",
|
|
33
31
|
enforce: "pre",
|
|
34
32
|
|
|
35
33
|
configResolved(config) {
|
|
@@ -54,21 +52,8 @@ export function createVersionInjectorPlugin(
|
|
|
54
52
|
const prepend: string[] = RSC_ENTRY_BOOTSTRAP_IMPORTS.map(
|
|
55
53
|
(id) => `import "${id}";`,
|
|
56
54
|
);
|
|
57
|
-
let newCode = code;
|
|
58
|
-
const needsVersion =
|
|
59
|
-
code.includes("createRSCHandler") &&
|
|
60
|
-
!code.includes("@rangojs/router:version") &&
|
|
61
|
-
/createRSCHandler\s*\(\s*\{/.test(code);
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
prepend.push(`import { VERSION } from "@rangojs/router:version";`);
|
|
65
|
-
newCode = newCode.replace(
|
|
66
|
-
/createRSCHandler\s*\(\s*\{/,
|
|
67
|
-
"createRSCHandler({\n version: VERSION,",
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const lines = newCode.split("\n");
|
|
56
|
+
const lines = code.split("\n");
|
|
72
57
|
let insertAt = 0;
|
|
73
58
|
while (insertAt < lines.length) {
|
|
74
59
|
const trimmed = lines[insertAt]!.trim();
|
|
@@ -78,7 +63,7 @@ export function createVersionInjectorPlugin(
|
|
|
78
63
|
break;
|
|
79
64
|
}
|
|
80
65
|
}
|
|
81
|
-
newCode = [
|
|
66
|
+
const newCode = [
|
|
82
67
|
...lines.slice(0, insertAt),
|
|
83
68
|
...prepend,
|
|
84
69
|
...lines.slice(insertAt),
|
|
@@ -55,7 +55,7 @@ export function isExportOnlyFile(
|
|
|
55
55
|
// (which may be nested, e.g. createLoader<A<B>>(...)) and the call paren are
|
|
56
56
|
// resolved per match via findCallParenAfterGenerics, so a nested `>` no longer
|
|
57
57
|
// defeats the scan the way `<[^>]*>` did (it stopped at the first `>`).
|
|
58
|
-
function createCallPattern(fnNames: string[]): RegExp {
|
|
58
|
+
export function createCallPattern(fnNames: string[]): RegExp {
|
|
59
59
|
return new RegExp(`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\b`, "g");
|
|
60
60
|
}
|
|
61
61
|
|