@rebask/core 0.2.1 → 0.3.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.
Files changed (84) hide show
  1. package/dist/__type_probe__.d.ts +2 -0
  2. package/dist/__type_probe__.d.ts.map +1 -0
  3. package/dist/__type_probe__.js +4 -0
  4. package/dist/components/head.d.ts +2 -11
  5. package/dist/components/head.d.ts.map +1 -1
  6. package/dist/components/head.js +12 -24
  7. package/dist/entry.browser.js +2 -2
  8. package/dist/entry.ssr.d.ts.map +1 -1
  9. package/dist/entry.ssr.js +12 -7
  10. package/dist/handlers/rsc/background-render.js +2 -2
  11. package/dist/handlers/rsc/render-request.js +2 -2
  12. package/dist/handlers/rsc/render-to-response.js +2 -2
  13. package/dist/handlers/rsc/state.d.ts.map +1 -1
  14. package/dist/handlers/rsc/state.js +11 -5
  15. package/dist/lib/client-route-prediction.d.ts +1 -1
  16. package/dist/lib/client-route-prediction.d.ts.map +1 -1
  17. package/dist/lib/client-route-prediction.js +2 -7
  18. package/dist/lib/head/head-manager.d.ts +9 -0
  19. package/dist/lib/head/head-manager.d.ts.map +1 -0
  20. package/dist/lib/head/head-manager.js +98 -0
  21. package/dist/lib/head/head-script.js +8 -13
  22. package/dist/lib/image-optimization/image-plugin.d.ts +2 -0
  23. package/dist/lib/image-optimization/image-plugin.d.ts.map +1 -1
  24. package/dist/lib/image-optimization/image-plugin.js +10 -3
  25. package/dist/lib/plugin-names.d.ts +3 -0
  26. package/dist/lib/plugin-names.d.ts.map +1 -0
  27. package/dist/lib/plugin-names.js +2 -0
  28. package/dist/lib/proxy/build-proxy.d.ts +1 -1
  29. package/dist/lib/proxy/build-proxy.d.ts.map +1 -1
  30. package/dist/lib/proxy/build-proxy.js +4 -11
  31. package/dist/lib/proxy/pattern.d.ts +7 -0
  32. package/dist/lib/proxy/pattern.d.ts.map +1 -0
  33. package/dist/lib/proxy/pattern.js +18 -0
  34. package/dist/lib/proxy/types.d.ts +3 -1
  35. package/dist/lib/proxy/types.d.ts.map +1 -1
  36. package/dist/lib/route-prediction.d.ts.map +1 -1
  37. package/dist/lib/rsc-request.d.ts.map +1 -1
  38. package/dist/lib/rsc-request.js +6 -4
  39. package/dist/lib/server-router/build-entries.d.ts +76 -0
  40. package/dist/lib/server-router/build-entries.d.ts.map +1 -0
  41. package/dist/lib/server-router/build-entries.js +74 -0
  42. package/dist/lib/server-router/get-router.d.ts.map +1 -1
  43. package/dist/lib/server-router/get-router.js +55 -105
  44. package/dist/lib/server-router/rou3.d.ts +20 -0
  45. package/dist/lib/server-router/rou3.d.ts.map +1 -0
  46. package/dist/lib/server-router/rou3.js +55 -0
  47. package/dist/lib/server-router/route-entries.d.ts +16 -0
  48. package/dist/lib/server-router/route-entries.d.ts.map +1 -0
  49. package/dist/lib/server-router/route-entries.js +67 -0
  50. package/dist/lib/server-router/types.d.ts +24 -33
  51. package/dist/lib/server-router/types.d.ts.map +1 -1
  52. package/dist/lib/server-router/types.js +1 -6
  53. package/dist/lib/types.d.ts +2 -2
  54. package/dist/lib/types.d.ts.map +1 -1
  55. package/dist/plugins/prerender.d.ts +3 -4
  56. package/dist/plugins/prerender.d.ts.map +1 -1
  57. package/dist/plugins/prerender.js +31 -0
  58. package/dist/plugins/proxy.d.ts.map +1 -1
  59. package/dist/plugins/proxy.js +7 -1
  60. package/dist/plugins/router/rou3-compiled.d.ts +9 -0
  61. package/dist/plugins/router/rou3-compiled.d.ts.map +1 -0
  62. package/dist/plugins/router/rou3-compiled.js +14 -0
  63. package/dist/plugins/router/rou3-router.d.ts +3 -0
  64. package/dist/plugins/router/rou3-router.d.ts.map +1 -0
  65. package/dist/plugins/router/rou3-router.js +16 -0
  66. package/dist/plugins/router/router-plugin.d.ts +6 -16
  67. package/dist/plugins/router/router-plugin.d.ts.map +1 -1
  68. package/dist/plugins/router/router-plugin.js +43 -22
  69. package/dist/proxy.d.ts +1 -0
  70. package/dist/proxy.d.ts.map +1 -1
  71. package/dist/proxy.js +1 -0
  72. package/dist/request-context.d.ts +0 -2
  73. package/dist/request-context.d.ts.map +1 -1
  74. package/dist/request-context.js +0 -4
  75. package/dist/router.d.ts +1 -1
  76. package/dist/router.d.ts.map +1 -1
  77. package/dist/router.js +4 -4
  78. package/dist/server-router.d.ts +3 -3
  79. package/dist/server-router.d.ts.map +1 -1
  80. package/dist/server-router.js +2 -2
  81. package/dist/vite.d.ts +8 -3
  82. package/dist/vite.d.ts.map +1 -1
  83. package/dist/vite.js +60 -29
  84. package/package.json +5 -4
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=__type_probe__.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"__type_probe__.d.ts","sourceRoot":"","sources":["../src/__type_probe__.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import { createMatcher } from "virtual:rebask/server-router";
2
+ const matcher = createMatcher([{ methods: ["GET"], pattern: "/" }]);
3
+ const probe = matcher;
4
+ void probe;
@@ -2,9 +2,7 @@ import { type ReactNode } from "react";
2
2
  /**
3
3
  * Head component for managing document head elements with automatic deduplication.
4
4
  *
5
- * Renders tags directly — React 19 hoists them to `<head>`. `HeadScript` then
6
- * deduplicates by keeping the highest `data-order` within each dedupe key
7
- * (title, meta[name], meta[property], meta[http-equiv], canonical link, base).
5
+ * Tags rendered by nested `<Head>` components override their parents.
8
6
  *
9
7
  * @example
10
8
  * ```tsx
@@ -16,12 +14,5 @@ import { type ReactNode } from "react";
16
14
  */
17
15
  export declare function Head({ children }: {
18
16
  children: ReactNode;
19
- }): import("react").JSX.Element;
20
- /**
21
- * Inline script that deduplicates head elements.
22
- * Place this in your layout's <head>.
23
- *
24
- * Keeps only the highest `data-order` element within each dedupe key.
25
- */
26
- export declare function HeadScript(): import("react").JSX.Element;
17
+ }): import("react").JSX.Element | null;
27
18
  //# sourceMappingURL=head.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../src/components/head.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AA6B/E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAoBzD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,gCAEzB"}
1
+ {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../src/components/head.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIN,KAAK,SAAS,EAGd,MAAM,OAAO,CAAA;AAoBd;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,sCAsBzD"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
- import { Children, createElement, isValidElement } from "react";
4
- import headDedupeScript from "virtual:rebask/head-dedupe";
3
+ import { Children, createElement, isValidElement, useId, useLayoutEffect, } from "react";
4
+ import { registerHead, unregisterHead } from "../lib/head/head-manager.js";
5
5
  function parseChildren(children) {
6
6
  const entries = [];
7
7
  for (const child of Children.toArray(children)) {
@@ -11,18 +11,14 @@ function parseChildren(children) {
11
11
  if (!tag)
12
12
  continue;
13
13
  const { children, ...props } = child.props;
14
- const entry = { tag, props, children };
15
- entries.push(entry);
14
+ entries.push({ tag, props, children });
16
15
  }
17
16
  return entries;
18
17
  }
19
- let headOrder = 0;
20
18
  /**
21
19
  * Head component for managing document head elements with automatic deduplication.
22
20
  *
23
- * Renders tags directly — React 19 hoists them to `<head>`. `HeadScript` then
24
- * deduplicates by keeping the highest `data-order` within each dedupe key
25
- * (title, meta[name], meta[property], meta[http-equiv], canonical link, base).
21
+ * Tags rendered by nested `<Head>` components override their parents.
26
22
  *
27
23
  * @example
28
24
  * ```tsx
@@ -34,20 +30,12 @@ let headOrder = 0;
34
30
  */
35
31
  export function Head({ children }) {
36
32
  const entries = parseChildren(children);
37
- // Render tags directly - React 19 hoists them to <head>
38
- // The HeadScript component handles deduplication
39
- return (_jsx(_Fragment, { children: entries.map((entry, i) => createElement(entry.tag, {
40
- key: i,
41
- "data-order": String((headOrder += 1)),
42
- ...entry.props,
43
- }, entry.children)) }));
44
- }
45
- /**
46
- * Inline script that deduplicates head elements.
47
- * Place this in your layout's <head>.
48
- *
49
- * Keeps only the highest `data-order` element within each dedupe key.
50
- */
51
- export function HeadScript() {
52
- return _jsx("script", { dangerouslySetInnerHTML: { __html: headDedupeScript } });
33
+ const id = useId();
34
+ useLayoutEffect(() => {
35
+ registerHead(id, entries);
36
+ });
37
+ useLayoutEffect(() => () => unregisterHead(id), [id]);
38
+ if (typeof window !== "undefined")
39
+ return null;
40
+ return (_jsx(_Fragment, { children: entries.map((entry, i) => createElement(entry.tag, { key: i, ...entry.props, "data-rebask-head": "" }, entry.children)) }));
53
41
  }
@@ -12,7 +12,7 @@ import { HandledDeploymentMismatch, isRebaskServerError, ServerFunctionError, }
12
12
  import { REBASK_ACTION_HEADER } from "./lib/ppr/headers.js";
13
13
  import { RouterCache } from "./lib/router-cache.js";
14
14
  import { initializeScrollHandling } from "./lib/scroll.js";
15
- import { proxyPatternsAtom } from "./router.js";
15
+ import { proxyRegexpsAtom } from "./router.js";
16
16
  async function main() {
17
17
  const [payload, route] = await Promise.all([
18
18
  createFromReadableStream(rscStream),
@@ -32,7 +32,7 @@ async function main() {
32
32
  // the server (through `useRouter`) and break the build.
33
33
  createFromFetch,
34
34
  });
35
- proxyPatternsAtom.set(payload.proxyPatterns);
35
+ proxyRegexpsAtom.set(payload.proxyRegexps);
36
36
  if (payload.routePrediction) {
37
37
  learnRoutePrediction(routeTreeResponse);
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entry.ssr.d.ts","sourceRoot":"","sources":["../src/entry.ssr.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,kBAAkB,CAAA;AAMxE,OAAO,EAAE,KAAK,aAAa,EAAyC,MAAM,yBAAyB,CAAA;AAInG,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAgFtD,wBAAsB,cAAc,CACnC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,wBAwBX;AAED,2DAA2D;AAC3D,wBAAsB,UAAU,CAC/B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,gCAW7D;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IACR,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,KAAK,EAAE,aAAa,CAAA;IACpB,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;;;;;;GAsCD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC/B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GAC/B,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAUrC"}
1
+ {"version":3,"file":"entry.ssr.d.ts","sourceRoot":"","sources":["../src/entry.ssr.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAoB,MAAM,kBAAkB,CAAA;AAOxE,OAAO,EAAE,KAAK,aAAa,EAAyC,MAAM,yBAAyB,CAAA;AAInG,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AA8FtD,wBAAsB,cAAc,CACnC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,wBAwBX;AAED,2DAA2D;AAC3D,wBAAsB,UAAU,CAC/B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,gCAU7D;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAClC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IACR,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,KAAK,EAAE,aAAa,CAAA;IACpB,sFAAsF;IACtF,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;;;;;;GAmCD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC/B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GAC/B,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAUrC"}
package/dist/entry.ssr.js CHANGED
@@ -3,6 +3,7 @@ import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr";
3
3
  import { renderToReadableStream, resume } from "react-dom/server.edge";
4
4
  import { prerender } from "react-dom/static.edge";
5
5
  import { injectRSCPayload } from "rsc-html-stream/server";
6
+ import headDedupeScript from "virtual:rebask/head-dedupe";
6
7
  import { AppRoot } from "./components/app-root.js";
7
8
  import { Delay } from "./components/delay.js";
8
9
  import { waitForRunnerIdle } from "./lib/dev-server.js";
@@ -26,8 +27,15 @@ function handleSSRError(error, logError = true) {
26
27
  console.error(error);
27
28
  }
28
29
  let bootstrapScriptContentPromise = null;
29
- function getBootstrapScriptContent() {
30
- return (bootstrapScriptContentPromise ??= import.meta.viteRsc.loadBootstrapScriptContent("index"));
30
+ function versionScript() {
31
+ return `self.__REBASK__={version:${JSON.stringify(__REBASK_VERSION__)}}`;
32
+ }
33
+ async function getBootstrapScriptContent(route) {
34
+ const scripts = [versionScript(), headDedupeScript];
35
+ if (route)
36
+ scripts.push(documentRouteScript(route));
37
+ scripts.push(await (bootstrapScriptContentPromise ??= import.meta.viteRsc.loadBootstrapScriptContent("index")));
38
+ return scripts.join(";");
31
39
  }
32
40
  function SsrRoot({ cache, onShell }) {
33
41
  return (_jsx(AppRoot, { cache: cache, trailing: _jsx(Delay, { promise: new Promise((resolve) => {
@@ -90,7 +98,7 @@ export async function getRouterCache(rscStream, routeTree, url) {
90
98
  export async function renderHTML(rscStream, cache, options) {
91
99
  const htmlStream = await renderToReadableStream(_jsx(SsrRoot, { cache: cache }), {
92
100
  // The document route must be available before hydration starts.
93
- bootstrapScriptContent: documentRouteScript(options.route) + ";" + (await getBootstrapScriptContent()),
101
+ bootstrapScriptContent: await getBootstrapScriptContent(options.route),
94
102
  formState: options.formState,
95
103
  onError: (error) => handleSSRError(error),
96
104
  });
@@ -107,12 +115,9 @@ export async function prerenderHTML(rscStream, cache, options) {
107
115
  const { signal, onShell, renderToCompletion, route, isShell } = options;
108
116
  // Start prerender - this blocks until abort or completion.
109
117
  const result = await MicrotaskStorage.run({ pending: 0, subs: new Set() }, async () => {
110
- const bootstrapScriptContent = await getBootstrapScriptContent();
111
118
  const prerenderOptions = {
112
119
  signal,
113
- bootstrapScriptContent: isShell
114
- ? bootstrapScriptContent
115
- : documentRouteScript(route) + ";" + bootstrapScriptContent,
120
+ bootstrapScriptContent: await getBootstrapScriptContent(isShell ? undefined : route),
116
121
  onError: (error) => handleSSRError(error, false),
117
122
  };
118
123
  // `Number.MAX_SAFE_INTEGER` keeps Fizz from flushing partial chunks so resolved Suspense
@@ -1,4 +1,4 @@
1
- import { proxyPatterns } from "virtual:rebask/proxy-router";
1
+ import { proxyRegexps } from "virtual:rebask/proxy-router";
2
2
  import { scheduleBackgroundRevalidation } from "../../lib/background-revalidation.js";
3
3
  import { createResumeState, serializeResumeState } from "../../lib/ppr/postponed-state.js";
4
4
  import { maybeAbort, RenderStorage } from "../../lib/render-context.js";
@@ -22,7 +22,7 @@ async function createRscStream(state) {
22
22
  const bgRscStream = renderRsc({
23
23
  seedData: state.seedData,
24
24
  ...(state.routePrediction && { routePrediction: state.routePrediction }),
25
- ...(proxyPatterns && { proxyPatterns }),
25
+ ...(proxyRegexps && { proxyRegexps }),
26
26
  }, { temporaryReferences: state.postBody.temporaryReferences });
27
27
  const [bgRscStream1, bgRscStream2] = bgRscStream.tee();
28
28
  const routerCache = await state.ssrEntryModule.getRouterCache(bgRscStream1, state.routeTree, state.url.href);
@@ -1,5 +1,5 @@
1
1
  import { hooks, hooksOptions } from "virtual:rebask/hooks";
2
- import { proxyPatterns } from "virtual:rebask/proxy-router";
2
+ import { proxyRegexps } from "virtual:rebask/proxy-router";
3
3
  import { ResumeMode } from "../../lib/ppr/types.js";
4
4
  import { prerenderPaths } from "../../lib/prerender-paths.js";
5
5
  import { renderPageSegment, renderRouteSegments } from "../../lib/route-renderer.js";
@@ -102,7 +102,7 @@ export async function renderRequest(state, cacheContext) {
102
102
  : {
103
103
  seedData,
104
104
  ...(state.routePrediction && { routePrediction: state.routePrediction }),
105
- ...(proxyPatterns && { proxyPatterns }),
105
+ ...(proxyRegexps && { proxyRegexps }),
106
106
  ...(formState !== undefined && { formState }),
107
107
  // The built-in error route is only ever rendered after a failed shell.
108
108
  ...(state.isErrorRoute && { shellError: true }),
@@ -1,5 +1,5 @@
1
1
  import { pprConfig, rscPathSuffix } from "virtual:rebask/ppr-config";
2
- import { proxyPatterns } from "virtual:rebask/proxy-router";
2
+ import { proxyRegexps } from "virtual:rebask/proxy-router";
3
3
  import { scheduleBackgroundRevalidation } from "../../lib/background-revalidation.js";
4
4
  import {} from "../../lib/cache-context.js";
5
5
  import { CacheKeyTag } from "../../lib/cache-key-tags.js";
@@ -250,7 +250,7 @@ async function renderResumeStream(state, postponed) {
250
250
  const rscStream = renderRsc({
251
251
  seedData,
252
252
  ...(state.routePrediction && { routePrediction: state.routePrediction }),
253
- ...(proxyPatterns && { proxyPatterns }),
253
+ ...(proxyRegexps && { proxyRegexps }),
254
254
  ...(state.postBody.formState && { formState: state.postBody.formState }),
255
255
  }, { temporaryReferences: state.postBody.temporaryReferences }, () => markRenderError());
256
256
  const [serverStream, browserStream] = rscStream.tee();
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/handlers/rsc/state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/handlers/rsc/state.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { pprConfig } from "virtual:rebask/ppr-config";
2
2
  import { pageModules } from "../../lib/app-manifest.js";
3
3
  import { REBASK_TREE_HEADER } from "../../lib/ppr/headers.js";
4
+ import { getPrerenderParams } from "../../lib/prerender-params.js";
4
5
  import { prerenderPaths } from "../../lib/prerender-paths.js";
5
6
  import { getDynamicSegmentNames } from "../../lib/route-matcher.js";
6
7
  import { buildRouteTree } from "../../lib/route-tree.js";
@@ -31,9 +32,17 @@ export async function buildRenderRequestState(request, route, params, handleOpti
31
32
  // (catch-all) prediction would only teach clients to prefetch 404s and shadow real sibling
32
33
  // routes. Suppress it.
33
34
  const canPredict = isPageRoute && !isNotFound;
35
+ const dynamicSegmentNames = getDynamicSegmentNames(route.segments);
36
+ const isDynamicRoute = dynamicSegmentNames.length > 0;
37
+ const fullParamsSet = new Set(dynamicSegmentNames);
34
38
  // A route with `allowExtraParams: false` has only fixed paths, so params resolve and
35
- // `routeParams()` is not dynamic IO.
36
- const isStaticOnly = isPageRoute && (await prerenderPaths.isStaticOnly(route));
39
+ // `routeParams()` is not dynamic IO. During build prerendering this reads `prerenderParams()`
40
+ // because the manifest is written after rendering; at runtime it reads the manifest.
41
+ const isStaticOnly = isPageRoute &&
42
+ isDynamicRoute &&
43
+ (handleOptions?.isBuildPrerender
44
+ ? (await getPrerenderParams(route))?.allowExtraParams === false
45
+ : await prerenderPaths.isStaticOnly(route));
37
46
  const routePrediction = canPredict ? await getRoutePrediction(route, isStaticOnly) : undefined;
38
47
  const isBotRequest = __REBASK_FULL_HTML_FOR_BOTS &&
39
48
  isHtmlRequest &&
@@ -42,9 +51,6 @@ export async function buildRenderRequestState(request, route, params, handleOpti
42
51
  const isBuildPrerender = handleOptions?.isBuildPrerender ?? false;
43
52
  const shouldPrerender = !isBotRequest && isHtmlRequest;
44
53
  const isStaticGen = import.meta.env.PROD && !isPost;
45
- const dynamicSegmentNames = getDynamicSegmentNames(route.segments);
46
- const isDynamicRoute = dynamicSegmentNames.length > 0;
47
- const fullParamsSet = new Set(dynamicSegmentNames);
48
54
  const fillHeader = pprConfig && request.headers.get(pprConfig.fillHeader);
49
55
  const isHtmlFillRequest = !isResumeRequest && fillHeader === "html";
50
56
  const isRscFillRequest = fillHeader === "rsc" && isPageRoute && !isPost;
@@ -35,6 +35,6 @@ export declare function getRoutePathInfo(pathname: string): {
35
35
  staticOnly: boolean;
36
36
  hasDynamicIO: HasDynamicIO | undefined;
37
37
  };
38
- export declare function predictRouteTree(url: string, proxyPatterns?: string[]): RouteTreeResponse | undefined;
38
+ export declare function predictRouteTree(url: string, proxyRegexps?: string[]): RouteTreeResponse | undefined;
39
39
  export {};
40
40
  //# sourceMappingURL=client-route-prediction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-route-prediction.d.ts","sourceRoot":"","sources":["../../src/lib/client-route-prediction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtF,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,mBAAmB,CAAA;AAEpE,UAAU,sBAAsB;IAC/B,IAAI,EAAE,SAAS,CAAA;IACf,UAAU,EAAE,eAAe,CAAA;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACxC;;;;OAIG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QAAC,EAAE,EAAE,YAAY,CAAA;KAAE,CAAC,CAAA;IACtE,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;CACf;AAED,eAAO,MAAM,kBAAkB,qCAA4C,CAAA;AAE3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAMpE;AA4FD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAkCtE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACnD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,YAAY,GAAG,SAAS,CAAA;CACtC,CA4BA;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,EACX,aAAa,CAAC,EAAE,MAAM,EAAE,GACtB,iBAAiB,GAAG,SAAS,CA0B/B"}
1
+ {"version":3,"file":"client-route-prediction.d.ts","sourceRoot":"","sources":["../../src/lib/client-route-prediction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtF,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,mBAAmB,CAAA;AAEpE,UAAU,sBAAsB;IAC/B,IAAI,EAAE,SAAS,CAAA;IACf,UAAU,EAAE,eAAe,CAAA;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACxC;;;;OAIG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QAAC,EAAE,EAAE,YAAY,CAAA;KAAE,CAAC,CAAA;IACtE,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;CACf;AAED,eAAO,MAAM,kBAAkB,qCAA4C,CAAA;AAE3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAMpE;AAqFD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAkCtE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACnD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,YAAY,GAAG,SAAS,CAAA;CACtC,CA4BA;AAED,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,MAAM,EAAE,GACrB,iBAAiB,GAAG,SAAS,CAyB/B"}
@@ -82,11 +82,6 @@ function applyRouteTreeParams(tree, params) {
82
82
  ? [applySegmentParams(segment, params), nextSlots, flags]
83
83
  : [applySegmentParams(segment, params), nextSlots];
84
84
  }
85
- function proxyPatternToRegex(pattern) {
86
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
87
- const source = escaped.replace(/\*/g, ".*").replace(/\/:([^/]+)/g, "/[^/]+");
88
- return new RegExp(`^${source}$`);
89
- }
90
85
  export function learnRoutePrediction(response) {
91
86
  const { tree, routePrediction: prediction } = response;
92
87
  if (!prediction)
@@ -144,9 +139,9 @@ export function getRoutePathInfo(pathname) {
144
139
  }
145
140
  return { staticOnly, hasDynamicIO };
146
141
  }
147
- export function predictRouteTree(url, proxyPatterns) {
142
+ export function predictRouteTree(url, proxyRegexps) {
148
143
  const pathname = new URL(url, "http://localhost").pathname;
149
- const proxyMatched = proxyPatterns?.some((pattern) => proxyPatternToRegex(pattern).test(pathname)) ?? false;
144
+ const proxyMatched = proxyRegexps?.some((source) => new RegExp(source).test(pathname)) ?? false;
150
145
  const predictions = [...learnedPredictions.values()].sort((a, b) => {
151
146
  return compareRouteSegments(getTemplateSegments(a.segments), getTemplateSegments(b.segments));
152
147
  });
@@ -0,0 +1,9 @@
1
+ import { type ReactNode } from "react";
2
+ export interface HeadEntry {
3
+ tag: string;
4
+ props: Record<string, unknown>;
5
+ children?: ReactNode;
6
+ }
7
+ export declare function registerHead(id: string, entries: HeadEntry[]): void;
8
+ export declare function unregisterHead(id: string): void;
9
+ //# sourceMappingURL=head-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/head/head-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIxE,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAA;CACpB;AAsGD,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAG5D;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,QAExC"}
@@ -0,0 +1,98 @@
1
+ import { createElement } from "react";
2
+ import { createPortal, flushSync } from "react-dom";
3
+ import { createRoot } from "react-dom/client";
4
+ const heads = new Map();
5
+ let root = null;
6
+ let titleElement = null;
7
+ let scheduled = false;
8
+ function getText(children) {
9
+ if (typeof children === "string" ||
10
+ typeof children === "number" ||
11
+ typeof children === "bigint") {
12
+ return String(children);
13
+ }
14
+ if (Array.isArray(children))
15
+ return children.map(getText).join("");
16
+ return "";
17
+ }
18
+ function updateTitle(entry) {
19
+ if (!entry) {
20
+ titleElement?.remove();
21
+ titleElement = null;
22
+ return;
23
+ }
24
+ if (!titleElement)
25
+ titleElement = document.createElement("title");
26
+ const firstTitle = document.head.querySelector("title");
27
+ if (firstTitle !== titleElement)
28
+ document.head.insertBefore(titleElement, firstTitle);
29
+ titleElement.textContent = getText(entry.children);
30
+ }
31
+ function updateHead() {
32
+ scheduled = false;
33
+ if (!root) {
34
+ for (const element of document.querySelectorAll("[data-rebask-head]")) {
35
+ element.remove();
36
+ }
37
+ new MutationObserver((mutations) => {
38
+ for (const mutation of mutations) {
39
+ for (const node of mutation.addedNodes) {
40
+ if (node.nodeType !== 1)
41
+ continue;
42
+ const element = node;
43
+ if (element.matches("[data-rebask-head]"))
44
+ element.remove();
45
+ else
46
+ for (const child of element.querySelectorAll("[data-rebask-head]"))
47
+ child.remove();
48
+ }
49
+ }
50
+ }).observe(document.documentElement, { childList: true, subtree: true });
51
+ root = createRoot(document.createElement("div"));
52
+ }
53
+ const keyed = new Map();
54
+ const elements = [];
55
+ let title;
56
+ for (const [id, entries] of heads) {
57
+ for (let i = 0; i < entries.length; i++) {
58
+ const entry = entries[i];
59
+ let key = entry.tag.toLowerCase();
60
+ if (key === "meta") {
61
+ const attr = entry.props.name || entry.props.property || entry.props.httpEquiv;
62
+ key = attr ? `${key}:${String(attr)}` : null;
63
+ }
64
+ else if (key === "link") {
65
+ key = entry.props.rel === "canonical" ? "link:canonical" : null;
66
+ }
67
+ if (key === null) {
68
+ elements.push(createElement(entry.tag, { key: `${id}:${i}`, ...entry.props }, entry.children));
69
+ }
70
+ else if (key === "title") {
71
+ title = entry;
72
+ }
73
+ else {
74
+ keyed.set(key, entry);
75
+ }
76
+ }
77
+ }
78
+ for (const [key, entry] of keyed) {
79
+ elements.push(createElement(entry.tag, { key, ...entry.props }, entry.children));
80
+ }
81
+ const headRoot = root;
82
+ flushSync(() => headRoot.render(createPortal(elements, document.head)));
83
+ updateTitle(title);
84
+ }
85
+ function scheduleUpdate() {
86
+ if (scheduled)
87
+ return;
88
+ scheduled = true;
89
+ queueMicrotask(updateHead);
90
+ }
91
+ export function registerHead(id, entries) {
92
+ heads.set(id, entries);
93
+ scheduleUpdate();
94
+ }
95
+ export function unregisterHead(id) {
96
+ if (heads.delete(id))
97
+ scheduleUpdate();
98
+ }
@@ -1,7 +1,8 @@
1
- // This script is inlined in the browser when the `HeadScript` component is used.
1
+ // This script is inlined in the document bootstrap.
2
2
  function dedupeHeadElements() {
3
- const seen = new Map();
4
- for (const element of document.querySelectorAll("[data-order]")) {
3
+ const seen = new Set();
4
+ // Keep the last element per key.
5
+ for (const element of Array.from(document.querySelectorAll("[data-rebask-head]")).reverse()) {
5
6
  let key = element.tagName.toLowerCase();
6
7
  if (key === "meta") {
7
8
  const attr = element.getAttribute("name") ||
@@ -16,23 +17,17 @@ function dedupeHeadElements() {
16
17
  continue;
17
18
  key = "link:canonical";
18
19
  }
19
- const order = Number(element.getAttribute("data-order")) || 0;
20
- const previous = seen.get(key);
21
- if (!previous || order > previous.order) {
22
- if (previous)
23
- previous.element.remove();
24
- seen.set(key, { element, order });
25
- }
26
- else {
20
+ if (seen.has(key))
27
21
  element.remove();
28
- }
22
+ else
23
+ seen.add(key);
29
24
  }
30
25
  }
31
26
  dedupeHeadElements();
32
27
  const observer = new MutationObserver((mutations) => {
33
28
  for (const mutation of mutations) {
34
29
  for (const node of mutation.addedNodes) {
35
- if (node.nodeType === 1 && node.matches?.("[data-order]")) {
30
+ if (node.nodeType === 1 && node.matches?.("[data-rebask-head]")) {
36
31
  dedupeHeadElements();
37
32
  return;
38
33
  }
@@ -5,6 +5,8 @@ export declare const REBASK_IMAGE_PLUGIN_NAME = "rebask:image";
5
5
  export interface RebaskImagePluginApi {
6
6
  /** Get the resolved image configuration */
7
7
  getImageConfig: () => ImageConfigComplete;
8
+ /** Whether the build has an image handler. */
9
+ hasHandler: () => Promise<boolean>;
8
10
  /**
9
11
  * Disable the image handler for this build. Useful if the platform adapter offers its own image
10
12
  * optimization solution.
@@ -1 +1 @@
1
- {"version":3,"file":"image-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/image-optimization/image-plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAsB,MAAM,mBAAmB,CAAA;AAIlG,qCAAqC;AACrC,eAAO,MAAM,wBAAwB,iBAAiB,CAAA;AA2BtD,MAAM,WAAW,oBAAoB;IACpC,2CAA2C;IAC3C,cAAc,EAAE,MAAM,mBAAmB,CAAA;IACzC;;;OAGG;IACH,cAAc,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAqEzD"}
1
+ {"version":3,"file":"image-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/image-optimization/image-plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAsB,MAAM,mBAAmB,CAAA;AAIlG,qCAAqC;AACrC,eAAO,MAAM,wBAAwB,iBAAiB,CAAA;AA0BtD,MAAM,WAAW,oBAAoB;IACpC,2CAA2C;IAC3C,cAAc,EAAE,MAAM,mBAAmB,CAAA;IACzC,8CAA8C;IAC9C,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAClC;;;OAGG;IACH,cAAc,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CA+EzD"}
@@ -13,7 +13,7 @@ async function findImageHandler(root, customPath) {
13
13
  }
14
14
  catch {
15
15
  console.warn(`[rebask] Image handler not found at path: ${customPath}`);
16
- return null;
16
+ return;
17
17
  }
18
18
  }
19
19
  // Look for default rebask.image.{ts,js} in project root
@@ -27,7 +27,6 @@ async function findImageHandler(root, customPath) {
27
27
  // File doesn't exist, try next extension
28
28
  }
29
29
  }
30
- return null;
31
30
  }
32
31
  export function rebaskImage(options) {
33
32
  const imageConfig = {
@@ -37,8 +36,16 @@ export function rebaskImage(options) {
37
36
  let publicDir;
38
37
  let projectRoot;
39
38
  let disabled = false;
39
+ let resolvedHandlerPath;
40
+ async function resolveHandlerPath() {
41
+ if (resolvedHandlerPath === undefined) {
42
+ resolvedHandlerPath = await findImageHandler(projectRoot, imageConfig.handler);
43
+ }
44
+ return resolvedHandlerPath;
45
+ }
40
46
  const api = {
41
47
  getImageConfig: () => imageConfig,
48
+ hasHandler: async () => !disabled && (await resolveHandlerPath()) !== null,
42
49
  disableHandler: () => {
43
50
  disabled = true;
44
51
  },
@@ -81,7 +88,7 @@ export function rebaskImage(options) {
81
88
  }
82
89
  if (id === "\0virtual:rebask/image-handler") {
83
90
  // The handler can be disabled by other plugins (e.g., platform adapter)
84
- const handlerPath = !disabled && (await findImageHandler(projectRoot, imageConfig.handler));
91
+ const handlerPath = disabled ? null : await resolveHandlerPath();
85
92
  if (!handlerPath) {
86
93
  return `export const loadImageHandler = undefined;`;
87
94
  }
@@ -0,0 +1,3 @@
1
+ /** The `name` of the Rebask app config plugin. */
2
+ export declare const REBASK_PLUGIN_NAME = "rebask:app-config";
3
+ //# sourceMappingURL=plugin-names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-names.d.ts","sourceRoot":"","sources":["../../src/lib/plugin-names.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,eAAO,MAAM,kBAAkB,sBAAsB,CAAA"}
@@ -0,0 +1,2 @@
1
+ /** The `name` of the Rebask app config plugin. */
2
+ export const REBASK_PLUGIN_NAME = "rebask:app-config";
@@ -1,4 +1,4 @@
1
1
  import type { ProxyRouter, ProxyRoutes } from "./types.js";
2
- /** Build a compiled proxy router. */
2
+ /** Build a proxy router. The proxy is small, so it keeps the rou3 interpreter. */
3
3
  export declare function buildProxy(routes: ProxyRoutes): ProxyRouter | null;
4
4
  //# sourceMappingURL=build-proxy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-proxy.d.ts","sourceRoot":"","sources":["../../../src/lib/proxy/build-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE1D,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAoBlE"}
1
+ {"version":3,"file":"build-proxy.d.ts","sourceRoot":"","sources":["../../../src/lib/proxy/build-proxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE1D,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAgBlE"}
@@ -1,24 +1,17 @@
1
- import { createMatcher } from "virtual:rebask/server-router";
1
+ import { createMatcher } from "../../plugins/router/rou3-router.js";
2
2
  import { HTTP_METHODS } from "../route-matcher.js";
3
- import { RouteType } from "../server-router/types.js";
4
- /** Build a compiled proxy router. */
3
+ /** Build a proxy router. The proxy is small, so it keeps the rou3 interpreter. */
5
4
  export function buildProxy(routes) {
6
5
  const entries = Object.entries(routes);
7
6
  if (entries.length === 0)
8
7
  return null;
9
- const matchEntries = entries.map(([pattern, handler]) => ({
10
- type: RouteType.PROXY,
11
- methods: [...HTTP_METHODS],
12
- pattern,
13
- handler,
14
- }));
15
- const matcher = createMatcher(matchEntries);
8
+ const matcher = createMatcher(entries.map(([pattern, handler]) => ({ methods: [...HTTP_METHODS], pattern, handler })));
16
9
  return {
17
10
  find(request) {
18
11
  const match = matcher.find(request.method, request.url);
19
12
  if (!match)
20
13
  return null;
21
- return match;
14
+ return (req) => match.entry.handler(req, match.params ?? {});
22
15
  },
23
16
  };
24
17
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Consumers that only match paths never read captures. Named groups are unnecessary, and duplicate
3
+ * names across alternatives can fail engines that don't support them.
4
+ */
5
+ export declare function proxyPatternToRegExpSource(pattern: string): string;
6
+ export declare function proxyPatternToClientSource(pattern: string): string;
7
+ //# sourceMappingURL=pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../../src/lib/proxy/pattern.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAGD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASlE"}
@@ -0,0 +1,18 @@
1
+ import { routeToRegExp } from "rou3";
2
+ /**
3
+ * Consumers that only match paths never read captures. Named groups are unnecessary, and duplicate
4
+ * names across alternatives can fail engines that don't support them.
5
+ */
6
+ export function proxyPatternToRegExpSource(pattern) {
7
+ return routeToRegExp(pattern).source.replace(/\(\?<[^>]+>/g, "(?:");
8
+ }
9
+ // Helps with failures in Node 20/22 if some pattern can't be converted to a regexp.
10
+ export function proxyPatternToClientSource(pattern) {
11
+ try {
12
+ return proxyPatternToRegExpSource(pattern);
13
+ }
14
+ catch (error) {
15
+ console.error(`[rebask] Could not generate a proxy match source for "${pattern}". Client route prediction is disabled for it. ${error instanceof Error ? error.message : String(error)}`);
16
+ return "^/.*$";
17
+ }
18
+ }