vinext 1.0.0-beta.11 → 1.0.0-beta.13

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 (170) hide show
  1. package/README.md +39 -12
  2. package/dist/build/action-owner-manifest.js +23 -5
  3. package/dist/build/lifecycle.d.ts +42 -0
  4. package/dist/build/lifecycle.js +246 -0
  5. package/dist/build/nitro-route-rules.js +1 -1
  6. package/dist/build/pages-client-assets-module.d.ts +0 -3
  7. package/dist/build/pages-client-assets-module.js +1 -13
  8. package/dist/build/precompress.js +1 -1
  9. package/dist/build/prerender-paths.d.ts +1 -1
  10. package/dist/build/prerender-paths.js +6 -6
  11. package/dist/build/prerender-server-pool.js +1 -1
  12. package/dist/build/prerender.d.ts +1 -1
  13. package/dist/build/prerender.js +5 -5
  14. package/dist/build/preview-credentials.d.ts +1 -1
  15. package/dist/build/preview-credentials.js +2 -2
  16. package/dist/build/report.js +1 -1
  17. package/dist/build/run-prerender.d.ts +2 -2
  18. package/dist/build/run-prerender.js +5 -5
  19. package/dist/build/standalone.js +2 -2
  20. package/dist/cli-args.d.ts +5 -13
  21. package/dist/cli-args.js +2 -45
  22. package/dist/cli-dev-config.d.ts +6 -2
  23. package/dist/cli-dev-config.js +160 -3
  24. package/dist/cli.js +104 -439
  25. package/dist/config/config-matchers.js +1 -1
  26. package/dist/config/next-config.d.ts +2 -2
  27. package/dist/config/next-config.js +5 -5
  28. package/dist/config/prerender.d.ts +3 -0
  29. package/dist/config/prerender.js +8 -2
  30. package/dist/entries/app-browser-entry.js +1 -1
  31. package/dist/entries/app-rsc-entry.d.ts +2 -0
  32. package/dist/entries/app-rsc-entry.js +25 -5
  33. package/dist/entries/pages-client-entry.d.ts +1 -0
  34. package/dist/entries/pages-client-entry.js +17 -2
  35. package/dist/index.d.ts +6 -8
  36. package/dist/index.js +282 -105
  37. package/dist/init-cloudflare.d.ts +3 -2
  38. package/dist/init-cloudflare.js +117 -5
  39. package/dist/init-platform.d.ts +2 -0
  40. package/dist/init-platform.js +9 -3
  41. package/dist/init.d.ts +7 -5
  42. package/dist/init.js +41 -22
  43. package/dist/plugins/dynamic-preload-metadata.js +1 -1
  44. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  45. package/dist/plugins/fonts.js +1 -1
  46. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  47. package/dist/plugins/import-meta-url.js +1 -1
  48. package/dist/plugins/instrumentation-client.js +1 -1
  49. package/dist/plugins/og-assets.js +32 -13
  50. package/dist/plugins/og-harfbuzz.d.ts +24 -0
  51. package/dist/plugins/og-harfbuzz.js +260 -0
  52. package/dist/plugins/optimize-imports.js +1 -1
  53. package/dist/plugins/require-condition-resolution.js +2 -2
  54. package/dist/plugins/require-context.js +2 -2
  55. package/dist/plugins/typeof-window.js +1 -1
  56. package/dist/plugins/use-cache-callable.d.ts +0 -2
  57. package/dist/plugins/use-cache-callable.js +40 -22
  58. package/dist/plugins/worker-image-imports.js +1 -1
  59. package/dist/routing/app-route-graph.js +1 -1
  60. package/dist/routing/app-router.js +1 -1
  61. package/dist/routing/pages-router.js +1 -1
  62. package/dist/server/app-action-forwarding.js +1 -1
  63. package/dist/server/app-browser-entry.js +1 -0
  64. package/dist/server/app-browser-error.js +1 -1
  65. package/dist/server/app-elements-wire.js +2 -2
  66. package/dist/server/app-middleware.js +1 -1
  67. package/dist/server/app-optimistic-routing.js +1 -1
  68. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  69. package/dist/server/app-page-cache-finalizer.js +14 -2
  70. package/dist/server/app-page-dispatch.js +1 -1
  71. package/dist/server/app-page-element-builder.js +3 -2
  72. package/dist/server/app-page-probe.js +3 -3
  73. package/dist/server/app-page-render.js +1 -0
  74. package/dist/server/app-page-request.d.ts +2 -0
  75. package/dist/server/app-page-request.js +16 -12
  76. package/dist/server/app-request-stage-dispatch.js +1 -1
  77. package/dist/server/app-request-stage-independent-entry.js +2 -2
  78. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  79. package/dist/server/app-route-handler-dispatch.js +3 -2
  80. package/dist/server/app-route-handler-execution.d.ts +1 -0
  81. package/dist/server/app-route-handler-execution.js +2 -2
  82. package/dist/server/app-route-handler-runtime.js +1 -1
  83. package/dist/server/app-router-entry.js +2 -2
  84. package/dist/server/app-rsc-handler.d.ts +9 -2
  85. package/dist/server/app-rsc-handler.js +30 -10
  86. package/dist/server/app-rsc-response-stage.js +6 -3
  87. package/dist/server/app-rsc-route-matching.js +1 -1
  88. package/dist/server/app-server-action-execution.js +35 -6
  89. package/dist/server/app-ssr-entry.js +7 -2
  90. package/dist/server/app-ssr-stream.js +25 -6
  91. package/dist/server/app-worker-stages.d.ts +4 -1
  92. package/dist/server/app-worker-stages.js +4 -4
  93. package/dist/server/artifact-compatibility.js +1 -1
  94. package/dist/server/client-reuse-manifest.js +1 -1
  95. package/dist/server/dev-lockfile.d.ts +1 -1
  96. package/dist/server/dev-lockfile.js +4 -1
  97. package/dist/server/dev-server.d.ts +1 -1
  98. package/dist/server/dev-server.js +28 -6
  99. package/dist/server/dev-stack-sourcemap.js +1 -1
  100. package/dist/server/html.d.ts +0 -20
  101. package/dist/server/html.js +16 -1
  102. package/dist/server/instrumentation.d.ts +4 -9
  103. package/dist/server/instrumentation.js +10 -15
  104. package/dist/server/isr-cache.js +3 -3
  105. package/dist/server/metadata-route-response.d.ts +1 -0
  106. package/dist/server/metadata-route-response.js +65 -0
  107. package/dist/server/middleware-runtime.js +3 -3
  108. package/dist/server/pages-asset-tags.d.ts +1 -0
  109. package/dist/server/pages-asset-tags.js +37 -2
  110. package/dist/server/pages-client-assets.d.ts +7 -0
  111. package/dist/server/pages-data-route.js +1 -1
  112. package/dist/server/pages-dev-hydration.d.ts +6 -0
  113. package/dist/server/pages-dev-hydration.js +19 -7
  114. package/dist/server/pages-document-initial-props.d.ts +1 -0
  115. package/dist/server/pages-document-initial-props.js +1 -1
  116. package/dist/server/pages-page-data.js +2 -2
  117. package/dist/server/pages-page-handler.js +5 -2
  118. package/dist/server/pages-page-response.d.ts +1 -0
  119. package/dist/server/pages-page-response.js +3 -2
  120. package/dist/server/pages-request-pipeline.js +3 -3
  121. package/dist/server/pages-request-stage-entry.js +3 -3
  122. package/dist/server/pages-revalidate.js +1 -1
  123. package/dist/server/prerender-route-params.js +1 -1
  124. package/dist/server/prod-server.js +19 -13
  125. package/dist/server/request-pipeline.js +2 -2
  126. package/dist/server/rsc-stream-hints.d.ts +12 -0
  127. package/dist/server/rsc-stream-hints.js +70 -35
  128. package/dist/server/seed-cache.js +3 -4
  129. package/dist/server/socket-error-backstop.js +1 -1
  130. package/dist/shims/cache-callable-runtime.d.ts +38 -0
  131. package/dist/shims/cache-callable-runtime.js +162 -11
  132. package/dist/shims/cache-runtime.d.ts +6 -8
  133. package/dist/shims/cache-runtime.js +89 -24
  134. package/dist/shims/constants.js +1 -1
  135. package/dist/shims/dynamic-preload-chunks.js +6 -2
  136. package/dist/shims/font-local.js +1 -1
  137. package/dist/shims/form.js +1 -1
  138. package/dist/shims/head.js +1 -1
  139. package/dist/shims/headers.js +2 -2
  140. package/dist/shims/image-config.js +2 -0
  141. package/dist/shims/internal/app-page-props-cache-key.d.ts +29 -0
  142. package/dist/shims/internal/app-page-props-cache-key.js +53 -1
  143. package/dist/shims/internal/format-url-object.d.ts +7 -0
  144. package/dist/shims/internal/format-url-object.js +53 -0
  145. package/dist/shims/internal/normalize-router-href.d.ts +15 -0
  146. package/dist/shims/internal/normalize-router-href.js +41 -0
  147. package/dist/shims/internal/pages-data-target.d.ts +4 -1
  148. package/dist/shims/internal/pages-data-target.js +28 -35
  149. package/dist/shims/internal/route-pattern-for-warning.d.ts +2 -2
  150. package/dist/shims/internal/route-pattern-for-warning.js +3 -3
  151. package/dist/shims/link.js +31 -92
  152. package/dist/shims/metadata.js +5 -4
  153. package/dist/shims/navigation.js +2 -2
  154. package/dist/shims/router-state.js +1 -1
  155. package/dist/shims/router.d.ts +8 -7
  156. package/dist/shims/router.js +312 -148
  157. package/dist/shims/script-nonce-context.d.ts +4 -1
  158. package/dist/shims/script-nonce-context.js +15 -6
  159. package/dist/shims/server.js +3 -3
  160. package/dist/utils/built-asset-url.js +1 -1
  161. package/dist/utils/client-runtime-metadata.d.ts +6 -0
  162. package/dist/utils/client-runtime-metadata.js +16 -0
  163. package/dist/utils/lazy-chunks.js +1 -1
  164. package/dist/utils/project.d.ts +1 -11
  165. package/dist/utils/project.js +20 -29
  166. package/dist/utils/react-version.d.ts +3 -1
  167. package/dist/utils/react-version.js +19 -1
  168. package/dist/utils/vite-cli-invocation.d.ts +21 -0
  169. package/dist/utils/vite-cli-invocation.js +144 -0
  170. package/package.json +10 -2
@@ -1,5 +1,6 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
2
  import { magicStringTransformResult } from "./transform-result.js";
3
+ import { resolveHarfbuzzWasmPath } from "./og-harfbuzz.js";
3
4
  import { OgAssetOwnership } from "./og-asset-ownership.js";
4
5
  import { createRequire } from "node:module";
5
6
  import fs from "node:fs";
@@ -94,7 +95,11 @@ function createOgInlineFetchAssetsPlugin() {
94
95
  }
95
96
  };
96
97
  }
97
- const OG_WASM_ASSETS = ["resvg.wasm", "yoga.wasm"];
98
+ const OG_WASM_ASSETS = [
99
+ "resvg.wasm",
100
+ "yoga.wasm",
101
+ "hb.wasm"
102
+ ];
98
103
  /**
99
104
  * Find an emitted WASM asset in the output bundle whose name corresponds to the
100
105
  * given base file (e.g. base `resvg.wasm` matches the emitted `resvg-HASH.wasm`).
@@ -105,15 +110,20 @@ const OG_WASM_ASSETS = ["resvg.wasm", "yoga.wasm"];
105
110
  *
106
111
  * @returns the emitted asset's `fileName` (relative to outDir), or null.
107
112
  */
108
- function findEmittedWasmAsset(bundle, baseName) {
113
+ function findEmittedWasmAsset(bundle, baseName, expectedSource) {
109
114
  const stem = baseName.replace(/\.wasm$/, "");
110
115
  const re = new RegExp(`^${stem}(?:[-.][\\w-]+)?\\.wasm$`);
111
116
  for (const output of Object.values(bundle)) {
112
117
  if (output.type !== "asset") continue;
113
- if (re.test(path.basename(output.fileName))) return output.fileName;
118
+ if (!re.test(path.basename(output.fileName))) continue;
119
+ if (expectedSource && !isSameBytes(output.source, expectedSource)) continue;
120
+ return output.fileName;
114
121
  }
115
122
  return null;
116
123
  }
124
+ function isSameBytes(source, expected) {
125
+ return source instanceof Uint8Array && Buffer.from(source).equals(expected);
126
+ }
117
127
  /**
118
128
  * Build the regex that matches the Node.js fallback reference
119
129
  * `new URL("./<base>", import.meta.url)` for a given WASM base name.
@@ -162,7 +172,7 @@ function copyMissingOgWasm(opts) {
162
172
  * target — so it helps Node/self-hosted builds as well as Cloudflare Workers.
163
173
  */
164
174
  function createOgAssetsPlugin() {
165
- let dedupedBases = /* @__PURE__ */ new Set();
175
+ const dedupedBasesByEnvironment = /* @__PURE__ */ new Map();
166
176
  return {
167
177
  name: "vinext:og-assets",
168
178
  apply: "build",
@@ -170,17 +180,18 @@ function createOgAssetsPlugin() {
170
180
  generateBundle: {
171
181
  order: "post",
172
182
  handler(_options, bundle) {
173
- if (this.environment?.name !== "rsc") return;
174
- dedupedBases = /* @__PURE__ */ new Set();
183
+ const envName = this.environment?.name;
184
+ if (envName !== "rsc" && envName !== "ssr") return;
185
+ const dedupedBases = /* @__PURE__ */ new Set();
186
+ dedupedBasesByEnvironment.set(envName, dedupedBases);
175
187
  const chunks = Object.values(bundle).filter((o) => o.type === "chunk");
176
188
  for (const base of OG_WASM_ASSETS) {
177
189
  if (!chunks.some((c) => c.code.includes(base))) continue;
178
- const emitted = findEmittedWasmAsset(bundle, base);
179
- if (!emitted) continue;
190
+ const emitted = findEmittedWasmAsset(bundle, base, base === "hb.wasm" ? fs.readFileSync(resolveHarfbuzzWasmPath(createRequire(import.meta.url).resolve("@vercel/og"))) : void 0);
180
191
  for (const chunk of chunks) {
181
192
  const re = fallbackUrlRegex(base);
182
193
  const chunkDir = path.dirname(chunk.fileName);
183
- const rel = path.relative(chunkDir, emitted);
194
+ const rel = path.relative(chunkDir, emitted ?? base);
184
195
  const ref = rel.startsWith(".") ? rel : `./${rel}`;
185
196
  const s = new MagicString(chunk.code);
186
197
  let edited = false;
@@ -197,7 +208,7 @@ function createOgAssetsPlugin() {
197
208
  source: chunk.fileName
198
209
  });
199
210
  }
200
- dedupedBases.add(base);
211
+ if (emitted) dedupedBases.add(base);
201
212
  }
202
213
  }
203
214
  },
@@ -205,18 +216,26 @@ function createOgAssetsPlugin() {
205
216
  sequential: true,
206
217
  order: "post",
207
218
  async handler(options, bundle) {
208
- if (this.environment?.name !== "rsc") return;
219
+ const envName = this.environment?.name;
220
+ if (envName !== "rsc" && envName !== "ssr") return;
209
221
  const outDir = options.dir;
210
222
  if (!outDir) return;
211
223
  const chunkCode = Object.values(bundle).map((output) => output.type === "chunk" ? output.code : "").join("\n");
212
- const referencedAssets = OG_WASM_ASSETS.filter((asset) => chunkCode.includes(asset) && !dedupedBases.has(asset));
224
+ const dedupedBases = dedupedBasesByEnvironment.get(envName);
225
+ dedupedBasesByEnvironment.delete(envName);
226
+ const referencedAssets = OG_WASM_ASSETS.filter((asset) => chunkCode.includes(asset) && !dedupedBases?.has(asset));
213
227
  if (referencedAssets.length === 0) return;
214
228
  try {
215
229
  const ogPkgPath = createRequire(import.meta.url).resolve("@vercel/og/package.json");
216
230
  copyMissingOgWasm({
217
231
  outDir,
218
232
  sourceDir: path.join(path.dirname(ogPkgPath), "dist"),
219
- assets: referencedAssets
233
+ assets: referencedAssets.filter((asset) => asset !== "hb.wasm")
234
+ });
235
+ if (referencedAssets.includes("hb.wasm")) copyMissingOgWasm({
236
+ outDir,
237
+ sourceDir: path.dirname(resolveHarfbuzzWasmPath(ogPkgPath)),
238
+ assets: ["hb.wasm"]
220
239
  });
221
240
  } catch {}
222
241
  }
@@ -0,0 +1,24 @@
1
+ import { Plugin } from "vite";
2
+ //#region src/plugins/og-harfbuzz.d.ts
3
+ /**
4
+ * Resolve the `hb.wasm` binary that matches the glue inlined in @vercel/og.
5
+ * @vercel/og and satori pin exact versions, so resolving through
6
+ * @vercel/og → satori → harfbuzzjs yields the build the bundle was made from.
7
+ */
8
+ export declare function resolveHarfbuzzWasmPath(ogEntry: string): string;
9
+ /**
10
+ * Read every function type in a WASM binary as an Emscripten signature (result
11
+ * letter, or `v` for none, then parameters). Any callback HarfBuzz calls
12
+ * through its function table must have one of these types, so adapters for
13
+ * all of them cover every callback the glue can register.
14
+ */
15
+ export declare function readWasmFunctionSignatures(wasm: Uint8Array): string[];
16
+ /**
17
+ * Build the module Emscripten's `convertJsFunctionToWasm` compiles for a
18
+ * signature: it imports a JavaScript function as `e.f` and re-exports it as
19
+ * `f`. Every section in it is shorter than 128 bytes, so each length and count
20
+ * is a single LEB128 byte.
21
+ */
22
+ export declare function createHarfbuzzCallbackWasm(signature: string): Uint8Array<ArrayBuffer>;
23
+ export declare function createOgHarfbuzzPlugin(): Plugin;
24
+ //#endregion
@@ -0,0 +1,260 @@
1
+ import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
+ import { magicStringTransformResult } from "./transform-result.js";
3
+ import { forEachAstChild, getAstName, staticStringValue } from "./ast-utils.js";
4
+ import { isFunctionNode } from "./ast-scope.js";
5
+ import { createRequire } from "node:module";
6
+ import fs from "node:fs";
7
+ import { parseAst } from "vite";
8
+ import MagicString from "magic-string";
9
+ //#region src/plugins/og-harfbuzz.ts
10
+ /**
11
+ * vinext:og-harfbuzz — load @vercel/og's bundled HarfBuzz under vinext.
12
+ *
13
+ * @vercel/og 1.x inlines harfbuzzjs's Emscripten glue into both entry bundles.
14
+ * Unmodified, that glue cannot start:
15
+ *
16
+ * - Node ESM: its Node branch calls esbuild's `__require("fs")` and reads
17
+ * `__dirname`, neither of which exists in an ES module.
18
+ * - workerd: it reads `self.location.href`, takes the Node branch under
19
+ * `nodejs_compat`, and fetches `hb.wasm` from a relative URL. Workers also
20
+ * forbid compiling WASM from bytes, which Emscripten does for every
21
+ * JavaScript callback it adds to the WASM function table.
22
+ *
23
+ * The transform locates the HarfBuzz factory by syntax (the function that
24
+ * names `"hb.wasm"` and reads Emscripten's `instantiateWasm` hook) and, inside
25
+ * it only:
26
+ *
27
+ * 1. sets every `ENVIRONMENT_IS_*` flag to `false`, so no host branch runs;
28
+ * 2. replaces `instantiateWasm` reads with a vinext loader that instantiates
29
+ * `hb.wasm` synchronously (a `?module` import on workerd, a disk read on
30
+ * Node), so a bad binary rejects initialization instead of hanging it;
31
+ * 3. on workerd, serves callback modules from precompiled adapters instead
32
+ * of `new WebAssembly.Module(bytes)`.
33
+ *
34
+ * Whitespace, esbuild's renames and harfbuzzjs's wrapper code can change
35
+ * freely. If a patch site is missing, the build fails with an explicit error
36
+ * instead of shipping an OG route that breaks at runtime.
37
+ */
38
+ const HARFBUZZ_WASM = "hb.wasm";
39
+ const VALUE_TYPES = {
40
+ i: 127,
41
+ j: 126,
42
+ f: 125,
43
+ d: 124
44
+ };
45
+ const VALUE_TYPE_LETTERS = new Map(Object.entries(VALUE_TYPES).map(([k, v]) => [v, k]));
46
+ /**
47
+ * Resolve the `hb.wasm` binary that matches the glue inlined in @vercel/og.
48
+ * @vercel/og and satori pin exact versions, so resolving through
49
+ * @vercel/og → satori → harfbuzzjs yields the build the bundle was made from.
50
+ */
51
+ function resolveHarfbuzzWasmPath(ogEntry) {
52
+ const satoriEntry = createRequire(ogEntry).resolve("satori");
53
+ return toSlash(createRequire(satoriEntry).resolve(`harfbuzzjs/${HARFBUZZ_WASM}`));
54
+ }
55
+ /**
56
+ * Read every function type in a WASM binary as an Emscripten signature (result
57
+ * letter, or `v` for none, then parameters). Any callback HarfBuzz calls
58
+ * through its function table must have one of these types, so adapters for
59
+ * all of them cover every callback the glue can register.
60
+ */
61
+ function readWasmFunctionSignatures(wasm) {
62
+ let offset = 8;
63
+ const readU32 = () => {
64
+ let result = 0;
65
+ for (let shift = 0;; shift += 7) {
66
+ const byte = wasm[offset++];
67
+ result |= (byte & 127) << shift;
68
+ if (!(byte & 128)) return result >>> 0;
69
+ }
70
+ };
71
+ const readTypes = () => {
72
+ let letters = "";
73
+ for (let count = readU32(); count > 0; count--) {
74
+ const letter = VALUE_TYPE_LETTERS.get(wasm[offset++]);
75
+ letters = letter && letters !== null ? letters + letter : null;
76
+ }
77
+ return letters;
78
+ };
79
+ const signatures = /* @__PURE__ */ new Set();
80
+ while (offset < wasm.length) {
81
+ const sectionId = wasm[offset++];
82
+ const sectionEnd = readU32() + offset;
83
+ if (sectionId === 1) for (let count = readU32(); count > 0; count--) {
84
+ offset++;
85
+ const params = readTypes();
86
+ const results = readTypes();
87
+ if (params !== null && results !== null && results.length <= 1) signatures.add((results || "v") + params);
88
+ }
89
+ offset = sectionEnd;
90
+ }
91
+ return [...signatures];
92
+ }
93
+ /**
94
+ * Build the module Emscripten's `convertJsFunctionToWasm` compiles for a
95
+ * signature: it imports a JavaScript function as `e.f` and re-exports it as
96
+ * `f`. Every section in it is shorter than 128 bytes, so each length and count
97
+ * is a single LEB128 byte.
98
+ */
99
+ function createHarfbuzzCallbackWasm(signature) {
100
+ const typeCode = (letter) => {
101
+ const code = VALUE_TYPES[letter];
102
+ if (code === void 0) throw new Error(`[vinext] Invalid WASM callback signature: ${signature}`);
103
+ return code;
104
+ };
105
+ const [result, ...params] = signature;
106
+ const results = result === "v" ? [] : [typeCode(result)];
107
+ const functionType = [
108
+ 96,
109
+ params.length,
110
+ ...params.map(typeCode),
111
+ results.length,
112
+ ...results
113
+ ];
114
+ if (functionType.length > 64) throw new Error(`[vinext] WASM callback signature too long: ${signature}`);
115
+ const section = (id, contents) => [
116
+ id,
117
+ contents.length,
118
+ ...contents
119
+ ];
120
+ return Uint8Array.from([
121
+ 0,
122
+ 97,
123
+ 115,
124
+ 109,
125
+ 1,
126
+ 0,
127
+ 0,
128
+ 0,
129
+ ...section(1, [1, ...functionType]),
130
+ ...section(2, [
131
+ 1,
132
+ 1,
133
+ 101,
134
+ 1,
135
+ 102,
136
+ 0,
137
+ 0
138
+ ]),
139
+ ...section(7, [
140
+ 1,
141
+ 1,
142
+ 102,
143
+ 0,
144
+ 0
145
+ ])
146
+ ]);
147
+ }
148
+ /** Write each callback adapter once and return its path by signature. */
149
+ function writeHarfbuzzCallbackModules(harfbuzzWasm, outDir) {
150
+ fs.mkdirSync(outDir, { recursive: true });
151
+ const modules = /* @__PURE__ */ new Map();
152
+ for (const signature of readWasmFunctionSignatures(fs.readFileSync(harfbuzzWasm))) {
153
+ const filePath = path.join(outDir, `harfbuzz-callback-${signature}.wasm`);
154
+ if (!fs.existsSync(filePath)) {
155
+ const tempPath = `${filePath}.${process.pid}.tmp`;
156
+ fs.writeFileSync(tempPath, createHarfbuzzCallbackWasm(signature));
157
+ fs.renameSync(tempPath, filePath);
158
+ }
159
+ modules.set(signature, filePath);
160
+ }
161
+ return modules;
162
+ }
163
+ const contains = (outer, inner) => outer.start <= inner.start && inner.end <= outer.end;
164
+ /**
165
+ * Find the HarfBuzz factory — the innermost function that both names
166
+ * `"hb.wasm"` and reads `instantiateWasm` — and the patch sites inside it.
167
+ * Scoping edits to that function keeps yoga's own Emscripten module, which
168
+ * also reads `instantiateWasm`, untouched.
169
+ */
170
+ function findHarfbuzzPatchSites(program) {
171
+ const functionStack = [];
172
+ const wasmNameScopes = [];
173
+ const instantiateWasmMembers = [];
174
+ const environmentFlags = [];
175
+ const moduleCompilations = [];
176
+ const visit = (node) => {
177
+ const isFunction = isFunctionNode(node);
178
+ if (isFunction) functionStack.push(node);
179
+ if (staticStringValue(node) === HARFBUZZ_WASM) wasmNameScopes.push([...functionStack]);
180
+ else if (node.type === "MemberExpression" && getAstName(node.property) === "instantiateWasm") instantiateWasmMembers.push(node);
181
+ else if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.id.name.startsWith("ENVIRONMENT_IS_") && node.init) environmentFlags.push({
182
+ declarator: node,
183
+ init: node.init
184
+ });
185
+ else if (node.type === "NewExpression" && node.callee.type === "MemberExpression" && getAstName(node.callee.object) === "WebAssembly" && getAstName(node.callee.property) === "Module" && functionStack.length > 0) moduleCompilations.push({
186
+ node,
187
+ enclosingFunction: functionStack[functionStack.length - 1]
188
+ });
189
+ forEachAstChild(node, visit);
190
+ if (isFunction) functionStack.pop();
191
+ };
192
+ visit(program);
193
+ const factories = /* @__PURE__ */ new Set();
194
+ for (const scopes of wasmNameScopes) {
195
+ const factory = [...scopes].reverse().find((scope) => instantiateWasmMembers.some((member) => contains(scope, member)));
196
+ if (factory) factories.add(factory);
197
+ }
198
+ if (factories.size !== 1) return `expected one function that names "${HARFBUZZ_WASM}" and reads instantiateWasm, found ${factories.size}`;
199
+ const [factory] = factories;
200
+ const flags = environmentFlags.filter(({ declarator }) => contains(factory, declarator));
201
+ if (!flags.some(({ declarator }) => getAstName(declarator.id) === "ENVIRONMENT_IS_NODE")) return "the factory does not declare ENVIRONMENT_IS_NODE";
202
+ return {
203
+ instantiateWasmReads: instantiateWasmMembers.filter((member) => contains(factory, member)),
204
+ environmentFlags: flags.map(({ init }) => init),
205
+ moduleCompilations: moduleCompilations.filter(({ node }) => contains(factory, node))
206
+ };
207
+ }
208
+ const INSTANTIATE_WASM = `function __vi_hb_instantiateWasm(imports, receiveInstance) {
209
+ var instance = new WebAssembly.Instance(__vi_hb_module(), imports);
210
+ receiveInstance(instance);
211
+ return instance.exports;
212
+ }`;
213
+ function createOgHarfbuzzPlugin() {
214
+ let callbackModuleDir;
215
+ let isBuild = false;
216
+ return {
217
+ name: "vinext:og-harfbuzz",
218
+ enforce: "pre",
219
+ configResolved(config) {
220
+ callbackModuleDir = path.join(toSlash(config.root), ".vinext", "og-assets");
221
+ isBuild = config.command === "build";
222
+ },
223
+ transform: {
224
+ filter: {
225
+ id: /[\\/]@vercel[\\/]og[\\/]dist[\\/]index\.(?:edge|node)\.js(?:\?.*)?$/,
226
+ code: /["'`]hb\.wasm["'`]/
227
+ },
228
+ handler(code, id) {
229
+ const ogEntry = toSlash(id.split("?", 1)[0]);
230
+ const isWorkerd = ogEntry.endsWith("/index.edge.js");
231
+ const fail = (reason) => this.error(`[vinext] Unsupported @vercel/og HarfBuzz bundle in ${ogEntry}: ${reason}. vinext must be updated to support this @vercel/og version.`);
232
+ const sites = findHarfbuzzPatchSites(parseAst(code, { lang: "js" }));
233
+ if (typeof sites === "string") return fail(sites);
234
+ const output = new MagicString(code);
235
+ for (const flag of sites.environmentFlags) output.overwrite(flag.start, flag.end, "false");
236
+ for (const member of sites.instantiateWasmReads) output.overwrite(member.start, member.end, "__vi_hb_instantiateWasm");
237
+ const harfbuzzWasm = resolveHarfbuzzWasmPath(ogEntry);
238
+ const preamble = [];
239
+ if (isWorkerd) {
240
+ if (sites.moduleCompilations.length === 0) return fail("no callback module compilation (new WebAssembly.Module) was found");
241
+ for (const { node, enclosingFunction } of sites.moduleCompilations) {
242
+ const signature = isFunctionNode(enclosingFunction) ? enclosingFunction.params[1] : void 0;
243
+ if (signature?.type !== "Identifier") return fail("the callback compiler does not take a (func, sig) signature");
244
+ output.prependLeft(node.start, `(__vi_hb_callbacks[${signature.name}.replace(/p/g, "i")] || `);
245
+ output.appendRight(node.end, ")");
246
+ }
247
+ const callbacks = [...writeHarfbuzzCallbackModules(harfbuzzWasm, callbackModuleDir)];
248
+ preamble.push(`import __vi_hb_wasm from ${JSON.stringify(`${harfbuzzWasm}?module`)};`, ...callbacks.map(([, file], index) => `import __vi_hb_callback_${index} from ${JSON.stringify(`${file}?module`)};`), `var __vi_hb_callbacks = { ${callbacks.map(([signature], index) => `${signature}: __vi_hb_callback_${index}`).join(", ")} };`, "function __vi_hb_module() { return __vi_hb_wasm; }");
249
+ } else {
250
+ const location = isBuild ? `new URL("./${HARFBUZZ_WASM}", import.meta.url)` : JSON.stringify(harfbuzzWasm);
251
+ preamble.push(`import { readFileSync as __vi_hb_readFileSync } from "node:fs";`, `function __vi_hb_module() { return new WebAssembly.Module(__vi_hb_readFileSync(${location})); }`);
252
+ }
253
+ output.prepend(`${preamble.join("\n")}\n${INSTANTIATE_WASM}\n`);
254
+ return magicStringTransformResult(output);
255
+ }
256
+ }
257
+ };
258
+ }
259
+ //#endregion
260
+ export { createHarfbuzzCallbackWasm, createOgHarfbuzzPlugin, readWasmFunctionSignatures, resolveHarfbuzzWasmPath };
@@ -5,8 +5,8 @@ import { VIRTUAL_MODULE_ID_RE } from "../utils/virtual-module.js";
5
5
  import { collectBindingNames, getAstName } from "./ast-utils.js";
6
6
  import { createRequire } from "node:module";
7
7
  import { parseAst } from "vite";
8
- import fsp from "node:fs/promises";
9
8
  import MagicString from "magic-string";
9
+ import fsp from "node:fs/promises";
10
10
  //#region src/plugins/optimize-imports.ts
11
11
  /**
12
12
  * Read a file's contents, returning null on any error.
@@ -1,11 +1,11 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { stripViteModuleQuery } from "../utils/path.js";
3
2
  import { magicStringTransformResult } from "./transform-result.js";
3
+ import { stripViteModuleQuery } from "../utils/path.js";
4
4
  import { SCRIPT_MODULE_ID_RE, collectBindingNames, forEachAstChild, isIdentifierNamed, scriptParserLanguage, staticStringValue, unwrapExpression } from "./ast-utils.js";
5
5
  import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, createAstScope, hasAstBinding, isFunctionNode } from "./ast-scope.js";
6
6
  import { createIdResolver, parseAst } from "vite";
7
- import { readFile } from "node:fs/promises";
8
7
  import MagicString from "magic-string";
8
+ import { readFile } from "node:fs/promises";
9
9
  //#region src/plugins/require-condition-resolution.ts
10
10
  const LITERAL_REQUIRE_RE = /\brequire\s*\(/;
11
11
  const CONDITIONAL_REQUIRE_SCRIPT_ID_RE = /\.vinext-require\.(?:js|jsx|ts|tsx)$/i;
@@ -1,10 +1,10 @@
1
1
  import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { stripViteModuleQuery } from "../utils/path.js";
3
2
  import { magicStringTransformResult } from "./transform-result.js";
3
+ import { stripViteModuleQuery } from "../utils/path.js";
4
4
  import { SCRIPT_MODULE_ID_RE, booleanLiteralValue, scriptParserLanguage, stringLiteralValue, walkAst } from "./ast-utils.js";
5
5
  import { parseAst } from "vite";
6
- import { readdir, realpath, stat } from "node:fs/promises";
7
6
  import MagicString from "magic-string";
7
+ import { readdir, realpath, stat } from "node:fs/promises";
8
8
  //#region src/plugins/require-context.ts
9
9
  function createRequireContextPlugin() {
10
10
  const watchedContexts = /* @__PURE__ */ new WeakMap();
@@ -1,6 +1,6 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { stripViteModuleQuery } from "../utils/path.js";
3
2
  import { magicStringTransformResult } from "./transform-result.js";
3
+ import { stripViteModuleQuery } from "../utils/path.js";
4
4
  import { booleanLiteralValue, collectBindingNames, forEachAstChild, isIdentifierNamed, stringLiteralValue } from "./ast-utils.js";
5
5
  import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, createAstScope, hasAstBinding, isFunctionNode } from "./ast-scope.js";
6
6
  import { parseAst } from "vite";
@@ -3,8 +3,6 @@ import { Plugin } from "vite";
3
3
  type Options = {
4
4
  projectRoot: string;
5
5
  cacheRuntime: string;
6
- getAppDir: () => string | undefined;
7
- matchesPageExtension: (fileName: string) => boolean;
8
6
  allowMissingRsc?: boolean;
9
7
  };
10
8
  export declare function createUseCacheCallablePlugin(options: Options): Promise<Plugin>;
@@ -1,9 +1,10 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { NODE_MODULES_PATH_RE, isPathInside, stripViteModuleQuery } from "../utils/path.js";
3
2
  import { magicStringTransformResult } from "./transform-result.js";
3
+ import { NODE_MODULES_PATH_RE } from "../utils/path.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { parseAstAsync } from "vite";
6
6
  import { pathToFileURL } from "node:url";
7
+ import { createHmac, randomBytes } from "node:crypto";
7
8
  //#region src/plugins/use-cache-callable.ts
8
9
  const PLUGIN_NAME = "vinext:server-function-directives";
9
10
  const SOURCE_MODULE_ID_RE = /\.(?:tsx?|jsx?|mjs)(?:\?.*)?$/;
@@ -43,13 +44,6 @@ function acceptsSecondArgument(meta) {
43
44
  if (node?.type !== "FunctionDeclaration" && node?.type !== "FunctionExpression" && node?.type !== "ArrowFunctionExpression") return true;
44
45
  return node.params.length >= 2 || node.params.some((parameter) => parameter.type === "RestElement");
45
46
  }
46
- function isAppPageDefaultExport(options, id, name, isModuleDirective) {
47
- const appDir = options.getAppDir();
48
- if (!isModuleDirective || name !== "default" || !appDir) return false;
49
- const modulePath = stripViteModuleQuery(id);
50
- const moduleFileName = path.basename(modulePath);
51
- return isPathInside(appDir, modulePath) && path.parse(moduleFileName).name === "page" && options.matchesPageExtension(moduleFileName);
52
- }
53
47
  function shouldTransformModuleExport(name, id, meta) {
54
48
  if (meta.isFunction === false && (name !== "default" && meta.valueNode?.type === "Literal" || meta.valueNode?.type === "ObjectExpression" || meta.valueNode?.type === "ArrayExpression")) return false;
55
49
  if (/\/(layout|template)\.(tsx?|jsx?|mjs)$/.test(id) && name === "default") return false;
@@ -65,11 +59,21 @@ function hasFunctionDirective(meta, directive) {
65
59
  if (node?.type !== "FunctionDeclaration" && node?.type !== "FunctionExpression" && node?.type !== "ArrowFunctionExpression" || node.body.type !== "BlockStatement") return false;
66
60
  return node.body.body.some((statement) => statement.type === "ExpressionStatement" && "directive" in statement && statement.directive === directive);
67
61
  }
68
- function getCacheWrapperOptions(options, id, name, isModuleDirective, meta) {
62
+ function getFunctionDirectiveExportNames(transforms, ast, directive) {
63
+ const names = /* @__PURE__ */ new Set();
64
+ for (const group of transforms.scanModuleExports(ast)) {
65
+ const entries = group.type === "declaration" ? [group.export] : group.type === "variable-declaration" ? group.declarators.flatMap((declarator) => declarator.exports) : group.type === "specifiers" ? group.exports : group.type === "default" ? [{
66
+ exportName: "default",
67
+ meta: group.meta
68
+ }] : [];
69
+ for (const entry of entries) if (hasFunctionDirective(entry.meta, directive)) names.add(entry.exportName);
70
+ }
71
+ return names;
72
+ }
73
+ function getCacheWrapperOptions(meta) {
69
74
  const argumentCount = getArgumentCount(meta);
70
75
  return {
71
76
  acceptsSecondArgument: acceptsSecondArgument(meta),
72
- ...isAppPageDefaultExport(options, id, name, isModuleDirective) ? { appPageDefaultExport: true } : {},
73
77
  ...argumentCount === void 0 ? {} : { argumentCount }
74
78
  };
75
79
  }
@@ -78,6 +82,7 @@ async function createUseCacheCallablePlugin(options) {
78
82
  const transformsPath = resolvePluginRscModule(options.projectRoot, "@vitejs/plugin-rsc/transforms");
79
83
  const rscModule = await import(pathToFileURL(rscModulePath).href);
80
84
  const transforms = await import(pathToFileURL(transformsPath).href);
85
+ const referenceSecret = randomBytes(32);
81
86
  let manager;
82
87
  return {
83
88
  name: PLUGIN_NAME,
@@ -109,6 +114,8 @@ async function createUseCacheCallablePlugin(options) {
109
114
  const useServerBoundary = transforms.hasDirective(ast.body, "use server");
110
115
  if (moduleDirective && useServerBoundary) throw new Error(`A module cannot contain both ${JSON.stringify(moduleDirective)} and "use server" directives.`);
111
116
  const reference = manager.serverReferences.resolve(id, "rsc");
117
+ const relativeImportId = manager.toRelativeId(reference.importId);
118
+ const secureExportName = (name) => `$$vinext_cache_${createHmac("sha256", referenceSecret).update(relativeImportId).update("\0").update(name).digest("hex")}`;
112
119
  if (!(this.environment.name === "rsc")) {
113
120
  if (useServerBoundary) {
114
121
  manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
@@ -126,6 +133,7 @@ async function createUseCacheCallablePlugin(options) {
126
133
  manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
127
134
  return;
128
135
  }
136
+ const useServerExportNames = getFunctionDirectiveExportNames(transforms, ast, "use server");
129
137
  const result = transforms.transformDirectiveProxyExport(ast, {
130
138
  code,
131
139
  directive: moduleDirective,
@@ -134,7 +142,7 @@ async function createUseCacheCallablePlugin(options) {
134
142
  validateModuleExport(transforms, meta);
135
143
  return true;
136
144
  },
137
- runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${name}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
145
+ runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${useServerExportNames.has(name) ? name : secureExportName(name)}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
138
146
  });
139
147
  if (!result?.output.hasChanged()) {
140
148
  manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
@@ -142,7 +150,7 @@ async function createUseCacheCallablePlugin(options) {
142
150
  }
143
151
  manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
144
152
  ...reference,
145
- exportNames: result.exportNames
153
+ exportNames: result.exportNames.map((name) => useServerExportNames.has(name) ? name : secureExportName(name))
146
154
  });
147
155
  const runtimeEnvironment = this.environment.name === "client" ? "browser" : "ssr";
148
156
  result.output.prepend(`import * as $$ReactClient from "@vitejs/plugin-rsc/react/${runtimeEnvironment}";\n`);
@@ -151,19 +159,23 @@ async function createUseCacheCallablePlugin(options) {
151
159
  source: id
152
160
  });
153
161
  }
154
- const wrap = (value, name, directiveMatch, meta, isModuleDirective) => {
162
+ const secureExports = /* @__PURE__ */ new Set();
163
+ const wrap = (value, name, directiveMatch, meta) => {
155
164
  const variant = directiveMatch[1] ?? "";
165
+ const secureName = secureExportName(name);
166
+ secureExports.add(secureName);
156
167
  const wrapperOptions = {
157
- ...getCacheWrapperOptions(options, id, name, isModuleDirective, meta),
158
- serverReferenceId: `${reference.referenceKey}#${name}`
168
+ ...getCacheWrapperOptions(meta),
169
+ serverReferenceId: `${reference.referenceKey}#${secureName}`
159
170
  };
160
171
  return `$$cacheRuntime.registerCachedFunction(${value}, ${JSON.stringify(`${id}:${name}`)}, ${JSON.stringify(variant)}, ${JSON.stringify(wrapperOptions)})`;
161
172
  };
162
173
  let needsReactServer = false;
163
- const runtime = (value, name, directiveMatch, meta, isModuleDirective) => {
164
- const cached = wrap(value, name, directiveMatch, meta, isModuleDirective);
174
+ const runtime = (value, name, directiveMatch, meta) => {
175
+ const cached = wrap(value, name, directiveMatch, meta);
176
+ const secureName = secureExportName(name);
165
177
  needsReactServer = true;
166
- return `$$VinextReactServer.registerServerReference(${cached}, ${JSON.stringify(reference.referenceKey)}, ${JSON.stringify(name)})`;
178
+ return `(${secureName} = $$VinextReactServer.registerServerReference(${cached}, ${JSON.stringify(reference.referenceKey)}, ${JSON.stringify(secureName)}))`;
167
179
  };
168
180
  const result = moduleDirective ? transforms.transformWrapExport(code, ast, {
169
181
  filter: (name, meta) => {
@@ -171,12 +183,13 @@ async function createUseCacheCallablePlugin(options) {
171
183
  validateModuleExport(transforms, meta);
172
184
  return true;
173
185
  },
174
- runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(moduleDirective), meta, true)
186
+ runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(moduleDirective), meta)
175
187
  }) : transforms.transformHoistInlineDirective(code, ast, {
176
188
  directive: USE_CACHE_DIRECTIVE_CANDIDATE,
177
189
  rejectNonAsyncFunction: true,
178
190
  hoistRuntime: true,
179
- runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(meta.directiveMatch[0]), meta, false),
191
+ noExport: true,
192
+ runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(meta.directiveMatch[0]), meta),
180
193
  encode: (value) => `$$cacheRuntime.encryptCacheCaptures(${value})`,
181
194
  decode: (value) => value
182
195
  });
@@ -186,10 +199,15 @@ async function createUseCacheCallablePlugin(options) {
186
199
  }
187
200
  manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
188
201
  ...reference,
189
- exportNames: "names" in result ? result.names : result.exportNames
202
+ exportNames: [...secureExports]
190
203
  });
191
204
  const importPosition = ast.body.find((node) => !("directive" in node))?.start ?? code.length;
192
- result.output.prependLeft(importPosition, [`import * as $$cacheRuntime from ${JSON.stringify(options.cacheRuntime)};`, needsReactServer && `import * as $$VinextReactServer from "@vitejs/plugin-rsc/react/rsc/server";`].filter(Boolean).join("\n") + "\n");
205
+ result.output.prependLeft(importPosition, [
206
+ `import * as $$cacheRuntime from ${JSON.stringify(options.cacheRuntime)};`,
207
+ needsReactServer && `import * as $$VinextReactServer from "@vitejs/plugin-rsc/react/rsc/server";`,
208
+ secureExports.size > 0 && `let ${[...secureExports].join(",")};`
209
+ ].filter(Boolean).join("\n") + "\n");
210
+ if (secureExports.size > 0) result.output.append(`\nexport { ${[...secureExports].join(",")} };\n`);
193
211
  return magicStringTransformResult(result.output, {
194
212
  hires: "boundary",
195
213
  source: id
@@ -1,7 +1,7 @@
1
1
  import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
+ import { magicStringTransformResult } from "./transform-result.js";
2
3
  import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
3
4
  import { NODE_MODULES_PATH_RE, stripViteModuleQuery } from "../utils/path.js";
4
- import { magicStringTransformResult } from "./transform-result.js";
5
5
  import { staticStringValue, walkAst } from "./ast-utils.js";
6
6
  import fs from "node:fs";
7
7
  import { parseAst } from "vite";
@@ -1,6 +1,6 @@
1
1
  import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
3
2
  import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
3
+ import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
4
4
  import { validateRoutePatterns } from "./route-validation.js";
5
5
  import { compareStrings } from "../utils/compare.js";
6
6
  import fs from "node:fs";
@@ -1,6 +1,6 @@
1
1
  import { createValidFileMatcher } from "./file-matcher.js";
2
- import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
3
2
  import { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
3
+ import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
4
4
  //#region src/routing/app-router.ts
5
5
  /**
6
6
  * App Router file-system routing.
@@ -1,6 +1,6 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
- import { decodeRouteSegment, sortRoutes } from "./utils.js";
3
2
  import { createValidFileMatcher, scanWithExtensions } from "./file-matcher.js";
3
+ import { decodeRouteSegment, sortRoutes } from "./utils.js";
4
4
  import { patternToNextFormat, validateRoutePatterns } from "./route-validation.js";
5
5
  import { createRouteTrieCache, matchRouteWithTrieRawPathname } from "./route-matching.js";
6
6
  //#region src/routing/pages-router.ts