@reckona/mreact-router 0.0.132 → 0.0.135

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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/cloudflare.js +1 -1
  3. package/dist/adapters/cloudflare.js.map +1 -1
  4. package/dist/adapters/static.js +5 -1
  5. package/dist/adapters/static.js.map +1 -1
  6. package/dist/build.d.ts +1 -0
  7. package/dist/build.d.ts.map +1 -1
  8. package/dist/build.js +136 -41
  9. package/dist/build.js.map +1 -1
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +167 -8
  12. package/dist/client.js.map +1 -1
  13. package/dist/http.d.ts +1 -0
  14. package/dist/http.d.ts.map +1 -1
  15. package/dist/http.js +7 -1
  16. package/dist/http.js.map +1 -1
  17. package/dist/module-runner.d.ts +4 -1
  18. package/dist/module-runner.d.ts.map +1 -1
  19. package/dist/module-runner.js +3 -2
  20. package/dist/module-runner.js.map +1 -1
  21. package/dist/render.d.ts +6 -1
  22. package/dist/render.d.ts.map +1 -1
  23. package/dist/render.js +84 -46
  24. package/dist/render.js.map +1 -1
  25. package/dist/routes.js +1 -1
  26. package/dist/routes.js.map +1 -1
  27. package/dist/serve.d.ts.map +1 -1
  28. package/dist/serve.js +110 -17
  29. package/dist/serve.js.map +1 -1
  30. package/dist/vite-plugin-cache-key.d.ts +2 -1
  31. package/dist/vite-plugin-cache-key.d.ts.map +1 -1
  32. package/dist/vite-plugin-cache-key.js +9 -0
  33. package/dist/vite-plugin-cache-key.js.map +1 -1
  34. package/dist/vite.d.ts +2 -1
  35. package/dist/vite.d.ts.map +1 -1
  36. package/dist/vite.js +2 -0
  37. package/dist/vite.js.map +1 -1
  38. package/package.json +11 -11
  39. package/src/adapters/cloudflare.ts +1 -1
  40. package/src/adapters/static.ts +7 -1
  41. package/src/build.ts +201 -53
  42. package/src/client.ts +288 -17
  43. package/src/http.ts +9 -1
  44. package/src/module-runner.ts +8 -2
  45. package/src/render.ts +117 -21
  46. package/src/routes.ts +1 -1
  47. package/src/serve.ts +167 -18
  48. package/src/vite-plugin-cache-key.ts +12 -1
  49. package/src/vite.ts +4 -0
package/dist/routes.js CHANGED
@@ -162,7 +162,7 @@ async function collectRouteFiles(directory, rootDirectory = directory) {
162
162
  return files;
163
163
  }
164
164
  function shouldSkipRouteScanDirectory(name) {
165
- return name === ".vite" || name === "node_modules";
165
+ return name === ".vite" || name === "__tests__" || name === "node_modules";
166
166
  }
167
167
  function appFileConventionForRelativeFile(relativeFile) {
168
168
  const parts = relativeFile.split(sep);
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport { createNativeRouteMatcher } from \"./native-route-matcher.js\";\nimport {\n appFileConventionForRootFilename,\n type AppFileConvention,\n} from \"./file-conventions.js\";\n\nexport interface ScanAppRoutesOptions {\n appDir: string;\n}\n\nexport type AppRoute = AppAssetRoute | AppMetadataRoute | PageRoute | ServerRoute;\n\nexport interface PageRoute {\n kind: \"page\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface ServerRoute {\n kind: \"server\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface AppMetadataRoute {\n convention: AppFileConvention;\n kind: \"metadata\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface AppAssetRoute {\n convention: AppFileConvention;\n kind: \"asset\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport type RouteSegment =\n | { kind: \"static\"; value: string }\n | { kind: \"dynamic\"; name: string }\n | { kind: \"catch-all\"; name: string };\n\nexport interface MatchedRoute {\n route: AppRoute;\n params: Record<string, readonly string[] | string>;\n}\n\nexport interface RouteMatcher {\n match(pathname: string): MatchedRoute | undefined;\n}\n\nexport async function scanAppRoutes(\n options: ScanAppRoutesOptions,\n): Promise<AppRoute[]> {\n const files = await collectRouteFiles(options.appDir);\n\n return files\n .map((file): AppRoute => {\n const relativeFile = relative(options.appDir, file);\n const convention = appFileConventionForRelativeFile(relativeFile);\n if (convention !== undefined) {\n return {\n convention: convention.convention,\n file,\n kind: convention.kind,\n path: convention.path,\n segments: segmentsFromPath(convention.path),\n };\n }\n\n const kind = relativeFile.endsWith(\"route.ts\") ? \"server\" : \"page\";\n const routePath = routePathFromRelativeFile(relativeFile);\n const segments = segmentsFromPath(routePath);\n\n return { kind, path: routePath, file, segments };\n })\n .sort(compareRouteListEntries);\n}\n\nexport function matchRoute(\n routes: readonly AppRoute[],\n pathname: string,\n): MatchedRoute | undefined {\n return createRouteMatcher(routes).match(pathname);\n}\n\nexport function createRouteMatcher(routes: readonly AppRoute[]): RouteMatcher {\n const sortedRoutes = [...routes].sort(compareRoutes);\n const nativeMatcher = createNativeRouteMatcher(sortedRoutes);\n\n if (nativeMatcher !== undefined) {\n return nativeMatcher;\n }\n\n return {\n match(pathname) {\n return matchSortedRoutes(sortedRoutes, pathname);\n },\n };\n}\n\nfunction matchSortedRoutes(\n routes: readonly AppRoute[],\n pathname: string,\n): MatchedRoute | undefined {\n const normalized = normalizePath(pathname);\n const pathnameSegments = normalized === \"/\" ? [] : normalized.slice(1).split(\"/\");\n\n for (const route of routes) {\n const catchAllIndex = route.segments.findIndex(\n (segment) => segment.kind === \"catch-all\",\n );\n\n if (catchAllIndex === -1 && route.segments.length !== pathnameSegments.length) {\n continue;\n }\n\n if (catchAllIndex !== -1 && pathnameSegments.length < catchAllIndex + 1) {\n continue;\n }\n\n const params: Record<string, readonly string[] | string> = {};\n let matched = true;\n\n for (const [index, segment] of route.segments.entries()) {\n const value = pathnameSegments[index];\n\n if (value === undefined) {\n matched = false;\n break;\n }\n\n if (segment.kind === \"static\" && segment.value !== value) {\n matched = false;\n break;\n }\n\n if (segment.kind === \"dynamic\") {\n const decoded = safeDecodeURIComponent(value);\n if (decoded === undefined) {\n // Malformed percent-encoding -- treat as non-match rather than\n // letting URIError escape and produce a 500 (Issue 072).\n matched = false;\n break;\n }\n params[segment.name] = decoded;\n }\n\n if (segment.kind === \"catch-all\") {\n const suffixSegments = route.segments.slice(index + 1);\n const catchAllEnd = pathnameSegments.length - suffixSegments.length;\n\n if (catchAllEnd <= index) {\n matched = false;\n break;\n }\n\n const decodedParts: string[] = [];\n let decodeOk = true;\n for (const part of pathnameSegments.slice(index, catchAllEnd)) {\n const decoded = safeDecodeURIComponent(part);\n if (decoded === undefined) {\n decodeOk = false;\n break;\n }\n decodedParts.push(decoded);\n }\n if (!decodeOk) {\n matched = false;\n break;\n }\n params[segment.name] = decodedParts;\n\n for (let suffixIndex = 0; suffixIndex < suffixSegments.length; suffixIndex += 1) {\n const suffixSegment = suffixSegments[suffixIndex];\n const suffixValue = pathnameSegments[catchAllEnd + suffixIndex];\n\n if (suffixSegment === undefined || suffixValue === undefined) {\n matched = false;\n break;\n }\n\n if (suffixSegment.kind === \"static\" && suffixSegment.value !== suffixValue) {\n matched = false;\n break;\n }\n\n if (suffixSegment.kind === \"dynamic\") {\n const decoded = safeDecodeURIComponent(suffixValue);\n if (decoded === undefined) {\n matched = false;\n break;\n }\n params[suffixSegment.name] = decoded;\n }\n\n if (suffixSegment.kind === \"catch-all\") {\n matched = false;\n break;\n }\n }\n\n break;\n }\n }\n\n if (matched) {\n return { route, params };\n }\n }\n\n return undefined;\n}\n\n// Issue 072: attacker-supplied path segments / cookie values can include\n// malformed percent escapes (e.g. `%ZZ`, `%E0`). Catch the URIError so a\n// single bad byte cannot turn every request into a 500 + stack-leaking\n// response.\nexport function safeDecodeURIComponent(value: string): string | undefined {\n try {\n return decodeURIComponent(value);\n } catch {\n return undefined;\n }\n}\n\nasync function collectRouteFiles(directory: string, rootDirectory = directory): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const path = join(directory, entry.name);\n\n if (entry.isDirectory()) {\n if (shouldSkipRouteScanDirectory(entry.name)) {\n continue;\n }\n\n files.push(...(await collectRouteFiles(path, rootDirectory)));\n continue;\n }\n\n if (\n entry.isFile() &&\n (entry.name === \"page.tsx\" ||\n entry.name === \"page.mreact.tsx\" ||\n entry.name === \"route.ts\" ||\n appFileConventionForRelativeFile(relative(rootDirectory, path)) !== undefined)\n ) {\n files.push(path);\n }\n }\n\n return files;\n}\n\nfunction shouldSkipRouteScanDirectory(name: string): boolean {\n return name === \".vite\" || name === \"node_modules\";\n}\n\nfunction appFileConventionForRelativeFile(\n relativeFile: string,\n): ReturnType<typeof appFileConventionForRootFilename> {\n const parts = relativeFile.split(sep);\n const filename = parts.at(-1);\n\n if (filename === undefined) {\n return undefined;\n }\n\n const convention = appFileConventionForRootFilename(filename);\n\n if (convention === undefined) {\n return undefined;\n }\n\n if (parts.length === 1) {\n return convention;\n }\n\n if (convention.kind !== \"metadata\" || convention.convention !== \"opengraph-image\") {\n return undefined;\n }\n\n const routeParts = parts\n .slice(0, -1)\n .filter((part) => !isRouteGroup(part))\n .map((part) => (part.startsWith(\"$\") ? `:${part.slice(1)}` : part));\n const conventionPath = convention.path.startsWith(\"/\")\n ? convention.path.slice(1)\n : convention.path;\n\n return {\n ...convention,\n path: normalizePath(`/${[...routeParts, conventionPath].join(\"/\")}`),\n };\n}\n\nfunction routePathFromRelativeFile(relativeFile: string): string {\n const parts = relativeFile.split(sep);\n const routeParts = parts\n .slice(0, -1)\n .filter((part) => !isRouteGroup(part))\n .map((part) => (part.startsWith(\"$\") ? `:${part.slice(1)}` : part));\n\n return normalizePath(`/${routeParts.join(\"/\")}`);\n}\n\nfunction segmentsFromPath(path: string): RouteSegment[] {\n return path === \"/\"\n ? []\n : path\n .slice(1)\n .split(\"/\")\n .map((part) =>\n part.startsWith(\":...\")\n ? { kind: \"catch-all\", name: part.slice(4) }\n : part.startsWith(\":\")\n ? { kind: \"dynamic\", name: part.slice(1) }\n : { kind: \"static\", value: part },\n );\n}\n\nfunction normalizePath(path: string): string {\n const withoutTrailing = path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n\n return withoutTrailing === \"\" ? \"/\" : withoutTrailing;\n}\n\nfunction isRouteGroup(part: string): boolean {\n return part.startsWith(\"(\") && part.endsWith(\")\");\n}\n\nfunction compareRoutes(a: AppRoute, b: AppRoute): number {\n const scoreDelta = routeScore(b) - routeScore(a);\n\n return scoreDelta === 0 ? a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind) : scoreDelta;\n}\n\nfunction compareRouteListEntries(a: AppRoute, b: AppRoute): number {\n return routeListKey(a.path).localeCompare(routeListKey(b.path)) ||\n a.kind.localeCompare(b.kind);\n}\n\nfunction routeListKey(path: string): string {\n return path === \"/\"\n ? \"\"\n : path.replaceAll(\"/:...\", \"/zzzz-catch-all-\").replaceAll(\"/:\", \"/zzzz-dynamic-\");\n}\n\nfunction routeScore(route: AppRoute): number {\n return route.segments.reduce((score, segment) => {\n if (segment.kind === \"static\") {\n return score + 100;\n }\n\n if (segment.kind === \"dynamic\") {\n return score + 10;\n }\n\n return score;\n }, route.segments.length);\n}\n"]}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport { createNativeRouteMatcher } from \"./native-route-matcher.js\";\nimport {\n appFileConventionForRootFilename,\n type AppFileConvention,\n} from \"./file-conventions.js\";\n\nexport interface ScanAppRoutesOptions {\n appDir: string;\n}\n\nexport type AppRoute = AppAssetRoute | AppMetadataRoute | PageRoute | ServerRoute;\n\nexport interface PageRoute {\n kind: \"page\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface ServerRoute {\n kind: \"server\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface AppMetadataRoute {\n convention: AppFileConvention;\n kind: \"metadata\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport interface AppAssetRoute {\n convention: AppFileConvention;\n kind: \"asset\";\n path: string;\n file: string;\n segments: RouteSegment[];\n}\n\nexport type RouteSegment =\n | { kind: \"static\"; value: string }\n | { kind: \"dynamic\"; name: string }\n | { kind: \"catch-all\"; name: string };\n\nexport interface MatchedRoute {\n route: AppRoute;\n params: Record<string, readonly string[] | string>;\n}\n\nexport interface RouteMatcher {\n match(pathname: string): MatchedRoute | undefined;\n}\n\nexport async function scanAppRoutes(\n options: ScanAppRoutesOptions,\n): Promise<AppRoute[]> {\n const files = await collectRouteFiles(options.appDir);\n\n return files\n .map((file): AppRoute => {\n const relativeFile = relative(options.appDir, file);\n const convention = appFileConventionForRelativeFile(relativeFile);\n if (convention !== undefined) {\n return {\n convention: convention.convention,\n file,\n kind: convention.kind,\n path: convention.path,\n segments: segmentsFromPath(convention.path),\n };\n }\n\n const kind = relativeFile.endsWith(\"route.ts\") ? \"server\" : \"page\";\n const routePath = routePathFromRelativeFile(relativeFile);\n const segments = segmentsFromPath(routePath);\n\n return { kind, path: routePath, file, segments };\n })\n .sort(compareRouteListEntries);\n}\n\nexport function matchRoute(\n routes: readonly AppRoute[],\n pathname: string,\n): MatchedRoute | undefined {\n return createRouteMatcher(routes).match(pathname);\n}\n\nexport function createRouteMatcher(routes: readonly AppRoute[]): RouteMatcher {\n const sortedRoutes = [...routes].sort(compareRoutes);\n const nativeMatcher = createNativeRouteMatcher(sortedRoutes);\n\n if (nativeMatcher !== undefined) {\n return nativeMatcher;\n }\n\n return {\n match(pathname) {\n return matchSortedRoutes(sortedRoutes, pathname);\n },\n };\n}\n\nfunction matchSortedRoutes(\n routes: readonly AppRoute[],\n pathname: string,\n): MatchedRoute | undefined {\n const normalized = normalizePath(pathname);\n const pathnameSegments = normalized === \"/\" ? [] : normalized.slice(1).split(\"/\");\n\n for (const route of routes) {\n const catchAllIndex = route.segments.findIndex(\n (segment) => segment.kind === \"catch-all\",\n );\n\n if (catchAllIndex === -1 && route.segments.length !== pathnameSegments.length) {\n continue;\n }\n\n if (catchAllIndex !== -1 && pathnameSegments.length < catchAllIndex + 1) {\n continue;\n }\n\n const params: Record<string, readonly string[] | string> = {};\n let matched = true;\n\n for (const [index, segment] of route.segments.entries()) {\n const value = pathnameSegments[index];\n\n if (value === undefined) {\n matched = false;\n break;\n }\n\n if (segment.kind === \"static\" && segment.value !== value) {\n matched = false;\n break;\n }\n\n if (segment.kind === \"dynamic\") {\n const decoded = safeDecodeURIComponent(value);\n if (decoded === undefined) {\n // Malformed percent-encoding -- treat as non-match rather than\n // letting URIError escape and produce a 500 (Issue 072).\n matched = false;\n break;\n }\n params[segment.name] = decoded;\n }\n\n if (segment.kind === \"catch-all\") {\n const suffixSegments = route.segments.slice(index + 1);\n const catchAllEnd = pathnameSegments.length - suffixSegments.length;\n\n if (catchAllEnd <= index) {\n matched = false;\n break;\n }\n\n const decodedParts: string[] = [];\n let decodeOk = true;\n for (const part of pathnameSegments.slice(index, catchAllEnd)) {\n const decoded = safeDecodeURIComponent(part);\n if (decoded === undefined) {\n decodeOk = false;\n break;\n }\n decodedParts.push(decoded);\n }\n if (!decodeOk) {\n matched = false;\n break;\n }\n params[segment.name] = decodedParts;\n\n for (let suffixIndex = 0; suffixIndex < suffixSegments.length; suffixIndex += 1) {\n const suffixSegment = suffixSegments[suffixIndex];\n const suffixValue = pathnameSegments[catchAllEnd + suffixIndex];\n\n if (suffixSegment === undefined || suffixValue === undefined) {\n matched = false;\n break;\n }\n\n if (suffixSegment.kind === \"static\" && suffixSegment.value !== suffixValue) {\n matched = false;\n break;\n }\n\n if (suffixSegment.kind === \"dynamic\") {\n const decoded = safeDecodeURIComponent(suffixValue);\n if (decoded === undefined) {\n matched = false;\n break;\n }\n params[suffixSegment.name] = decoded;\n }\n\n if (suffixSegment.kind === \"catch-all\") {\n matched = false;\n break;\n }\n }\n\n break;\n }\n }\n\n if (matched) {\n return { route, params };\n }\n }\n\n return undefined;\n}\n\n// Issue 072: attacker-supplied path segments / cookie values can include\n// malformed percent escapes (e.g. `%ZZ`, `%E0`). Catch the URIError so a\n// single bad byte cannot turn every request into a 500 + stack-leaking\n// response.\nexport function safeDecodeURIComponent(value: string): string | undefined {\n try {\n return decodeURIComponent(value);\n } catch {\n return undefined;\n }\n}\n\nasync function collectRouteFiles(directory: string, rootDirectory = directory): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const path = join(directory, entry.name);\n\n if (entry.isDirectory()) {\n if (shouldSkipRouteScanDirectory(entry.name)) {\n continue;\n }\n\n files.push(...(await collectRouteFiles(path, rootDirectory)));\n continue;\n }\n\n if (\n entry.isFile() &&\n (entry.name === \"page.tsx\" ||\n entry.name === \"page.mreact.tsx\" ||\n entry.name === \"route.ts\" ||\n appFileConventionForRelativeFile(relative(rootDirectory, path)) !== undefined)\n ) {\n files.push(path);\n }\n }\n\n return files;\n}\n\nfunction shouldSkipRouteScanDirectory(name: string): boolean {\n return name === \".vite\" || name === \"__tests__\" || name === \"node_modules\";\n}\n\nfunction appFileConventionForRelativeFile(\n relativeFile: string,\n): ReturnType<typeof appFileConventionForRootFilename> {\n const parts = relativeFile.split(sep);\n const filename = parts.at(-1);\n\n if (filename === undefined) {\n return undefined;\n }\n\n const convention = appFileConventionForRootFilename(filename);\n\n if (convention === undefined) {\n return undefined;\n }\n\n if (parts.length === 1) {\n return convention;\n }\n\n if (convention.kind !== \"metadata\" || convention.convention !== \"opengraph-image\") {\n return undefined;\n }\n\n const routeParts = parts\n .slice(0, -1)\n .filter((part) => !isRouteGroup(part))\n .map((part) => (part.startsWith(\"$\") ? `:${part.slice(1)}` : part));\n const conventionPath = convention.path.startsWith(\"/\")\n ? convention.path.slice(1)\n : convention.path;\n\n return {\n ...convention,\n path: normalizePath(`/${[...routeParts, conventionPath].join(\"/\")}`),\n };\n}\n\nfunction routePathFromRelativeFile(relativeFile: string): string {\n const parts = relativeFile.split(sep);\n const routeParts = parts\n .slice(0, -1)\n .filter((part) => !isRouteGroup(part))\n .map((part) => (part.startsWith(\"$\") ? `:${part.slice(1)}` : part));\n\n return normalizePath(`/${routeParts.join(\"/\")}`);\n}\n\nfunction segmentsFromPath(path: string): RouteSegment[] {\n return path === \"/\"\n ? []\n : path\n .slice(1)\n .split(\"/\")\n .map((part) =>\n part.startsWith(\":...\")\n ? { kind: \"catch-all\", name: part.slice(4) }\n : part.startsWith(\":\")\n ? { kind: \"dynamic\", name: part.slice(1) }\n : { kind: \"static\", value: part },\n );\n}\n\nfunction normalizePath(path: string): string {\n const withoutTrailing = path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n\n return withoutTrailing === \"\" ? \"/\" : withoutTrailing;\n}\n\nfunction isRouteGroup(part: string): boolean {\n return part.startsWith(\"(\") && part.endsWith(\")\");\n}\n\nfunction compareRoutes(a: AppRoute, b: AppRoute): number {\n const scoreDelta = routeScore(b) - routeScore(a);\n\n return scoreDelta === 0 ? a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind) : scoreDelta;\n}\n\nfunction compareRouteListEntries(a: AppRoute, b: AppRoute): number {\n return routeListKey(a.path).localeCompare(routeListKey(b.path)) ||\n a.kind.localeCompare(b.kind);\n}\n\nfunction routeListKey(path: string): string {\n return path === \"/\"\n ? \"\"\n : path.replaceAll(\"/:...\", \"/zzzz-catch-all-\").replaceAll(\"/:\", \"/zzzz-dynamic-\");\n}\n\nfunction routeScore(route: AppRoute): number {\n return route.segments.reduce((score, segment) => {\n if (segment.kind === \"static\") {\n return score + 100;\n }\n\n if (segment.kind === \"dynamic\") {\n return score + 10;\n }\n\n return score;\n }, route.segments.length);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAItD,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE3B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA0DvD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACvD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,eAAe,CAAC;AAI3D,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC/C,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACzD,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,MAAM,gCAAgC,GAAG,IAAI,CACjD,4BAA4B,EAC5B,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CACzD,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,CACJ,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gCAAgC,GAAG,SAAS,GACrD,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAED,MAAM,MAAM,0BAA0B,GAClC,KAAK,GACL,oBAAoB,GACpB,YAAY,GACZ,YAAY,GACZ,MAAM,CAAC;AAEX,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,0BAA0B,CAAC;IACjC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAKlB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAOtG,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC3C,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC/C,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACxC,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACzD,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,SAAS,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAC5C;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,MAAM,CAOT;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC5C,GAAG,IAAI,CAcP;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC;IAClG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChE;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,mBAAmB,CAAC,CAkC9B;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,8BAA8B,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAuED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,QAAQ,CAAC,CAanB;AA0LD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC;IAAE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA+FlE;AAsBD,iBAAe,oBAAoB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAmC/B;AAED,eAAO,MAAM,6BAA6B,6BAAuB,CAAC;AAElE,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,wBAAgB,qCAAqC,IAAI,MAAM,CAE9D"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAItD,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE3B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAQxD,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA2DvD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AACvD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,eAAe,CAAC;AAI3D,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC/C,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACzD,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,MAAM,gCAAgC,GAAG,IAAI,CACjD,4BAA4B,EAC5B,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CACzD,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,OAAO,CAAC,EAAE,8BAA8B,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,CACJ,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gCAAgC,GAAG,SAAS,GACrD,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAED,MAAM,MAAM,0BAA0B,GAClC,KAAK,GACL,oBAAoB,GACpB,YAAY,GACZ,YAAY,GACZ,MAAM,CAAC;AAEX,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,0BAA0B,CAAC;IACjC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAKlB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAOtG,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC3C,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC/C,cAAc,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACxC,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACzD,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,SAAS,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAC5C;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,MAAM,CAOT;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,UAAU,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC5C,GAAG,IAAI,CAcP;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAAC;IAClG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChE;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,mBAAmB,CAAC,CAkC9B;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,8BAA8B,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAuED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,QAAQ,CAAC,CAanB;AAgMD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC;IAAE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA+FlE;AAyGD,iBAAe,oBAAoB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAmC/B;AAED,eAAO,MAAM,6BAA6B,6BAAuB,CAAC;AAElE,wBAAgB,mCAAmC,IAAI,IAAI,CAE1D;AAED,wBAAgB,qCAAqC,IAAI,MAAM,CAE9D"}
package/dist/serve.js CHANGED
@@ -4,7 +4,7 @@ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
4
  import { dirname, isAbsolute, join, normalize, sep } from "node:path";
5
5
  import { createRouteMatcher } from "./routes.js";
6
6
  import { preloadBuiltRequestModules, renderAppRequest, resolveAppRouterMiddleware, } from "./render.js";
7
- import { bytesResponse, htmlResponse, nodeRequestToWebRequest, sendResponse } from "./http.js";
7
+ import { bytesResponse, htmlResponse, nodeRequestToWebRequest, rawNodeRequestUrl, sendResponse, } from "./http.js";
8
8
  import { emitRouterLog, logDurationMs, logError, logNow, nodeRequestPath, requestLogFields, } from "./logger.js";
9
9
  import { builtAppRuntimePreloadPlan } from "./preload-policy.js";
10
10
  import { routeShellCandidates } from "./route-shells.js";
@@ -135,8 +135,9 @@ export async function renderBuiltAppRequest(options) {
135
135
  async function renderBuiltAppRequestWithRuntime(options) {
136
136
  const url = new URL(options.request.url);
137
137
  const timing = createBuiltRenderTiming(options.logger);
138
- if (url.pathname.startsWith("/_mreact/client/")) {
139
- return readBuiltClientAsset(options.outDir, url.pathname);
138
+ const clientAssetPathname = builtClientAssetPathname(options.request, url);
139
+ if (clientAssetPathname !== undefined) {
140
+ return readBuiltClientAsset(options.outDir, clientAssetPathname, options.runtime.clientAssetPaths);
140
141
  }
141
142
  if (options.request.method === "GET" || options.request.method === "HEAD") {
142
143
  const publicAsset = await readBuiltPublicAsset(options.outDir, url.pathname);
@@ -343,11 +344,10 @@ export async function startServer(options) {
343
344
  close: () => new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))),
344
345
  };
345
346
  }
346
- async function readBuiltClientAsset(outDir, pathname) {
347
+ async function readBuiltClientAsset(outDir, pathname, allowedPaths) {
347
348
  const clientPrefix = "/_mreact/client/";
348
- const relativePath = pathname.slice(clientPrefix.length);
349
- const normalized = normalize(relativePath);
350
- if (normalized.startsWith("..")) {
349
+ const normalized = safeBuiltClientAssetPath(pathname.slice(clientPrefix.length));
350
+ if (normalized === undefined || !allowedPaths.has(normalized)) {
351
351
  return new Response("Not Found", { status: 404 });
352
352
  }
353
353
  try {
@@ -360,6 +360,66 @@ async function readBuiltClientAsset(outDir, pathname) {
360
360
  return new Response("Not Found", { status: 404 });
361
361
  }
362
362
  }
363
+ function builtClientAssetPathname(request, url) {
364
+ const rawUrl = rawNodeRequestUrl(request);
365
+ const rawPathname = rawUrl?.split(/[?#]/, 1)[0];
366
+ const pathname = rawPathname === undefined || rawPathname === "" ? url.pathname : rawPathname;
367
+ const normalizedPathname = pathname.startsWith("/") ? pathname : `/${pathname}`;
368
+ return normalizedPathname.startsWith("/_mreact/client/") ? normalizedPathname : undefined;
369
+ }
370
+ function safeBuiltClientAssetPath(relativePath) {
371
+ let decoded;
372
+ try {
373
+ decoded = decodeURIComponent(relativePath);
374
+ }
375
+ catch {
376
+ return undefined;
377
+ }
378
+ if (decoded.includes("\\") || decoded.includes("\0")) {
379
+ return undefined;
380
+ }
381
+ if (decoded.split("/").some((segment) => segment === "..")) {
382
+ return undefined;
383
+ }
384
+ const normalized = normalize(decoded);
385
+ if (isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${sep}`)) {
386
+ return undefined;
387
+ }
388
+ return normalized;
389
+ }
390
+ function builtClientAssetPaths(manifest) {
391
+ const paths = new Set(["manifest.json"]);
392
+ for (const route of manifest.routes) {
393
+ for (const asset of [
394
+ route.script,
395
+ route.sourceMap,
396
+ route.navigationScript,
397
+ ...(route.css ?? []),
398
+ ...(route.imports ?? []),
399
+ ]) {
400
+ const path = safeClientManifestAssetPath(asset);
401
+ if (path !== undefined) {
402
+ paths.add(path);
403
+ }
404
+ }
405
+ }
406
+ for (const asset of manifest.assets ?? []) {
407
+ const path = safeClientManifestAssetPath(asset);
408
+ if (path !== undefined) {
409
+ paths.add(path);
410
+ }
411
+ }
412
+ return paths;
413
+ }
414
+ function safeClientManifestAssetPath(asset) {
415
+ if (asset === undefined || asset === "" || asset.startsWith("/") || asset.includes("\\")) {
416
+ return undefined;
417
+ }
418
+ const segments = asset.split("/");
419
+ return segments.some((segment) => segment === "" || segment === "." || segment === "..")
420
+ ? undefined
421
+ : segments.join("/");
422
+ }
363
423
  async function readBuiltPublicAsset(outDir, pathname) {
364
424
  const relativePath = pathname.startsWith("/") ? pathname.slice(1) : pathname;
365
425
  if (relativePath === "") {
@@ -404,9 +464,12 @@ async function readBuiltRuntime(options) {
404
464
  if (options.immutable === true && cached !== undefined) {
405
465
  return cached.runtime;
406
466
  }
467
+ const serverManifestPath = join(outDir, "server", "manifest.json");
468
+ const clientManifestPath = join(outDir, "client", "manifest.json");
469
+ const importPolicyPath = join(outDir, "server", "import-policy.json");
407
470
  const [serverManifestText, clientManifestText, importPolicyText] = await Promise.all([
408
- readFile(join(outDir, "server", "manifest.json"), "utf8"),
409
- readFile(join(outDir, "client", "manifest.json"), "utf8"),
471
+ readRequiredBuiltArtifactText(serverManifestPath, "built app server manifest"),
472
+ readRequiredBuiltArtifactText(clientManifestPath, "built app client manifest"),
410
473
  readBuiltImportPolicyText(outDir),
411
474
  ]);
412
475
  if (cached !== undefined &&
@@ -417,10 +480,13 @@ async function readBuiltRuntime(options) {
417
480
  }
418
481
  const runtime = materializeBuiltRuntime({
419
482
  clientManifestText,
483
+ clientManifestPath,
420
484
  importPolicyText,
485
+ importPolicyPath,
421
486
  outDir,
422
487
  runtimeDir,
423
488
  serverManifestText,
489
+ serverManifestPath,
424
490
  });
425
491
  builtRuntimeCache.set(cacheKey, {
426
492
  clientManifestText,
@@ -431,8 +497,8 @@ async function readBuiltRuntime(options) {
431
497
  return runtime;
432
498
  }
433
499
  async function materializeBuiltRuntime(options) {
434
- const serverManifest = JSON.parse(options.serverManifestText);
435
- const clientManifest = JSON.parse(options.clientManifestText);
500
+ const serverManifest = parseBuiltJsonArtifact(options.serverManifestText, options.serverManifestPath, "built app server manifest");
501
+ const clientManifest = parseBuiltJsonArtifact(options.clientManifestText, options.clientManifestPath, "built app client manifest");
436
502
  const appDir = await materializeBuiltServerApp(options.runtimeDir, serverManifest);
437
503
  const projectRoot = appDir;
438
504
  const routesDir = join(projectRoot, serverManifest.routesDir ?? "");
@@ -482,13 +548,14 @@ async function materializeBuiltRuntime(options) {
482
548
  .digest("hex")
483
549
  .slice(0, 16);
484
550
  const allowedSourceDirs = (serverManifest.allowedSourceDirs ?? [""]).map((directory) => join(projectRoot, directory));
485
- const generatedImportPolicy = builtGeneratedImportPolicy(options.importPolicyText);
551
+ const generatedImportPolicy = builtGeneratedImportPolicy(options.importPolicyText, options.importPolicyPath);
486
552
  return {
487
553
  appDir: routesDir,
488
554
  allowedSourceDirs,
489
555
  ...(serverManifest.assetBaseUrl === undefined
490
556
  ? {}
491
557
  : { assetBaseUrl: serverManifest.assetBaseUrl }),
558
+ clientAssetPaths: builtClientAssetPaths(clientManifest),
492
559
  clientScripts,
493
560
  clientStylesByFile,
494
561
  clientStyles,
@@ -518,21 +585,22 @@ async function materializeBuiltRuntime(options) {
518
585
  };
519
586
  }
520
587
  async function readBuiltImportPolicyText(outDir) {
588
+ const policyPath = join(outDir, "server", "import-policy.json");
521
589
  try {
522
- return await readFile(join(outDir, "server", "import-policy.json"), "utf8");
590
+ return await readFile(policyPath, "utf8");
523
591
  }
524
592
  catch (error) {
525
593
  if (isMissingFileError(error)) {
526
594
  return undefined;
527
595
  }
528
- throw error;
596
+ throw builtArtifactReadError("built app import policy", policyPath, error);
529
597
  }
530
598
  }
531
- function builtGeneratedImportPolicy(importPolicyText) {
599
+ function builtGeneratedImportPolicy(importPolicyText, importPolicyPath) {
532
600
  if (importPolicyText === undefined) {
533
601
  return undefined;
534
602
  }
535
- const artifact = JSON.parse(importPolicyText);
603
+ const artifact = parseBuiltJsonArtifact(importPolicyText, importPolicyPath, "built app import policy");
536
604
  const runtimePackages = Array.isArray(artifact.runtimePackages)
537
605
  ? artifact.runtimePackages.filter((name) => typeof name === "string")
538
606
  : [];
@@ -563,6 +631,28 @@ function isMissingFileError(error) {
563
631
  "code" in error &&
564
632
  error.code === "ENOENT");
565
633
  }
634
+ async function readRequiredBuiltArtifactText(labelPath, label) {
635
+ try {
636
+ return await readFile(labelPath, "utf8");
637
+ }
638
+ catch (error) {
639
+ throw builtArtifactReadError(label, labelPath, error);
640
+ }
641
+ }
642
+ function builtArtifactReadError(label, artifactPath, error) {
643
+ const prefix = isMissingFileError(error) ? "Missing" : "Unable to read";
644
+ const detail = error instanceof Error && error.message !== "" ? `: ${error.message}` : "";
645
+ return new Error(`${prefix} ${label}: ${artifactPath}${detail}`, { cause: error });
646
+ }
647
+ function parseBuiltJsonArtifact(text, artifactPath, label) {
648
+ try {
649
+ return JSON.parse(text);
650
+ }
651
+ catch (error) {
652
+ const detail = error instanceof Error && error.message !== "" ? `: ${error.message}` : "";
653
+ throw new Error(`Invalid ${label}: ${artifactPath}${detail}`, { cause: error });
654
+ }
655
+ }
566
656
  async function loadBuiltServerModuleArtifacts(runtime, files, kind = "all") {
567
657
  for (const file of files) {
568
658
  await loadBuiltServerModuleArtifact(runtime, file, kind);
@@ -588,10 +678,13 @@ async function loadBuiltServerModuleArtifact(runtime, file, kind = "all") {
588
678
  const loaded = readFile(artifactPath, "utf8")
589
679
  .then((text) => {
590
680
  const existing = runtime.serverModules.get(file) ?? {};
591
- runtime.serverModules.set(file, mergeBuiltServerModuleArtifacts(existing, hydrateBuiltServerModuleArtifact(JSON.parse(text), builtServerDirForArtifactPath(artifactPath))));
681
+ runtime.serverModules.set(file, mergeBuiltServerModuleArtifacts(existing, hydrateBuiltServerModuleArtifact(parseBuiltJsonArtifact(text, artifactPath, `built server module artifact for ${file}`), builtServerDirForArtifactPath(artifactPath))));
592
682
  })
593
683
  .catch((error) => {
594
684
  runtime.serverModuleArtifactLoads.delete(`${kind}\0${file}`);
685
+ if (isMissingFileError(error)) {
686
+ throw builtArtifactReadError(`built server module artifact for ${file}`, artifactPath, error);
687
+ }
595
688
  throw error;
596
689
  });
597
690
  runtime.serverModuleArtifactLoads.set(`${kind}\0${file}`, loaded);