veryfront 0.1.993 → 0.1.995

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 (39) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/embedding/index.d.ts +1 -1
  3. package/esm/src/embedding/index.d.ts.map +1 -1
  4. package/esm/src/embedding/rag-store.d.ts.map +1 -1
  5. package/esm/src/embedding/rag-store.js +37 -0
  6. package/esm/src/embedding/types.d.ts +7 -0
  7. package/esm/src/embedding/types.d.ts.map +1 -1
  8. package/esm/src/embedding/upload-loader.d.ts +5 -4
  9. package/esm/src/embedding/upload-loader.d.ts.map +1 -1
  10. package/esm/src/embedding/upload-loader.js +5 -4
  11. package/esm/src/embedding/veryfront-cloud/rag-store.d.ts.map +1 -1
  12. package/esm/src/embedding/veryfront-cloud/rag-store.js +45 -5
  13. package/esm/src/html/html-injection.d.ts +7 -0
  14. package/esm/src/html/html-injection.d.ts.map +1 -1
  15. package/esm/src/html/html-injection.js +7 -1
  16. package/esm/src/html/hydration-script-builder/templates/renderer.d.ts.map +1 -1
  17. package/esm/src/html/hydration-script-builder/templates/renderer.js +6 -2
  18. package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
  19. package/esm/src/html/hydration-script-builder/templates/router.js +49 -8
  20. package/esm/src/rendering/layouts/layout-applicator.d.ts.map +1 -1
  21. package/esm/src/rendering/layouts/layout-applicator.js +2 -5
  22. package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
  23. package/esm/src/rendering/orchestrator/html.js +1 -0
  24. package/esm/src/rendering/page-rendering.d.ts.map +1 -1
  25. package/esm/src/rendering/page-rendering.js +2 -5
  26. package/esm/src/rendering/script-page-handling.d.ts.map +1 -1
  27. package/esm/src/rendering/script-page-handling.js +2 -5
  28. package/esm/src/routing/api/context-builder.d.ts +4 -0
  29. package/esm/src/routing/api/context-builder.d.ts.map +1 -1
  30. package/esm/src/routing/api/context-builder.js +6 -5
  31. package/esm/src/routing/flatten-route-params.d.ts +11 -0
  32. package/esm/src/routing/flatten-route-params.d.ts.map +1 -0
  33. package/esm/src/routing/flatten-route-params.js +20 -0
  34. package/esm/src/routing/index.d.ts +1 -0
  35. package/esm/src/routing/index.d.ts.map +1 -1
  36. package/esm/src/routing/index.js +1 -0
  37. package/esm/src/utils/version-constant.d.ts +1 -1
  38. package/esm/src/utils/version-constant.js +1 -1
  39. package/package.json +1 -1
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.993",
3
+ "version": "0.1.995",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "minimumDependencyAge": {
@@ -24,6 +24,6 @@ export { loadUpload } from "./upload-loader.js";
24
24
  export { useUploads } from "./react/use-uploads.js";
25
25
  export type { UseUploadsOptions, UseUploadsResult } from "./react/use-uploads.js";
26
26
  export { clearEmbeddingProviders, registerEmbeddingProvider, resolveEmbeddingModel, } from "./resolve.js";
27
- export type { ChunkOptions, Embedding, EmbeddingConfig, RagChunk, RagDocumentMeta, RagSearchOptions, RagSearchResult, RagStore, RagStoreBackend, RagStoreConfig, RagStoreData, SearchOptions, SearchResult, VectorStore, VectorStoreConfig, } from "./types.js";
27
+ export type { ChunkOptions, Embedding, EmbeddingConfig, RagChunk, RagDocumentMeta, RagRefreshOptions, RagSearchOptions, RagSearchResult, RagStore, RagStoreBackend, RagStoreConfig, RagStoreData, SearchOptions, SearchResult, VectorStore, VectorStoreConfig, } from "./types.js";
28
28
  export type { UploadAuthorizationResult, UploadAuthorize, UploadHandlerAuthConfig, UploadHandlerConfig, } from "./upload-handler.js";
29
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,YAAY,EACZ,SAAS,EACT,eAAe,EACf,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,gBAAgB,IAAI,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,YAAY,EACZ,SAAS,EACT,eAAe,EACf,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"rag-store.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/rag-store.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAKV,QAAQ,EAER,cAAc,EAEf,MAAM,YAAY,CAAC;AA2HpB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAkCzD"}
1
+ {"version":3,"file":"rag-store.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/rag-store.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAMV,QAAQ,EAER,cAAc,EAEf,MAAM,YAAY,CAAC;AA2HpB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAyCzD"}
@@ -126,6 +126,13 @@ export function ragStore(config) {
126
126
  ingest(title, text, meta) {
127
127
  return getStore().ingest(title, text, meta);
128
128
  },
129
+ refreshDocument(id, text, meta) {
130
+ const store = getStore();
131
+ if (!store.refreshDocument) {
132
+ throw INVALID_ARGUMENT.create({ detail: "RAG store does not support document refresh" });
133
+ }
134
+ return store.refreshDocument(id, text, meta);
135
+ },
129
136
  search(query, options) {
130
137
  return getStore().search(query, options);
131
138
  },
@@ -404,6 +411,36 @@ function createLocalJsonRagStore(config) {
404
411
  return documentId;
405
412
  });
406
413
  },
414
+ async refreshDocument(id, text, meta) {
415
+ return withLock(async () => {
416
+ const data = await load();
417
+ const document = data.documents.find((doc) => doc.id === id);
418
+ if (!document) {
419
+ throw INVALID_ARGUMENT.create({ detail: `RAG document not found: ${id}` });
420
+ }
421
+ if (text.length > MAX_TEXT_LENGTH) {
422
+ throw INVALID_ARGUMENT.create({
423
+ detail: `Upload text exceeds ${MAX_TEXT_LENGTH / 1024 / 1024} MB limit`,
424
+ });
425
+ }
426
+ const chunks = await chunk(text, chunkOptions);
427
+ if (chunks.length === 0) {
428
+ throw INVALID_ARGUMENT.create({ detail: "Upload contains no extractable text" });
429
+ }
430
+ document.title = meta?.title ?? document.title;
431
+ document.source = meta?.source ?? document.source;
432
+ document.type = meta?.type ?? document.type;
433
+ data.chunks = data.chunks.filter((chunk) => chunk.documentId !== id);
434
+ data.chunks.push(...chunks.map((chunkText, index) => ({
435
+ id: dntShim.crypto.randomUUID(),
436
+ documentId: id,
437
+ text: chunkText,
438
+ embedding: [],
439
+ index,
440
+ })));
441
+ await save(data);
442
+ });
443
+ },
407
444
  async search(query, options) {
408
445
  if (!query.trim())
409
446
  return [];
@@ -102,12 +102,19 @@ export interface RagSearchOptions {
102
102
  topK?: number;
103
103
  threshold?: number;
104
104
  }
105
+ /** Options accepted when refreshing an existing rag document. */
106
+ export interface RagRefreshOptions {
107
+ title?: string;
108
+ source?: string;
109
+ type?: string;
110
+ }
105
111
  /** Public API contract for rag store. */
106
112
  export interface RagStore {
107
113
  ingest(title: string, text: string, meta?: {
108
114
  source?: string;
109
115
  type?: string;
110
116
  }): Promise<string>;
117
+ refreshDocument?(id: string, text: string, meta?: RagRefreshOptions): Promise<void>;
111
118
  search(query: string, options?: RagSearchOptions): Promise<RagSearchResult[]>;
112
119
  listDocuments(): Promise<RagDocumentMeta[]>;
113
120
  removeDocument(id: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/types.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,15 @@
1
1
  /**
2
- * Extracts plain text from various upload formats.
2
+ * Extracts embedding-ready text or Markdown from upload formats.
3
3
  *
4
4
  * Text and CSV are handled inline (CSV uses a RAG-optimized format that
5
5
  * denormalizes headers into every row). All other formats (PDF, DOCX, XLSX,
6
- * PPTX, HTML, RTF, EPUB, etc.) are delegated to the `DocumentExtractor` extension
7
- * contract, which owns kreuzberg and the Worker isolation on Deno.
6
+ * PPTX, HTML, RTF, EPUB, etc.) are delegated to the `DocumentExtractor`
7
+ * extension contract, which owns kreuzberg, Markdown extraction, and Worker
8
+ * isolation on Deno.
8
9
  *
9
10
  * @example
10
11
  * ```ts
11
- * const text = await loadUpload(buffer, "application/pdf");
12
+ * const markdown = await loadUpload(buffer, "application/pdf");
12
13
  * ```
13
14
  */
14
15
  export declare function loadUpload(buffer: ArrayBuffer, mimeType: string): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"upload-loader.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-loader.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BvF"}
1
+ {"version":3,"file":"upload-loader.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-loader.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BvF"}
@@ -1,15 +1,16 @@
1
1
  import { tryResolve } from "../extensions/contracts.js";
2
2
  /**
3
- * Extracts plain text from various upload formats.
3
+ * Extracts embedding-ready text or Markdown from upload formats.
4
4
  *
5
5
  * Text and CSV are handled inline (CSV uses a RAG-optimized format that
6
6
  * denormalizes headers into every row). All other formats (PDF, DOCX, XLSX,
7
- * PPTX, HTML, RTF, EPUB, etc.) are delegated to the `DocumentExtractor` extension
8
- * contract, which owns kreuzberg and the Worker isolation on Deno.
7
+ * PPTX, HTML, RTF, EPUB, etc.) are delegated to the `DocumentExtractor`
8
+ * extension contract, which owns kreuzberg, Markdown extraction, and Worker
9
+ * isolation on Deno.
9
10
  *
10
11
  * @example
11
12
  * ```ts
12
- * const text = await loadUpload(buffer, "application/pdf");
13
+ * const markdown = await loadUpload(buffer, "application/pdf");
13
14
  * ```
14
15
  */
15
16
  export async function loadUpload(buffer, mimeType) {
@@ -1 +1 @@
1
- {"version":3,"file":"rag-store.d.ts","sourceRoot":"","sources":["../../../../src/src/embedding/veryfront-cloud/rag-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAIV,QAAQ,EACR,cAAc,EACf,MAAM,aAAa,CAAC;AA4ErB,KAAK,2BAA2B,GAAG,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA6gBtE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,2BAA2B,GAAG,QAAQ,CA6H1F"}
1
+ {"version":3,"file":"rag-store.d.ts","sourceRoot":"","sources":["../../../../src/src/embedding/veryfront-cloud/rag-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAKV,QAAQ,EACR,cAAc,EACf,MAAM,aAAa,CAAC;AA4ErB,KAAK,2BAA2B,GAAG,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA8kBtE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,2BAA2B,GAAG,QAAQ,CAuI1F"}
@@ -56,12 +56,26 @@ function buildDocumentFilePath(documentId, type) {
56
56
  const extension = type?.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
57
57
  return `${DOCUMENTS_DIR}/${documentId}.${extension || "txt"}`;
58
58
  }
59
+ function buildRefreshDocumentFilePath(documentId, type) {
60
+ const extension = type?.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
61
+ return `${DOCUMENTS_DIR}/${documentId}.refresh-${dntShim.crypto.randomUUID()}.${extension || "txt"}`;
62
+ }
59
63
  function isRecord(value) {
60
64
  return typeof value === "object" && value !== null;
61
65
  }
62
66
  function toStringValue(value, fallback = "") {
63
67
  return typeof value === "string" ? value : fallback;
64
68
  }
69
+ function toPublicRagDocumentMeta(document) {
70
+ return {
71
+ id: document.id,
72
+ title: document.title,
73
+ source: document.source,
74
+ type: document.type,
75
+ createdAt: document.createdAt,
76
+ url: document.url,
77
+ };
78
+ }
65
79
  function buildDocumentChunks(sourceText, chunkTexts, metadata) {
66
80
  let searchStart = 0;
67
81
  return chunkTexts.map((content, index) => {
@@ -176,6 +190,7 @@ async function listRagDocuments(context) {
176
190
  source: doc.source,
177
191
  type: doc.type,
178
192
  createdAt: new Date(doc.created_at).getTime(),
193
+ filePath: typeof doc.metadata?.filePath === "string" ? doc.metadata.filePath : undefined,
179
194
  }));
180
195
  }
181
196
  async function upsertRagDocument(context, document) {
@@ -197,6 +212,28 @@ async function deleteRagDocument(context, documentId) {
197
212
  // Document ingestion (chunks + embeddings + server-side record)
198
213
  // ---------------------------------------------------------------------------
199
214
  async function ingestDocument(context, config, title, text, meta) {
215
+ const documentId = dntShim.crypto.randomUUID();
216
+ await writeDocumentContent(context, config, documentId, title, text, meta);
217
+ return documentId;
218
+ }
219
+ async function refreshCloudDocument(context, config, documentId, text, meta) {
220
+ const documents = await listRagDocuments(context);
221
+ const existing = documents.find((doc) => doc.id === documentId);
222
+ if (!existing) {
223
+ throw INVALID_ARGUMENT.create({ detail: `RAG document not found: ${documentId}` });
224
+ }
225
+ const type = meta?.type ?? existing.type;
226
+ const previousFilePath = existing.filePath ?? buildDocumentFilePath(documentId, existing.type);
227
+ const filePath = buildRefreshDocumentFilePath(documentId, type);
228
+ await writeDocumentContent(context, config, documentId, meta?.title ?? existing.title, text, {
229
+ source: meta?.source ?? existing.source,
230
+ type,
231
+ }, { filePath });
232
+ if (previousFilePath !== filePath) {
233
+ await deleteFileChunks(context, previousFilePath);
234
+ }
235
+ }
236
+ async function writeDocumentContent(context, config, documentId, title, text, meta, options) {
200
237
  if (text.length > MAX_TEXT_LENGTH) {
201
238
  throw INVALID_ARGUMENT.create({
202
239
  detail: `Upload text exceeds ${MAX_TEXT_LENGTH / 1024 / 1024} MB limit`,
@@ -206,8 +243,7 @@ async function ingestDocument(context, config, title, text, meta) {
206
243
  if (chunkTexts.length === 0) {
207
244
  throw INVALID_ARGUMENT.create({ detail: "Upload contains no extractable text" });
208
245
  }
209
- const documentId = dntShim.crypto.randomUUID();
210
- const filePath = buildDocumentFilePath(documentId, meta?.type);
246
+ const filePath = options?.filePath ?? buildDocumentFilePath(documentId, meta?.type);
211
247
  const embedder = createEmbedder(config);
212
248
  const vectors = await embedder.embedMany(chunkTexts);
213
249
  const dimension = toSupportedDimension(vectors[0]?.length ?? 0);
@@ -243,7 +279,6 @@ async function ingestDocument(context, config, title, text, meta) {
243
279
  type: meta?.type ?? "",
244
280
  metadata: { filePath },
245
281
  });
246
- return documentId;
247
282
  }
248
283
  function createEmbedder(config) {
249
284
  return embedding({
@@ -340,6 +375,10 @@ export function createVeryfrontCloudRagStore(config) {
340
375
  const context = getCloudStoreContext(config);
341
376
  return ingestDocument(context, config, title, text, meta);
342
377
  },
378
+ async refreshDocument(id, text, meta) {
379
+ const context = getCloudStoreContext(config);
380
+ await refreshCloudDocument(context, config, id, text, meta);
381
+ },
343
382
  async search(query, options) {
344
383
  if (!query.trim())
345
384
  return [];
@@ -376,7 +415,8 @@ export function createVeryfrontCloudRagStore(config) {
376
415
  },
377
416
  async listDocuments() {
378
417
  const context = getCloudStoreContext(config);
379
- return listRagDocuments(context);
418
+ const documents = await listRagDocuments(context);
419
+ return documents.map(toPublicRagDocumentMeta);
380
420
  },
381
421
  async removeDocument(id) {
382
422
  const context = getCloudStoreContext(config);
@@ -387,7 +427,7 @@ export function createVeryfrontCloudRagStore(config) {
387
427
  await deleteRagDocument(context, id);
388
428
  // Best-effort cleanup of file chunks
389
429
  if (target) {
390
- const filePath = buildDocumentFilePath(id, target.type);
430
+ const filePath = target.filePath ?? buildDocumentFilePath(id, target.type);
391
431
  try {
392
432
  await deleteFileChunks(context, filePath);
393
433
  }
@@ -9,6 +9,13 @@ export interface InjectHTMLContentOptions {
9
9
  projectDir?: string;
10
10
  /** Whether the page has 'use client' directive */
11
11
  isClientPage?: boolean;
12
+ /**
13
+ * Route params from the initial match, seeded into the 'use client' hydration
14
+ * payload so full-HTML-document client pages hydrate with their params
15
+ * instead of an empty object (issue #2741). Catch-all arrays are preserved;
16
+ * the client runtime joins them (issue #2742).
17
+ */
18
+ params?: Record<string, string | string[]>;
12
19
  /** Whether page is embedded in Studio iframe */
13
20
  studioEmbed?: boolean;
14
21
  /** Project ID for Studio communication */
@@ -1 +1 @@
1
- {"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAwGR"}
1
+ {"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAmB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CA6GR"}
@@ -2,6 +2,7 @@ import { resolveRelativePath } from "../modules/react-loader/path-resolver.js";
2
2
  import { determineClientModuleStrategy } from "../rendering/rsc/client-module-strategy.js";
3
3
  import { generateLinkTags, generateMetaTags, generateScriptTags, generateStyleTags, } from "./tag-generators.js";
4
4
  import { buildNonceAttribute } from "./html-escape.js";
5
+ import { jsonForInlineScript } from "../security/client/html-sanitizer.js";
5
6
  import { getDevScripts, getDevStyles, getPreviewStylesheetLink, getProdScripts, getStudioScripts, } from "./dev-scripts.js";
6
7
  function toProjectRelativePath(absolutePath, projectDir) {
7
8
  const normalizedPath = absolutePath.replace(/\\/g, "/");
@@ -49,10 +50,15 @@ export function injectHTMLContent(template, content, metadata, options) {
49
50
  const hasBodyClose = /<\/body>/i.test(html);
50
51
  // Inject hydration data for 'use client' pages (before scripts, so client.js can find it)
51
52
  if (options.pagePath && options.isClientPage && hasBodyClose) {
52
- const hydrationData = JSON.stringify({
53
+ // Serialize with jsonForInlineScript, not raw JSON.stringify: route params
54
+ // (and slug) are URL-derived and decoded, so a segment like `%3C/script%3E`
55
+ // would otherwise break out of the <script> tag (reflected XSS). This escapes
56
+ // `<`, `>`, `&`, and line separators, matching the main shell hydration path.
57
+ const hydrationData = jsonForInlineScript({
53
58
  pagePath: toProjectRelativePath(options.pagePath, options.projectDir),
54
59
  slug: options.slug,
55
60
  isClientPage: true,
61
+ params: options.params ?? {},
56
62
  clientModuleStrategy: determineClientModuleStrategy({
57
63
  isLocalProject: options.isLocalProject ?? options.mode === "development",
58
64
  environment: options.environment,
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/renderer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,cAwN7B,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/renderer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,cA4N7B,CAAC"}
@@ -112,7 +112,11 @@ export const getRendererScript = () => `
112
112
  return;
113
113
  }
114
114
 
115
- const pageProps = { ...(data.props || {}), params: data.params || {} };
115
+ // Normalize catch-all params (arrays -> joined strings) so the hydrated
116
+ // props and page context match the server render. normalizeRouteParams
117
+ // is defined in router.ts, which loads first (issue #2742).
118
+ const normalizedParams = normalizeRouteParams(data.params);
119
+ const pageProps = { ...(data.props || {}), params: normalizedParams };
116
120
  let tree = React.createElement(PageComponent, pageProps);
117
121
 
118
122
  const layouts = data.layouts;
@@ -143,7 +147,7 @@ export const getRendererScript = () => `
143
147
  const pageContext = {
144
148
  slug: data.slug || '',
145
149
  path: data.pagePath || resolvedPathname,
146
- params: data.params || {},
150
+ params: normalizedParams,
147
151
  query: Object.fromEntries(new URLSearchParams(window.location.search)),
148
152
  frontmatter: data.frontmatter || {},
149
153
  headings,
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/router.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,cAklC3B,CAAC"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/router.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,cA2nC3B,CAAC"}
@@ -604,13 +604,18 @@ export const getRouterScript = () => `
604
604
  window.history.pushState({ pageData, scrollY: 0 }, '', href);
605
605
  }
606
606
 
607
- perfStart('nav:render:' + href);
608
- await renderPageFromData(pageData, targetPath);
609
- perfEnd('nav:render:' + href);
610
-
607
+ // Update the shared router snapshot BEFORE rendering. RouterProvider
608
+ // reads router.params during render, so mutating after renderPageFromData
609
+ // would leave the new page's first render with the previous route's
610
+ // params (issue #2741). pathname/query move up for the same reason.
611
611
  currentPath = targetPath;
612
612
  window.__veryfrontRouter.pathname = targetPath;
613
613
  window.__veryfrontRouter.query = Object.fromEntries(new URLSearchParams(window.location.search));
614
+ window.__veryfrontRouter.params = normalizeRouteParams(pageData.params);
615
+
616
+ perfStart('nav:render:' + href);
617
+ await renderPageFromData(pageData, targetPath);
618
+ perfEnd('nav:render:' + href);
614
619
 
615
620
  if (restoreScroll) {
616
621
  restoreScrollPosition(targetPath);
@@ -708,9 +713,15 @@ export const getRouterScript = () => `
708
713
  }
709
714
  }
710
715
 
716
+ // Normalize catch-all params (arrays -> joined strings) so page props and
717
+ // page context match the server render exactly. SSR emits joined strings
718
+ // via flattenRouteParams; without this the client would hand raw arrays to
719
+ // props and usePageContext() after navigation (issue #2742).
720
+ const normalizedParams = normalizeRouteParams(pageData.params);
721
+
711
722
  let tree = React.createElement(PageComponent, {
712
723
  ...pageData.props,
713
- params: pageData.params
724
+ params: normalizedParams
714
725
  });
715
726
 
716
727
  if (pageData.layouts?.length) {
@@ -733,7 +744,7 @@ export const getRouterScript = () => `
733
744
  const pageContext = {
734
745
  slug: pageData.slug || '',
735
746
  path: pageData.pagePath || targetPath,
736
- params: pageData.params || {},
747
+ params: normalizedParams,
737
748
  query: Object.fromEntries(new URLSearchParams(window.location.search)),
738
749
  frontmatter: pageData.frontmatter || {},
739
750
  headings: headingsArray,
@@ -951,6 +962,22 @@ export const getRouterScript = () => `
951
962
  }, IDLE_PREFETCH_DELAY_MS);
952
963
  }
953
964
 
965
+ // ============================================
966
+ // Route params normalization
967
+ // ============================================
968
+ // Catch-all segments arrive as arrays and are joined so no path info is
969
+ // lost, matching the server flattenRouteParams + RSC hydration normalizer.
970
+ function normalizeRouteParams(raw) {
971
+ const out = {};
972
+ if (!raw) return out;
973
+ for (const key in raw) {
974
+ const value = raw[key];
975
+ if (value === undefined) continue;
976
+ out[key] = Array.isArray(value) ? value.join('/') : value;
977
+ }
978
+ return out;
979
+ }
980
+
954
981
  // ============================================
955
982
  // Router object
956
983
  // ============================================
@@ -974,7 +1001,17 @@ export const getRouterScript = () => `
974
1001
  },
975
1002
  pathname: window.location.pathname,
976
1003
  query: Object.fromEntries(new URLSearchParams(window.location.search)),
977
- params: {},
1004
+ // Seed route params from the hydration data (issue #2741). Catch-all
1005
+ // segments arrive as arrays and are joined so no path info is lost.
1006
+ params: (function () {
1007
+ try {
1008
+ const el = document.getElementById('veryfront-hydration-data');
1009
+ const raw = (JSON.parse(el && el.textContent ? el.textContent : '{}') || {}).params || {};
1010
+ return normalizeRouteParams(raw);
1011
+ } catch (_) {
1012
+ return {};
1013
+ }
1014
+ })(),
978
1015
  isPreview: false,
979
1016
  isMounted: true,
980
1017
  navigate: (path) => navigateSPA(path, true),
@@ -999,10 +1036,14 @@ export const getRouterScript = () => `
999
1036
 
1000
1037
  showNavigationProgress();
1001
1038
  try {
1002
- await renderPageFromData(e.state.pageData, path);
1039
+ // Update the router snapshot before rendering so RouterProvider reads
1040
+ // this route's params, not the previous route's (issue #2741).
1003
1041
  currentPath = path;
1004
1042
  window.__veryfrontRouter.pathname = path;
1005
1043
  window.__veryfrontRouter.query = Object.fromEntries(new URLSearchParams(window.location.search));
1044
+ window.__veryfrontRouter.params = normalizeRouteParams(e.state.pageData.params);
1045
+
1046
+ await renderPageFromData(e.state.pageData, path);
1006
1047
 
1007
1048
  restoreScrollPosition(path);
1008
1049
  hideNavigationProgress();
@@ -1 +1 @@
1
- {"version":3,"file":"layout-applicator.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/layouts/layout-applicator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,YAAY,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAKzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAiBxE,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,oBAAoB,CAAC;IAClC,gBAAgB,EAAE,aAAa,CAAC;IAChC,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,UAAU,CAAC,CAAM;IACzB,OAAO,CAAC,MAAM,CAAC,CAAoC;IACnD,OAAO,CAAC,WAAW,CAAC,CAA0B;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAqD;IACtE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAAC,CAAyB;IACpD,OAAO,CAAC,+BAA+B,CAAC,CAGrC;gBAES,OAAO,EAAE,wBAAwB;IAiBvC,YAAY,CAChB,WAAW,EAAE,YAAY,CAAC,YAAY,EACtC,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,SAAS,GAAG,SAAS,EACnC,aAAa,EAAE,UAAU,EAAE,EAC3B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC;YA+FvB,gBAAgB;YAuDhB,sBAAsB;YAWtB,8BAA8B;YA4D9B,oBAAoB;YAqDpB,mBAAmB;YAuCnB,0BAA0B;CAgEzC"}
1
+ {"version":3,"file":"layout-applicator.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/layouts/layout-applicator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,YAAY,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAKzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAiBxE,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,WAAW,EAAE,oBAAoB,CAAC;IAClC,gBAAgB,EAAE,aAAa,CAAC;IAChC,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,UAAU,CAAC,CAAM;IACzB,OAAO,CAAC,MAAM,CAAC,CAAoC;IACnD,OAAO,CAAC,WAAW,CAAC,CAA0B;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAqD;IACtE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAAC,CAAyB;IACpD,OAAO,CAAC,+BAA+B,CAAC,CAGrC;gBAES,OAAO,EAAE,wBAAwB;IAiBvC,YAAY,CAChB,WAAW,EAAE,YAAY,CAAC,YAAY,EACtC,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,SAAS,GAAG,SAAS,EACnC,aAAa,EAAE,UAAU,EAAE,EAC3B,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACnD,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC;YAyFvB,gBAAgB;YAuDhB,sBAAsB;YAWtB,8BAA8B;YA4D9B,oBAAoB;YAqDpB,mBAAmB;YAuCnB,0BAA0B;CAgEzC"}
@@ -1,5 +1,6 @@
1
1
  import { dirname, join } from "../../platform/compat/path/index.js";
2
2
  import { rendererLogger } from "../../utils/index.js";
3
+ import { flattenRouteParams } from "../../routing/index.js";
3
4
  import { withSpan } from "../../observability/tracing/otlp-setup.js";
4
5
  import { SpanNames } from "../../observability/tracing/span-names.js";
5
6
  import { resolve as resolveContract } from "../../extensions/contracts.js";
@@ -66,11 +67,7 @@ export class LayoutApplicator {
66
67
  }
67
68
  const React = await getProjectReact();
68
69
  const headingsArray = this.headings ?? [];
69
- const flatParams = this.params
70
- ? Object.fromEntries(Object.entries(this.params)
71
- .map(([key, value]) => [key, Array.isArray(value) ? value[0] : value])
72
- .filter((entry) => entry[1] !== undefined))
73
- : {};
70
+ const flatParams = flattenRouteParams(this.params);
74
71
  const query = this.requestUrl ? Object.fromEntries(this.requestUrl.searchParams) : {};
75
72
  const pageContext = {
76
73
  slug: pageInfo.entity.slug || "",
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAClF,YAAY,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA+FlF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BjE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAqEZ,sBAAsB;YAuDtB,4BAA4B;YAiB5B,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAoF9B;;;;OAIG;YACW,gBAAgB;CAc/B"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAClF,YAAY,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA+FlF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BjE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAqEZ,sBAAsB;YAwDtB,4BAA4B;YAiB5B,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAoF9B;;;;OAIG;YACW,gBAAgB;CAc/B"}
@@ -163,6 +163,7 @@ export class HTMLGenerator {
163
163
  pagePath,
164
164
  projectDir: this.config.projectDir,
165
165
  isClientPage,
166
+ params: context.options?.params,
166
167
  environment: context.options?.environment,
167
168
  isLocalProject: this.config.mode === "development",
168
169
  nonce: context.options?.nonce,
@@ -1 +1 @@
1
- {"version":3,"file":"page-rendering.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/page-rendering.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAa,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQrG,UAAU,aAAa;IACrB,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,UAAU,sBAAsB;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,0BAA0B;IAClC,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAInE;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,UAAU,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACA,OAAO,CAAC,sBAAsB,CAAC,CA4CjC;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,aAAa,EAC/B,WAAW,EAAE,CACX,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,KACd,OAAO,CAAC,SAAS,CAAC,EACvB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,aAAa,CAAC,CAyHxB"}
1
+ {"version":3,"file":"page-rendering.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/page-rendering.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,YAAY,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAa,UAAU,EAAE,MAAM,mBAAmB,CAAC;AASrG,UAAU,aAAa;IACrB,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,UAAU,sBAAsB;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,0BAA0B;IAClC,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAInE;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,UAAU,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACA,OAAO,CAAC,sBAAsB,CAAC,CA4CjC;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,aAAa,EAC/B,WAAW,EAAE,CACX,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,QAAQ,CAAC,EAAE,MAAM,KACd,OAAO,CAAC,SAAS,CAAC,EACvB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,aAAa,CAAC,CAmHxB"}
@@ -3,6 +3,7 @@ import { RENDER_ERROR } from "../errors/error-registry.js";
3
3
  import { mdxRenderer } from "../transforms/mdx/index.js";
4
4
  import { clearMdxEsmCacheNamespace } from "../transforms/mdx/esm-module-loader/index.js";
5
5
  import { getProjectReact } from "../react/index.js";
6
+ import { flattenRouteParams } from "../routing/index.js";
6
7
  import { compileContent } from "../transforms/mdx/compiler/index.js";
7
8
  import { ensureError, getErrorMessage } from "../errors/veryfront-error.js";
8
9
  import { withSpan } from "../observability/tracing/otlp-setup.js";
@@ -77,11 +78,7 @@ export function handleMDXPage(pageInfo, slug, projectDir, mergedComponents, _com
77
78
  }
78
79
  if (typeof mod.generateMetadata === "function") {
79
80
  try {
80
- const params = options?.params
81
- ? Object.fromEntries(Object.entries(options.params)
82
- .map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])
83
- .filter((entry) => entry[1] !== undefined))
84
- : {};
81
+ const params = flattenRouteParams(options?.params);
85
82
  const query = options?.url ? Object.fromEntries(options.url.searchParams) : {};
86
83
  const gen = await mod.generateMetadata({
87
84
  params,
@@ -1 +1 @@
1
- {"version":3,"file":"script-page-handling.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/script-page-handling.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EAGV,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAenE,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqHD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,YAAY,CAAC,CAiDvB"}
1
+ {"version":3,"file":"script-page-handling.d.ts","sourceRoot":"","sources":["../../../src/src/rendering/script-page-handling.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EAGV,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAenE,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+GD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,YAAY,CAAC,CAiDvB"}
@@ -9,6 +9,7 @@ import { rewriteNpmImports } from "../transforms/npm-import-rewrites.js";
9
9
  import { dirname, join } from "../platform/compat/path/index.js";
10
10
  import { cwd } from "../platform/compat/process.js";
11
11
  import { RENDER_ERROR } from "../errors/error-registry.js";
12
+ import { flattenRouteParams } from "../routing/index.js";
12
13
  import { createError, toError } from "../errors/veryfront-error.js";
13
14
  import { computeHash } from "./utils/index.js";
14
15
  import { wrapInHTMLShell } from "../html/index.js";
@@ -75,11 +76,7 @@ function extractHtmlAndMetadata(output) {
75
76
  }));
76
77
  }
77
78
  function buildPageContext(pageInfo, slug, params, url) {
78
- const flatParams = params
79
- ? Object.fromEntries(Object.entries(params)
80
- .map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])
81
- .filter((entry) => entry[1] !== undefined))
82
- : {};
79
+ const flatParams = flattenRouteParams(params);
83
80
  return {
84
81
  params: flatParams,
85
82
  query: url ? Object.fromEntries(url.searchParams) : {},
@@ -16,5 +16,9 @@ export interface APIContext {
16
16
  fs: FileSystemAdapter;
17
17
  }
18
18
  export declare function createContext(request: Request, match: RouteMatch, fs: FileSystemAdapter): APIContext;
19
+ /**
20
+ * @deprecated Use {@link flattenRouteParams} directly. Kept as a thin alias so
21
+ * the routing barrel exposes a single flattener implementation (issue #2742).
22
+ */
19
23
  export declare function normalizeParams(params: Record<string, string | string[]>): Record<string, string>;
20
24
  //# sourceMappingURL=context-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACvD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACtD,EAAE,EAAE,iBAAiB,CAAC;CACvB;AAgBD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,iBAAiB,GACpB,UAAU,CAmBZ;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB"}
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../../../../src/src/routing/api/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACvD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC;IACtD,EAAE,EAAE,iBAAiB,CAAC;CACvB;AAgBD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,iBAAiB,GACpB,UAAU,CAmBZ;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
@@ -1,4 +1,5 @@
1
1
  import { parseCookies } from "../../utils/cookie-utils.js";
2
+ import { flattenRouteParams } from "../flatten-route-params.js";
2
3
  export { parseCookies };
3
4
  function createResponse(body, contentType, init) {
4
5
  return new Response(body, {
@@ -26,10 +27,10 @@ export function createContext(request, match, fs) {
26
27
  fs,
27
28
  };
28
29
  }
30
+ /**
31
+ * @deprecated Use {@link flattenRouteParams} directly. Kept as a thin alias so
32
+ * the routing barrel exposes a single flattener implementation (issue #2742).
33
+ */
29
34
  export function normalizeParams(params) {
30
- const out = {};
31
- for (const [key, value] of Object.entries(params)) {
32
- out[key] = Array.isArray(value) ? value.join("/") : value;
33
- }
34
- return out;
35
+ return flattenRouteParams(params);
35
36
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Flattens matched route params (which may be arrays for catch-all `[...slug]`
3
+ * segments) into the `Record<string, string>` shape the router value exposes.
4
+ *
5
+ * Catch-all segments are **joined with `/`** so no path information is lost —
6
+ * `/docs/guides/intro` -> `{ slug: "guides/intro" }`, not `{ slug: "guides" }`.
7
+ * This matches the client SPA normalizer and the RSC hydration normalizer, so
8
+ * server and client agree.
9
+ */
10
+ export declare function flattenRouteParams(params?: Record<string, string | string[]>): Record<string, string>;
11
+ //# sourceMappingURL=flatten-route-params.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten-route-params.d.ts","sourceRoot":"","sources":["../../../src/src/routing/flatten-route-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Flattens matched route params (which may be arrays for catch-all `[...slug]`
3
+ * segments) into the `Record<string, string>` shape the router value exposes.
4
+ *
5
+ * Catch-all segments are **joined with `/`** so no path information is lost —
6
+ * `/docs/guides/intro` -> `{ slug: "guides/intro" }`, not `{ slug: "guides" }`.
7
+ * This matches the client SPA normalizer and the RSC hydration normalizer, so
8
+ * server and client agree.
9
+ */
10
+ export function flattenRouteParams(params) {
11
+ if (!params)
12
+ return {};
13
+ const flat = {};
14
+ for (const [key, value] of Object.entries(params)) {
15
+ if (value === undefined)
16
+ continue;
17
+ flat[key] = Array.isArray(value) ? value.join("/") : value;
18
+ }
19
+ return flat;
20
+ }
@@ -5,6 +5,7 @@
5
5
  * @module routing
6
6
  */
7
7
  export type { Route, RouteMatch } from "./matchers/index.js";
8
+ export { flattenRouteParams } from "./flatten-route-params.js";
8
9
  export { getSpecificityScore, matchRoute, normalizePath, PageRouteMatcher, parseRoute, } from "./matchers/index.js";
9
10
  export type { PathCandidates, RouteParams } from "./slug-mapper/index.js";
10
11
  export { extractParams, getPathCandidates, getSlugFromPath, getSupportedExtensions, isDynamicRoute, matchesPattern, normalizeSlug, pathToSlug, slugToPath, } from "./slug-mapper/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,GACX,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,UAAU,GACX,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EACL,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACnB,IAAI,EACJ,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,UAAU,GACX,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,UAAU,GACX,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,yBAAyB,EACzB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EACL,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACnB,IAAI,EACJ,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,gBAAgB,CAAC"}
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * @module routing
6
6
  */
7
+ export { flattenRouteParams } from "./flatten-route-params.js";
7
8
  export { getSpecificityScore, matchRoute, normalizePath, PageRouteMatcher, parseRoute, } from "./matchers/index.js";
8
9
  export { extractParams, getPathCandidates, getSlugFromPath, getSupportedExtensions, isDynamicRoute, matchesPattern, normalizeSlug, pathToSlug, slugToPath, } from "./slug-mapper/index.js";
9
10
  export { extractPageDataFromScript, NavigationHandlers, PageLoader, PageTransition, ViewportPrefetch, } from "./client/index.js";
@@ -1,3 +1,3 @@
1
1
  /** Shared version value. */
2
- export declare const VERSION = "0.1.993";
2
+ export declare const VERSION = "0.1.995";
3
3
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,4 +1,4 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
3
  /** Shared version value. */
4
- export const VERSION = "0.1.993";
4
+ export const VERSION = "0.1.995";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.993",
3
+ "version": "0.1.995",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",