@markless/router 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,456 @@
1
+ import { basename, extname, join, normalize, relative } from "pathe";
2
+ import { joinURL, withLeadingSlash, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
3
+ const MIDDLEWARE_DIR = "middleware";
4
+ const HTTP_METHODS = /* @__PURE__ */ new Set([
5
+ "connect",
6
+ "delete",
7
+ "get",
8
+ "head",
9
+ "options",
10
+ "patch",
11
+ "post",
12
+ "put",
13
+ "trace"
14
+ ]);
15
+ function parseRequestFile(fileId, sourceText) {
16
+ const file = normalizeRequestFileId(fileId);
17
+ const apiFile = apiRelativeFile(file);
18
+ if (apiFile) return parseApiRequestFile(file, apiFile, sourceText);
19
+ if (middlewareRelativeFile(file)) return parseMiddlewareRequestFile(file, sourceText);
20
+ return {
21
+ diagnostics: [],
22
+ file,
23
+ kind: "none"
24
+ };
25
+ }
26
+ function normalizeRequestFileId(fileId) {
27
+ return withoutLeadingSlash(normalize(fileId));
28
+ }
29
+ function transformRequestFileSource(fileId, sourceText) {
30
+ const requestFile = parseRequestFile(fileId, sourceText);
31
+ if (requestFile.kind === "none" || requestFile.diagnostics.length > 0 || !requestFile.defaultExport) return;
32
+ const handler = localizeDefaultExport(sourceText);
33
+ if (!handler) return;
34
+ return {
35
+ code: requestFileWrapperSource(requestFile, handler.code, handler.name),
36
+ file: requestFile.file,
37
+ kind: requestFile.kind
38
+ };
39
+ }
40
+ function parseApiRequestFile(file, apiFile, sourceText) {
41
+ const defaultExport = findDefaultFunctionExport(sourceText);
42
+ const cache = parseCacheMetadata(sourceText);
43
+ const diagnostics = [
44
+ ...missingDefaultFunctionDiagnostics("api", defaultExport),
45
+ ...httpMethodExportDiagnostics(sourceText),
46
+ ...cacheMetadataDiagnostics(sourceText, cache)
47
+ ];
48
+ return {
49
+ ...cache ? { cache } : {},
50
+ ...defaultExport ? { defaultExport } : {},
51
+ diagnostics,
52
+ file,
53
+ kind: "api",
54
+ ...apiRouteFromFile(apiFile)
55
+ };
56
+ }
57
+ function parseMiddlewareRequestFile(file, sourceText) {
58
+ const defaultExport = findDefaultFunctionExport(sourceText);
59
+ const diagnostics = missingDefaultFunctionDiagnostics("middleware", defaultExport);
60
+ return {
61
+ ...defaultExport ? { defaultExport } : {},
62
+ diagnostics,
63
+ file,
64
+ kind: "middleware"
65
+ };
66
+ }
67
+ function apiRouteFromFile(apiFile) {
68
+ const withoutExtension = apiFile.slice(0, -3);
69
+ const rawSegments = normalize(join(withoutExtension)).split("/");
70
+ const finalSegment = rawSegments.at(-1);
71
+ const method = methodSuffix(finalSegment);
72
+ if (method !== "all") rawSegments[rawSegments.length - 1] = finalSegment.slice(0, -(method.length + 1));
73
+ if (rawSegments.at(-1) === "index") rawSegments.pop();
74
+ const normalizedSegments = rawSegments.filter(Boolean).map(normalizeRouteSegment);
75
+ const pathnameSegments = normalizedSegments.map((segment) => segment.pathname);
76
+ const patternSegments = normalizedSegments.map((segment) => segment.pattern);
77
+ return {
78
+ method,
79
+ route: {
80
+ params: normalizedSegments.flatMap((segment) => segment.params),
81
+ pathname: requestPathname(["api", ...pathnameSegments]),
82
+ pattern: requestPathname(["api", ...patternSegments])
83
+ }
84
+ };
85
+ }
86
+ function normalizeRouteSegment(segment) {
87
+ const catchAll = segment.match(/^\[\.\.\.([A-Za-z_$][\w$]*)\]$/);
88
+ if (catchAll) return {
89
+ params: [{
90
+ kind: "catch-all",
91
+ name: catchAll[1]
92
+ }],
93
+ pathname: "**",
94
+ pattern: `[...${catchAll[1]}]`
95
+ };
96
+ const dynamic = segment.match(/^\[([A-Za-z_$][\w$]*)\]$/);
97
+ if (dynamic) return {
98
+ params: [{
99
+ kind: "dynamic",
100
+ name: dynamic[1]
101
+ }],
102
+ pathname: `:${dynamic[1]}`,
103
+ pattern: `[${dynamic[1]}]`
104
+ };
105
+ return {
106
+ params: [],
107
+ pathname: segment,
108
+ pattern: segment
109
+ };
110
+ }
111
+ function requestPathname(segments) {
112
+ if (segments.length === 0) return "/";
113
+ const [base, ...rest] = segments;
114
+ return withLeadingSlash(joinURL(base, ...rest));
115
+ }
116
+ function methodSuffix(finalSegment) {
117
+ const suffix = finalSegment.split(".").at(-1);
118
+ return suffix && HTTP_METHODS.has(suffix) ? suffix : "all";
119
+ }
120
+ function findDefaultFunctionExport(sourceText) {
121
+ const directFunction = sourceText.match(/\bexport\s+default\s+(?:async\s+)?function(?:\s+[A-Za-z_$][\w$]*)?\s*\(\s*([A-Za-z_$][\w$]*)?/);
122
+ if (directFunction) return {
123
+ kind: "function",
124
+ parameterName: directFunction[1]
125
+ };
126
+ const directArrow = sourceText.match(/\bexport\s+default\s+(?:async\s+)?(?:\(\s*([A-Za-z_$][\w$]*)?\s*\)|([A-Za-z_$][\w$]*))\s*=>/);
127
+ if (directArrow) return {
128
+ kind: "function",
129
+ parameterName: directArrow[1] ?? directArrow[2]
130
+ };
131
+ const defaultIdentifier = sourceText.match(/\bexport\s+default\s+([A-Za-z_$][\w$]*)\s*;/)?.[1];
132
+ if (!defaultIdentifier) return;
133
+ const escapedIdentifier = escapeRegExp(defaultIdentifier);
134
+ const constArrow = sourceText.match(new RegExp(`\\bconst\\s+${escapedIdentifier}\\s*=\\s*(?:async\\s+)?(?:\\(\\s*([A-Za-z_$][\\w$]*)?\\s*\\)|([A-Za-z_$][\\w$]*))\\s*=>`));
135
+ if (constArrow) return {
136
+ kind: "function",
137
+ parameterName: constArrow[1] ?? constArrow[2]
138
+ };
139
+ const functionDeclaration = sourceText.match(new RegExp(`\\b(?:async\\s+)?function\\s+${escapedIdentifier}\\s*\\(\\s*([A-Za-z_$][\\w$]*)?`));
140
+ if (functionDeclaration) return {
141
+ kind: "function",
142
+ parameterName: functionDeclaration[1]
143
+ };
144
+ }
145
+ function parseCacheMetadata(sourceText) {
146
+ const objectLiteral = sourceText.match(/\bexport\s+const\s+cache\s*=\s*(\{[\s\S]*?\})\s*;?/)?.[1];
147
+ if (!objectLiteral) return;
148
+ const maxAge = objectLiteral.match(/^\{\s*maxAge\s*:\s*(\d+(?:\.\d+)?)\s*,?\s*\}$/)?.[1];
149
+ return maxAge ? { maxAge: Number(maxAge) } : void 0;
150
+ }
151
+ function missingDefaultFunctionDiagnostics(kind, defaultExport) {
152
+ if (defaultExport) return [];
153
+ return [{
154
+ code: "missing-default-function",
155
+ message: kind === "api" ? "API files must default export a function." : "Middleware files must default export a function."
156
+ }];
157
+ }
158
+ function httpMethodExportDiagnostics(sourceText) {
159
+ const exportedMethods = /* @__PURE__ */ new Set();
160
+ for (const pattern of [
161
+ /\bexport\s+(?:async\s+)?function\s+([A-Z]+)\b/g,
162
+ /\bexport\s+const\s+([A-Z]+)\b/g,
163
+ /\bexport\s*\{([^}]+)\}/g
164
+ ]) for (const match of sourceText.matchAll(pattern)) {
165
+ const exportClause = match[1];
166
+ if (!exportClause) continue;
167
+ if (exportClause.includes(",")) {
168
+ for (const exportName of exportClause.split(",")) addHttpMethodExport(exportedMethods, exportName);
169
+ continue;
170
+ }
171
+ addHttpMethodExport(exportedMethods, exportClause);
172
+ }
173
+ return Array.from(exportedMethods).toSorted().map((method) => ({
174
+ code: "http-method-export",
175
+ message: `Do not export ${method}; the HTTP method comes from the filename.`
176
+ }));
177
+ }
178
+ function addHttpMethodExport(methods, exportName) {
179
+ const method = exportName.trim().split(/\s+as\s+/i).at(-1)?.trim();
180
+ if (method && HTTP_METHODS.has(method.toLowerCase())) methods.add(method.toUpperCase());
181
+ }
182
+ function cacheMetadataDiagnostics(sourceText, cache) {
183
+ if (!/\bexport\s+const\s+cache\b/.test(sourceText) || cache) return [];
184
+ return [{
185
+ code: "invalid-cache-metadata",
186
+ message: "Use export const cache for endpoint cache metadata."
187
+ }];
188
+ }
189
+ function apiRelativeFile(file) {
190
+ if (!isRequestModuleFile(file) || file === "api" || !file.startsWith(`api/`)) return;
191
+ return relative("api", file);
192
+ }
193
+ function middlewareRelativeFile(file) {
194
+ if (!isRequestModuleFile(file) || file === MIDDLEWARE_DIR || !file.startsWith(`${MIDDLEWARE_DIR}/`)) return;
195
+ return relative(MIDDLEWARE_DIR, file);
196
+ }
197
+ function localizeDefaultExport(sourceText) {
198
+ const defaultIdentifierMatch = sourceText.match(/\bexport\s+default\s+([A-Za-z_$][\w$]*)\s*;/);
199
+ if (defaultIdentifierMatch) return {
200
+ code: sourceText.replace(defaultIdentifierMatch[0], ""),
201
+ name: defaultIdentifierMatch[1]
202
+ };
203
+ const directDefaultMatch = sourceText.match(/\bexport\s+default\b/);
204
+ if (!directDefaultMatch || directDefaultMatch.index === void 0) return;
205
+ return {
206
+ code: `${sourceText.slice(0, directDefaultMatch.index)}const __markless_request_handler__ =${sourceText.slice(directDefaultMatch.index + directDefaultMatch[0].length)}`,
207
+ name: "__markless_request_handler__"
208
+ };
209
+ }
210
+ function requestFileWrapperSource(requestFile, sourceText, handlerName) {
211
+ const defineImport = requestFile.kind === "api" && requestFile.cache ? "import { defineCachedHandler as __markless_define_handler__ } from \"nitro/cache\";" : "import { defineHandler as __markless_define_handler__ } from \"nitro\";";
212
+ const wrappedHandler = `(event) =>
213
+ ${handlerName}(__markless_create_http_context__(event))`;
214
+ const wrappedDefault = requestFile.kind === "api" && requestFile.cache ? `__markless_define_handler__(${wrappedHandler}, cache)` : `__markless_define_handler__(${wrappedHandler})`;
215
+ return `${defineImport}
216
+ import { __marklessCreateHttpContext as __markless_create_http_context__ } from "@markless/router";
217
+
218
+ ${sourceText.trimEnd()}
219
+
220
+ export default ${wrappedDefault};
221
+ `;
222
+ }
223
+ function isRequestModuleFile(file) {
224
+ return extname(file) === ".ts" && basename(file) !== ".ts";
225
+ }
226
+ function escapeRegExp(value) {
227
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
228
+ }
229
+ //#endregion
230
+ //#region src/route-manifest.ts
231
+ const PAGES_DIR = "pages";
232
+ const PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".tsrx", ".mdx"]);
233
+ function buildRouteManifestFromFileIds(fileIds) {
234
+ const pages = unique(fileIds.map(normalizeRouteFileId)).filter(isPageModuleFile).toSorted(compareCodeUnits).map(normalizePage);
235
+ const routes = pages.flatMap((page) => page.kind === "route" ? [page.route] : []);
236
+ assertNoRouteConflicts(routes);
237
+ const statusPages = {};
238
+ for (const page of pages) if (page.kind === "status") statusPages[page.status] = page.file;
239
+ return {
240
+ routes: routes.map(toPublicRoute).toSorted(compareRoutes),
241
+ statusPages
242
+ };
243
+ }
244
+ function normalizeRequestPathname(pathname) {
245
+ const normalizedPathname = withoutTrailingSlash(withLeadingSlash(pathname));
246
+ return normalizedPathname === "" ? "/" : normalizedPathname;
247
+ }
248
+ function normalizeRouteFileId(fileId) {
249
+ return withoutLeadingSlash(normalize(fileId));
250
+ }
251
+ function matchRouteManifest(pathname, manifest) {
252
+ const requestPathname = normalizeRequestPathname(pathname);
253
+ for (const route of manifest.routes) {
254
+ const params = matchRoutePathname(route, requestPathname);
255
+ if (params) return {
256
+ route,
257
+ params
258
+ };
259
+ }
260
+ }
261
+ function isPageModuleFile(file) {
262
+ const pageFile = pageRelativeFile(file);
263
+ return pageFile !== void 0 && PAGE_EXTENSIONS.has(extname(pageFile));
264
+ }
265
+ function normalizePage(file) {
266
+ const relativeFile = file;
267
+ const pageFile = pageRelativeFile(file);
268
+ const extension = extname(pageFile);
269
+ const withoutExtension = pageFile.slice(0, -extension.length);
270
+ const routeFile = normalize(join(withoutExtension));
271
+ const rawSegments = routeFile === "." ? [] : routeFile.split("/");
272
+ if (rawSegments.length === 1 && rawSegments[0] === "404") return {
273
+ kind: "status",
274
+ status: "notFound",
275
+ file: relativeFile
276
+ };
277
+ if (rawSegments.length === 1 && rawSegments[0] === "500") return {
278
+ kind: "status",
279
+ status: "error",
280
+ file: relativeFile
281
+ };
282
+ if (rawSegments.length > 1 && ["404", "500"].includes(rawSegments.at(-1))) throw new Error(`Nested status pages are not supported in v0: ${relativeFile}`);
283
+ if (rawSegments.at(-1) === "index") rawSegments.pop();
284
+ const pattern = routePathname(rawSegments);
285
+ const segments = rawSegments.map((segment, index) => normalizeSegment(segment, index, rawSegments, relativeFile));
286
+ const pathnameSegments = segments.map((segment) => segment.pathname);
287
+ const identitySegments = segments.map((segment) => segment.identity);
288
+ const params = segments.flatMap((segment) => segment.params);
289
+ return {
290
+ kind: "route",
291
+ route: {
292
+ pathname: routePathname(pathnameSegments),
293
+ pattern,
294
+ identity: routePathname(identitySegments),
295
+ params,
296
+ file: relativeFile,
297
+ relativeFile
298
+ }
299
+ };
300
+ }
301
+ function pageRelativeFile(file) {
302
+ if (file === PAGES_DIR || !file.startsWith(`${PAGES_DIR}/`)) return;
303
+ return relative(PAGES_DIR, file);
304
+ }
305
+ function normalizeSegment(segment, index, segments, relativeFile) {
306
+ const catchAll = segment.match(/^\[\.\.\.([A-Za-z_$][\w$]*)\]$/);
307
+ if (catchAll) {
308
+ if (index !== segments.length - 1) throw new Error(`Catch-all route segments must be final: ${relativeFile}`);
309
+ return {
310
+ pathname: "**",
311
+ identity: "**",
312
+ params: [{
313
+ name: catchAll[1],
314
+ kind: "catch-all"
315
+ }]
316
+ };
317
+ }
318
+ const dynamic = segment.match(/^\[([A-Za-z_$][\w$]*)\]$/);
319
+ if (dynamic) return {
320
+ pathname: `:${dynamic[1]}`,
321
+ identity: ":param",
322
+ params: [{
323
+ name: dynamic[1],
324
+ kind: "dynamic"
325
+ }]
326
+ };
327
+ if (segment.includes("[") || segment.includes("]")) throw new Error(`Unsupported route segment pattern: ${relativeFile}`);
328
+ return {
329
+ pathname: segment,
330
+ identity: segment,
331
+ params: []
332
+ };
333
+ }
334
+ function assertNoRouteConflicts(routes) {
335
+ const routesByIdentity = /* @__PURE__ */ new Map();
336
+ for (const route of routes) {
337
+ const existingRoutes = routesByIdentity.get(route.identity) ?? [];
338
+ existingRoutes.push(route);
339
+ routesByIdentity.set(route.identity, existingRoutes);
340
+ }
341
+ for (const [identity, conflictingRoutes] of routesByIdentity) {
342
+ if (conflictingRoutes.length < 2) continue;
343
+ const files = conflictingRoutes.map((route) => route.relativeFile).toSorted(compareCodeUnits);
344
+ throw new Error([`Route conflict: ${identity} is defined by both:`, ...files.map((file) => `- ${file}`)].join("\n"));
345
+ }
346
+ }
347
+ const PAGE_METHODS = /* @__PURE__ */ new Set([
348
+ "all",
349
+ "get",
350
+ "head"
351
+ ]);
352
+ /**
353
+ * Page files may live under pages/api/ beside the endpoints in api/; the build fails only when one
354
+ * address is answered by both, since the endpoint would always win and the page could never be served.
355
+ */
356
+ function assertNoEndpointConflicts(manifest, endpointFileIds) {
357
+ for (const fileId of endpointFileIds) {
358
+ const endpoint = parseRequestFile(fileId, "");
359
+ if (endpoint.kind !== "api" || !PAGE_METHODS.has(endpoint.method)) continue;
360
+ const segments = pathSegments(endpoint.route.pathname);
361
+ for (const route of manifest.routes) {
362
+ const address = sharedAddress(pathSegments(route.pathname), segments);
363
+ if (address === void 0) continue;
364
+ throw new Error([
365
+ `Route conflict: ${address} is answered by both a page and an endpoint:`,
366
+ `- ${route.file}`,
367
+ `- ${endpoint.file}`
368
+ ].join("\n"));
369
+ }
370
+ }
371
+ }
372
+ const pathSegments = (pathname) => pathname.split("/").filter(Boolean);
373
+ function sharedAddress(left, right) {
374
+ const address = [];
375
+ for (let index = 0;; index++) {
376
+ const a = left[index];
377
+ const b = right[index];
378
+ if (a === "**" || b === "**") {
379
+ const other = a === "**" ? right : left;
380
+ return other.length > index ? `/${[...address, ...other.slice(index)].join("/")}` : void 0;
381
+ }
382
+ if (a === void 0 || b === void 0) return a === b ? `/${address.join("/")}` : void 0;
383
+ if (a.startsWith(":")) address.push(b);
384
+ else if (b.startsWith(":") || a === b) address.push(a);
385
+ else return void 0;
386
+ }
387
+ }
388
+ function toPublicRoute(route) {
389
+ return {
390
+ pathname: route.pathname,
391
+ pattern: route.pattern,
392
+ params: route.params,
393
+ file: route.file
394
+ };
395
+ }
396
+ function compareRoutes(left, right) {
397
+ const leftSegments = splitRoutePathname(left.pathname);
398
+ const rightSegments = splitRoutePathname(right.pathname);
399
+ const length = Math.max(leftSegments.length, rightSegments.length);
400
+ for (let index = 0; index < length; index += 1) {
401
+ const leftSegment = leftSegments[index];
402
+ const rightSegment = rightSegments[index];
403
+ if (leftSegment === void 0) return -1;
404
+ if (rightSegment === void 0) return 1;
405
+ const rankDifference = segmentRank(leftSegment) - segmentRank(rightSegment);
406
+ if (rankDifference !== 0) return rankDifference;
407
+ if (segmentRank(leftSegment) === 0 && leftSegment !== rightSegment) return compareCodeUnits(leftSegment, rightSegment);
408
+ }
409
+ return compareCodeUnits(left.pathname, right.pathname);
410
+ }
411
+ function splitRoutePathname(pathname) {
412
+ const route = withoutLeadingSlash(pathname);
413
+ return route === "" ? [] : route.split("/");
414
+ }
415
+ function matchRoutePathname(route, requestPathname) {
416
+ const routeSegments = splitRoutePathname(route.pathname);
417
+ const requestSegments = splitRoutePathname(requestPathname);
418
+ const catchAllIndex = routeSegments.indexOf("**");
419
+ if (catchAllIndex === -1 && routeSegments.length !== requestSegments.length) return;
420
+ if (catchAllIndex !== -1 && requestSegments.length <= catchAllIndex) return;
421
+ const params = {};
422
+ for (let index = 0; index < routeSegments.length; index += 1) {
423
+ const routeSegment = routeSegments[index];
424
+ const requestSegment = requestSegments[index];
425
+ if (routeSegment === "**") {
426
+ const catchAllParam = route.params.find((param) => param.kind === "catch-all");
427
+ if (!catchAllParam) return void 0;
428
+ params[catchAllParam.name] = joinURL(requestSegment, ...requestSegments.slice(index + 1));
429
+ return params;
430
+ }
431
+ if (routeSegment.startsWith(":")) {
432
+ params[routeSegment.slice(1)] = requestSegment;
433
+ continue;
434
+ }
435
+ if (routeSegment !== requestSegment) return;
436
+ }
437
+ return params;
438
+ }
439
+ function segmentRank(segment) {
440
+ if (segment === "**") return 2;
441
+ if (segment.startsWith(":")) return 1;
442
+ return 0;
443
+ }
444
+ function compareCodeUnits(left, right) {
445
+ return left < right ? -1 : left > right ? 1 : 0;
446
+ }
447
+ function unique(values) {
448
+ return [...new Set(values)];
449
+ }
450
+ function routePathname(segments) {
451
+ if (segments.length === 0) return "/";
452
+ const [base, ...rest] = segments;
453
+ return withLeadingSlash(joinURL(base, ...rest));
454
+ }
455
+ //#endregion
456
+ export { normalizeRequestPathname as a, parseRequestFile as c, matchRouteManifest as i, transformRequestFileSource as l, buildRouteManifestFromFileIds as n, normalizeRouteFileId as o, isPageModuleFile as r, normalizeRequestFileId as s, assertNoEndpointConflicts as t };
@@ -168,7 +168,7 @@ function isReservedOrUnsupportedPage(fileId) {
168
168
  const withoutExtension = fileId.slice(0, -extension.length);
169
169
  const routeFile = (0, pathe.normalize)(withoutExtension);
170
170
  const segments = routeFile === "." ? [] : routeFile.split("/").filter(Boolean);
171
- return segments[0] === "api" || segments.length === 1 && (segments[0] === "404" || segments[0] === "500");
171
+ return segments.length === 1 && (segments[0] === "404" || segments[0] === "500");
172
172
  }
173
173
  function routeFromFileId(fileId) {
174
174
  const extension = (0, pathe.extname)(fileId);
@@ -168,7 +168,7 @@ function isReservedOrUnsupportedPage(fileId) {
168
168
  const withoutExtension = fileId.slice(0, -extension.length);
169
169
  const routeFile = normalize(withoutExtension);
170
170
  const segments = routeFile === "." ? [] : routeFile.split("/").filter(Boolean);
171
- return segments[0] === "api" || segments.length === 1 && (segments[0] === "404" || segments[0] === "500");
171
+ return segments.length === 1 && (segments[0] === "404" || segments[0] === "500");
172
172
  }
173
173
  function routeFromFileId(fileId) {
174
174
  const extension = extname(fileId);
@@ -1,4 +1,4 @@
1
- import { a as normalizeRouteFileId } from "../../route-manifest-Bw_nFohL.js";
1
+ import { o as normalizeRouteFileId } from "../../route-manifest-DMizh42B.js";
2
2
  //#region src/vite/runtime/create-route-discovery.ts
3
3
  function createRouteDiscovery(discoveredPageModuleLoaders) {
4
4
  const pageModuleLoaders = Object.fromEntries(Object.entries(discoveredPageModuleLoaders).map(([file, loader]) => [normalizeRouteFileId(file), loader]));
@@ -1,3 +1,4 @@
1
+ import { z as RouteManifest } from "../../index-BjxpxRL7.js";
1
2
  import { ModulePreloadInput } from "@markless/web/render-to-string";
2
3
  //#region src/vite/runtime/create-server-entry.d.ts
3
4
  export interface ServerEntryOptions {
@@ -19,9 +20,24 @@ export interface ServerEntryOptions {
19
20
  readonly render?: 'streaming' | 'blocking';
20
21
  readonly navigation?: 'fragment' | 'render';
21
22
  readonly fragmentEntryPath?: string;
23
+ readonly fragmentEntryImports?: readonly string[];
22
24
  readonly fragmentNavigationSource?: string;
25
+ readonly fragmentNavigationRunSource?: string;
26
+ readonly linkBridgePaths?: readonly [withoutHashLinks: string, withHashLinks: string];
23
27
  }
28
+ export type LinkBridgeOptions = Pick<ServerEntryOptions, 'base' | 'navigationEntryPath' | 'prefetch' | 'documentNavigation' | 'navigation' | 'fragmentEntryPath' | 'fragmentEntryImports' | 'fragmentNavigationSource' | 'fragmentNavigationRunSource' | 'routeFileIds'> & {
29
+ readonly debug?: boolean;
30
+ };
31
+ /** The link bridge modules a built app's pages import; the build writes them as static client files. */
32
+ export declare function routerLinkBridgeModules(options: LinkBridgeOptions, manifest?: RouteManifest): LinkBridgeFiles | undefined;
24
33
  export declare function createServerEntry(options: ServerEntryOptions): {
25
34
  fetch: (request: Request) => Promise<Response>;
35
+ linkBridgeModules: LinkBridgeFiles | undefined;
26
36
  };
37
+ export interface LinkBridgeModule {
38
+ readonly path: string;
39
+ readonly source: string;
40
+ }
41
+ /** The two page-imported bridges (without and with '#/' links), then any file they load later. */
42
+ export type LinkBridgeFiles = readonly [withoutHashLinks: LinkBridgeModule, withHashLinks: LinkBridgeModule, ...later: LinkBridgeModule[]];
27
43
  //#endregion