@reckona/mreact-router 0.0.174 → 0.0.176

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 (64) hide show
  1. package/dist/adapters/cloudflare.d.ts.map +1 -1
  2. package/dist/adapters/cloudflare.js +5 -49
  3. package/dist/adapters/cloudflare.js.map +1 -1
  4. package/dist/build.d.ts +1 -0
  5. package/dist/build.d.ts.map +1 -1
  6. package/dist/build.js +90 -0
  7. package/dist/build.js.map +1 -1
  8. package/dist/built-assets.d.ts +11 -0
  9. package/dist/built-assets.d.ts.map +1 -0
  10. package/dist/built-assets.js +130 -0
  11. package/dist/built-assets.js.map +1 -0
  12. package/dist/built-runtime.d.ts +53 -0
  13. package/dist/built-runtime.d.ts.map +1 -0
  14. package/dist/built-runtime.js +178 -0
  15. package/dist/built-runtime.js.map +1 -0
  16. package/dist/built-server-module-artifacts.d.ts +19 -0
  17. package/dist/built-server-module-artifacts.d.ts.map +1 -0
  18. package/dist/built-server-module-artifacts.js +217 -0
  19. package/dist/built-server-module-artifacts.js.map +1 -0
  20. package/dist/client-manifest-assets.d.ts +16 -0
  21. package/dist/client-manifest-assets.d.ts.map +1 -0
  22. package/dist/client-manifest-assets.js +60 -0
  23. package/dist/client-manifest-assets.js.map +1 -0
  24. package/dist/client.d.ts.map +1 -1
  25. package/dist/client.js +31 -3
  26. package/dist/client.js.map +1 -1
  27. package/dist/node-server.d.ts +29 -0
  28. package/dist/node-server.d.ts.map +1 -0
  29. package/dist/node-server.js +81 -0
  30. package/dist/node-server.js.map +1 -0
  31. package/dist/render.d.ts +9 -0
  32. package/dist/render.d.ts.map +1 -1
  33. package/dist/render.js +20 -41
  34. package/dist/render.js.map +1 -1
  35. package/dist/route-dispatch.d.ts +2 -0
  36. package/dist/route-dispatch.d.ts.map +1 -0
  37. package/dist/route-dispatch.js +16 -0
  38. package/dist/route-dispatch.js.map +1 -0
  39. package/dist/route-loader-runtime.d.ts +22 -0
  40. package/dist/route-loader-runtime.d.ts.map +1 -0
  41. package/dist/route-loader-runtime.js +30 -0
  42. package/dist/route-loader-runtime.js.map +1 -0
  43. package/dist/routes.d.ts +2 -0
  44. package/dist/routes.d.ts.map +1 -1
  45. package/dist/routes.js +48 -1
  46. package/dist/routes.js.map +1 -1
  47. package/dist/serve.d.ts +4 -3
  48. package/dist/serve.d.ts.map +1 -1
  49. package/dist/serve.js +84 -582
  50. package/dist/serve.js.map +1 -1
  51. package/package.json +11 -11
  52. package/src/adapters/cloudflare.ts +5 -60
  53. package/src/build.ts +143 -0
  54. package/src/built-assets.ts +164 -0
  55. package/src/built-runtime.ts +312 -0
  56. package/src/built-server-module-artifacts.ts +340 -0
  57. package/src/client-manifest-assets.ts +92 -0
  58. package/src/client.ts +31 -3
  59. package/src/node-server.ts +129 -0
  60. package/src/render.ts +38 -60
  61. package/src/route-dispatch.ts +17 -0
  62. package/src/route-loader-runtime.ts +54 -0
  63. package/src/routes.ts +70 -1
  64. package/src/serve.ts +105 -863
package/dist/serve.js CHANGED
@@ -1,16 +1,18 @@
1
- import { createServer } from "node:http";
2
- import { createHash } from "node:crypto";
3
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
- import { dirname, isAbsolute, join, normalize, sep } from "node:path";
5
- import { createRouteMatcher, } from "./routes.js";
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { builtClientAssetPathname, clearBuiltPublicAssetCacheForTest, getBuiltPublicAssetCacheSizeForTest, readBuiltClientAsset, readBuiltPublicAsset, } from "./built-assets.js";
4
+ import { materializeBuiltRuntime, mergeBuiltRuntimeImportPolicy, readBuiltImportPolicyText, } from "./built-runtime.js";
5
+ import { allBuiltServerModuleFiles, loadBuiltServerModuleArtifacts, loadBuiltServerModuleArtifactsForRequest, } from "./built-server-module-artifacts.js";
6
+ import {} from "./routes.js";
6
7
  import { preloadBuiltRequestModules, renderAppRequest, resolveAppRouterMiddleware, } from "./render.js";
7
- import { bytesResponse, htmlResponse, nodeRequestToWebRequest, rawNodeRequestUrl, sendResponse, } from "./http.js";
8
- import { emitRouterLog, logDurationMs, logError, logNow, nodeRequestPath, requestLogFields, } from "./logger.js";
8
+ import { bytesResponse, htmlResponse, } from "./http.js";
9
+ import { emitRouterLog, logDurationMs, logNow, } from "./logger.js";
10
+ import { startNodeRequestServer } from "./node-server.js";
9
11
  import { builtAppRuntimePreloadPlan } from "./preload-policy.js";
10
- import { routeShellCandidates } from "./route-shells.js";
11
12
  import { normalizeRoutePath } from "./route-path.js";
12
13
  const builtRuntimeCache = new Map();
13
- const builtPublicAssetCache = new Map();
14
+ const builtRuntimeReadInflight = new Map();
15
+ let builtRuntimeMaterializeCountForTest = 0;
14
16
  let warnedImplicitHostTrust = false;
15
17
  export function resolveRequestHost(options) {
16
18
  const raw = options.rawHost;
@@ -284,196 +286,40 @@ export async function startServer(options) {
284
286
  importPolicy: options.importPolicy,
285
287
  outDir: options.outDir,
286
288
  });
287
- const server = createServer(async (incoming, outgoing) => {
288
- const startedAt = logNow();
289
- const fallbackRequestFields = {
290
- method: incoming.method ?? "GET",
291
- path: nodeRequestPath(incoming.url),
292
- runtime: "node",
293
- };
294
- try {
295
- const fallbackHost = `${options.hostname ?? "127.0.0.1"}:${options.port}`;
296
- const host = resolveRequestHost({
297
- allowedHosts: options.allowedHosts,
298
- fallbackHost,
299
- hostPolicy: options.hostPolicy,
300
- rawHost: incoming.headers.host,
301
- });
302
- const origin = `http://${host}`;
303
- const request = nodeRequestToWebRequest(incoming, origin);
304
- const logFields = requestLogFields(request, "node");
305
- emitRouterLog(options.logger, "info", {
306
- ...logFields,
307
- type: "router:request:start",
308
- });
309
- const response = await runtime.render(request, {
310
- instrumentation: options.instrumentation,
311
- logger: options.logger,
312
- onResponse: options.onResponse,
313
- prerenderStore: options.prerenderStore,
314
- routeCache: options.routeCache,
315
- serverActions: options.serverActions,
316
- ...(options.sinkStrategy === undefined ? {} : { sinkStrategy: options.sinkStrategy }),
317
- });
318
- emitRouterLog(options.logger, "info", {
319
- ...logFields,
320
- durationMs: logDurationMs(startedAt),
321
- status: response.status,
322
- type: "router:request:end",
323
- });
324
- await sendResponse(outgoing, response);
325
- }
326
- catch (error) {
327
- // Log the full stack to stderr for operator visibility; never
328
- // place it in the response body where attackers can scrape it
329
- // (Issue 071). The errorHandler hook lets embedders customize
330
- // the public response shape while still benefiting from the
331
- // server-side log.
332
- emitRouterLog(options.logger, "error", {
333
- ...fallbackRequestFields,
334
- durationMs: logDurationMs(startedAt),
335
- error: logError(error),
336
- type: "router:request:error",
337
- });
338
- if (options.logger === undefined) {
339
- console.error("[mreact] startServer request failed:", error);
340
- }
341
- const payload = options.errorHandler
342
- ? options.errorHandler(error)
343
- : { body: "Internal Server Error", status: 500 };
344
- outgoing.statusCode = payload.status;
345
- outgoing.setHeader("content-type", payload.headers?.["content-type"] ?? "text/plain; charset=utf-8");
346
- for (const [name, value] of Object.entries(payload.headers ?? {})) {
347
- if (name.toLowerCase() === "content-type")
348
- continue;
349
- outgoing.setHeader(name, value);
350
- }
351
- outgoing.end(payload.body);
352
- }
289
+ return await startNodeRequestServer({
290
+ allowedHosts: options.allowedHosts,
291
+ errorHandler: options.errorHandler,
292
+ hostname: options.hostname,
293
+ hostPolicy: options.hostPolicy,
294
+ logger: options.logger,
295
+ onUpgrade: options.onUpgrade,
296
+ port: options.port,
297
+ resolveHost: resolveRequestHost,
298
+ render: (request) => runtime.render(request, {
299
+ instrumentation: options.instrumentation,
300
+ logger: options.logger,
301
+ onResponse: options.onResponse,
302
+ prerenderStore: options.prerenderStore,
303
+ routeCache: options.routeCache,
304
+ serverActions: options.serverActions,
305
+ ...(options.sinkStrategy === undefined ? {} : { sinkStrategy: options.sinkStrategy }),
306
+ }),
353
307
  });
354
- if (options.onUpgrade !== undefined) {
355
- server.on("upgrade", options.onUpgrade);
356
- }
357
- await new Promise((resolve) => server.listen(options.port, options.hostname ?? "127.0.0.1", resolve));
358
- const address = server.address();
359
- const port = typeof address === "object" && address !== null ? address.port : options.port;
360
- return {
361
- server,
362
- url: `http://${options.hostname ?? "127.0.0.1"}:${port}`,
363
- close: () => new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))),
364
- };
365
- }
366
- async function readBuiltClientAsset(outDir, pathname, allowedPaths) {
367
- const clientPrefix = "/_mreact/client/";
368
- const normalized = safeBuiltClientAssetPath(pathname.slice(clientPrefix.length));
369
- if (normalized === undefined || !allowedPaths.has(normalized)) {
370
- return new Response("Not Found", { status: 404 });
371
- }
372
- try {
373
- const code = await readFile(join(outDir, "client", normalized), "utf8");
374
- return new Response(code, {
375
- headers: clientAssetHeaders(normalized),
376
- });
377
- }
378
- catch {
379
- return new Response("Not Found", { status: 404 });
380
- }
381
308
  }
382
- function builtClientAssetPathname(request, url) {
383
- const rawUrl = rawNodeRequestUrl(request);
384
- const rawPathname = rawUrl?.split(/[?#]/, 1)[0];
385
- const pathname = rawPathname === undefined || rawPathname === "" ? url.pathname : rawPathname;
386
- const normalizedPathname = pathname.startsWith("/") ? pathname : `/${pathname}`;
387
- return normalizedPathname.startsWith("/_mreact/client/") ? normalizedPathname : undefined;
388
- }
389
- function safeBuiltClientAssetPath(relativePath) {
390
- let decoded;
391
- try {
392
- decoded = decodeURIComponent(relativePath);
393
- }
394
- catch {
395
- return undefined;
396
- }
397
- if (decoded.includes("\\") || decoded.includes("\0")) {
398
- return undefined;
399
- }
400
- if (decoded.split("/").some((segment) => segment === "..")) {
401
- return undefined;
402
- }
403
- const normalized = normalize(decoded);
404
- if (isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${sep}`)) {
405
- return undefined;
406
- }
407
- return normalized;
408
- }
409
- function builtClientAssetPaths(manifest) {
410
- const paths = new Set(["manifest.json"]);
411
- for (const route of manifest.routes) {
412
- for (const asset of [
413
- route.script,
414
- route.sourceMap,
415
- route.navigationScript,
416
- ...(route.css ?? []),
417
- ...(route.imports ?? []),
418
- ]) {
419
- const path = safeClientManifestAssetPath(asset);
420
- if (path !== undefined) {
421
- paths.add(path);
422
- }
423
- }
424
- }
425
- for (const asset of manifest.assets ?? []) {
426
- const path = safeClientManifestAssetPath(asset);
427
- if (path !== undefined) {
428
- paths.add(path);
429
- }
430
- }
431
- return paths;
309
+ export const __readBuiltPublicAssetForTest = readBuiltPublicAsset;
310
+ export function __clearBuiltRuntimeCacheForTest() {
311
+ builtRuntimeCache.clear();
312
+ builtRuntimeReadInflight.clear();
313
+ builtRuntimeMaterializeCountForTest = 0;
432
314
  }
433
- function safeClientManifestAssetPath(asset) {
434
- if (asset === undefined || asset === "" || asset.startsWith("/") || asset.includes("\\")) {
435
- return undefined;
436
- }
437
- const segments = asset.split("/");
438
- return segments.some((segment) => segment === "" || segment === "." || segment === "..")
439
- ? undefined
440
- : segments.join("/");
315
+ export function __getBuiltRuntimeMaterializeCountForTest() {
316
+ return builtRuntimeMaterializeCountForTest;
441
317
  }
442
- async function readBuiltPublicAsset(outDir, pathname) {
443
- const relativePath = pathname.startsWith("/") ? pathname.slice(1) : pathname;
444
- if (relativePath === "") {
445
- return undefined;
446
- }
447
- const normalized = normalize(relativePath);
448
- if (isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
449
- return undefined;
450
- }
451
- try {
452
- const cacheKey = `${outDir}\0${normalized}`;
453
- const cached = builtPublicAssetCache.get(cacheKey);
454
- if (cached !== undefined) {
455
- return bytesResponse(cached.bytes, {
456
- headers: cached.headers,
457
- });
458
- }
459
- const bytes = await readFile(join(outDir, "client", "public", normalized));
460
- const headers = publicAssetHeaders(normalized);
461
- builtPublicAssetCache.set(cacheKey, {
462
- bytes,
463
- headers,
464
- });
465
- return bytesResponse(bytes, { headers });
466
- }
467
- catch {
468
- return undefined;
469
- }
470
- }
471
- export const __readBuiltPublicAssetForTest = readBuiltPublicAsset;
472
318
  export function __clearBuiltPublicAssetCacheForTest() {
473
- builtPublicAssetCache.clear();
319
+ clearBuiltPublicAssetCacheForTest();
474
320
  }
475
321
  export function __getBuiltPublicAssetCacheSizeForTest() {
476
- return builtPublicAssetCache.size;
322
+ return getBuiltPublicAssetCacheSizeForTest();
477
323
  }
478
324
  async function readBuiltRuntime(options) {
479
325
  const outDir = options.outDir;
@@ -483,6 +329,36 @@ async function readBuiltRuntime(options) {
483
329
  if (options.immutable === true && cached !== undefined) {
484
330
  return cached.runtime;
485
331
  }
332
+ if (cached === undefined) {
333
+ const inflight = builtRuntimeReadInflight.get(cacheKey);
334
+ if (inflight !== undefined) {
335
+ return inflight;
336
+ }
337
+ const runtime = readBuiltRuntimeUncached({
338
+ cacheKey,
339
+ cached,
340
+ outDir,
341
+ runtimeDir,
342
+ });
343
+ builtRuntimeReadInflight.set(cacheKey, runtime);
344
+ void runtime
345
+ .finally(() => {
346
+ if (builtRuntimeReadInflight.get(cacheKey) === runtime) {
347
+ builtRuntimeReadInflight.delete(cacheKey);
348
+ }
349
+ })
350
+ .catch(() => { });
351
+ return runtime;
352
+ }
353
+ return readBuiltRuntimeUncached({
354
+ cacheKey,
355
+ cached,
356
+ outDir,
357
+ runtimeDir,
358
+ });
359
+ }
360
+ async function readBuiltRuntimeUncached(options) {
361
+ const { cacheKey, cached, outDir, runtimeDir } = options;
486
362
  const serverManifestPath = join(outDir, "server", "manifest.json");
487
363
  const clientManifestPath = join(outDir, "client", "manifest.json");
488
364
  const importPolicyPath = join(outDir, "server", "import-policy.json");
@@ -502,6 +378,9 @@ async function readBuiltRuntime(options) {
502
378
  clientManifestPath,
503
379
  importPolicyText,
504
380
  importPolicyPath,
381
+ onMaterialize() {
382
+ builtRuntimeMaterializeCountForTest += 1;
383
+ },
505
384
  outDir,
506
385
  runtimeDir,
507
386
  serverManifestText,
@@ -513,137 +392,12 @@ async function readBuiltRuntime(options) {
513
392
  runtime,
514
393
  serverManifestText,
515
394
  });
516
- return runtime;
517
- }
518
- async function materializeBuiltRuntime(options) {
519
- const serverManifest = parseBuiltJsonArtifact(options.serverManifestText, options.serverManifestPath, "built app server manifest");
520
- const clientManifest = parseBuiltJsonArtifact(options.clientManifestText, options.clientManifestPath, "built app client manifest");
521
- const appDir = await materializeBuiltServerApp(options.runtimeDir, serverManifest);
522
- const projectRoot = appDir;
523
- const routesDir = join(projectRoot, serverManifest.routesDir ?? "");
524
- const routes = serverManifest.routes.map((route) => ({
525
- ...route,
526
- file: join(projectRoot, route.file),
527
- }));
528
- const prerenderedRoutes = new Map(Object.entries(serverManifest.prerenderedRoutes ?? {}));
529
- const prerenderableRoutes = new Set(prerenderedRoutes.keys());
530
- const prerenderLocks = new Map();
531
- const serverModules = new Map(Object.entries(serverManifest.serverModules ?? {}).map(([file, artifact]) => [
532
- join(appDir, file),
533
- artifact,
534
- ]));
535
- const serverModuleFiles = new Map(Object.entries(serverManifest.serverModuleFiles ?? {}).map(([file, artifactFile]) => [
536
- join(appDir, file),
537
- join(options.outDir, "server", safeManifestFilePath(artifactFile)),
538
- ]));
539
- const serverModuleRequestFiles = new Map(Object.entries(serverManifest.serverModuleRequestFiles ?? {}).map(([file, artifactFile]) => [
540
- join(appDir, file),
541
- join(options.outDir, "server", safeManifestFilePath(artifactFile)),
542
- ]));
543
- const serverModuleRenderFiles = new Map(Object.entries(serverManifest.serverModuleRenderFiles ?? {}).map(([file, artifactFile]) => [
544
- join(appDir, file),
545
- join(options.outDir, "server", safeManifestFilePath(artifactFile)),
546
- ]));
547
- const serverSourceFiles = new Map(Object.entries(serverManifest.files).map(([file, source]) => [join(appDir, file), source]));
548
- const serverActionReferencesByFile = new Map(Object.entries(serverManifest.routeServerActionReferences ?? {}).map(([file, references]) => [
549
- join(appDir, file),
550
- references,
551
- ]));
552
- const routeMatcher = createRouteMatcher(routes, serverManifest.routeMatcher);
553
- const clientScripts = new Map(clientManifest.routes.flatMap((route) => route.client && route.script !== undefined ? [[route.path, route.script]] : []));
554
- const clientStyles = new Map(clientManifest.routes.flatMap((route) => route.css !== undefined && route.css.length > 0 ? [[route.path, route.css]] : []));
555
- const clientStylesByFile = new Map((clientManifest.styles ?? []).flatMap((style) => style.css !== undefined && style.css.length > 0
556
- ? [[join(routesDir, style.file), style.css]]
557
- : []));
558
- const navigationScripts = new Map(clientManifest.routes.flatMap((route) => route.navigation === true && route.navigationScript !== undefined
559
- ? [[route.path, route.navigationScript]]
560
- : []));
561
- const hasMiddleware = serverSourceFiles.has(join(routesDir, "middleware.ts")) ||
562
- serverSourceFiles.has(join(routesDir, "middleware.mreact.ts"));
563
- const serverModuleCacheVersion = createHash("sha256")
564
- .update(options.serverManifestText)
565
- .update("\0")
566
- .update(options.clientManifestText)
567
- .digest("hex")
568
- .slice(0, 16);
569
- const allowedSourceDirs = (serverManifest.allowedSourceDirs ?? [""]).map((directory) => join(projectRoot, directory));
570
- const generatedImportPolicy = builtGeneratedImportPolicy(options.importPolicyText, options.importPolicyPath);
571
- return {
572
- appDir: routesDir,
573
- allowedSourceDirs,
574
- ...(serverManifest.assetBaseUrl === undefined
575
- ? {}
576
- : { assetBaseUrl: serverManifest.assetBaseUrl }),
577
- clientAssetPaths: builtClientAssetPaths(clientManifest),
578
- clientScripts,
579
- clientStylesByFile,
580
- clientStyles,
581
- ...(generatedImportPolicy === undefined ? {} : { generatedImportPolicy }),
582
- hasMiddleware,
583
- navigationScripts,
584
- projectRoot,
585
- ...(serverManifest.publicAssetBaseUrl === undefined
586
- ? {}
587
- : { publicAssetBaseUrl: serverManifest.publicAssetBaseUrl }),
588
- prerenderableRoutes,
589
- prerenderLocks,
590
- prerenderedRoutes,
591
- routeMatcher,
592
- routes,
593
- serverActionReferencesByFile,
594
- ...(serverManifest.serverActionManifest === undefined
595
- ? {}
596
- : { serverActionManifest: serverManifest.serverActionManifest }),
597
- serverModuleArtifactLoads: new Map(),
598
- serverModuleClosureFiles: new Map(),
599
- serverModuleFiles,
600
- serverModuleRenderFiles,
601
- serverModuleRequestFiles,
602
- serverModules,
603
- serverModuleCacheVersion,
604
- serverSourceFiles,
605
- };
606
- }
607
- async function readBuiltImportPolicyText(outDir) {
608
- const policyPath = join(outDir, "server", "import-policy.json");
609
- try {
610
- return await readFile(policyPath, "utf8");
611
- }
612
- catch (error) {
613
- if (isMissingFileError(error)) {
614
- return undefined;
395
+ runtime.catch(() => {
396
+ if (builtRuntimeCache.get(cacheKey)?.runtime === runtime) {
397
+ builtRuntimeCache.delete(cacheKey);
615
398
  }
616
- throw builtArtifactReadError("built app import policy", policyPath, error);
617
- }
618
- }
619
- function builtGeneratedImportPolicy(importPolicyText, importPolicyPath) {
620
- if (importPolicyText === undefined) {
621
- return undefined;
622
- }
623
- const artifact = parseBuiltJsonArtifact(importPolicyText, importPolicyPath, "built app import policy");
624
- const runtimePackages = Array.isArray(artifact.runtimePackages)
625
- ? artifact.runtimePackages.filter((name) => typeof name === "string")
626
- : [];
627
- return runtimePackages.length === 0 ? undefined : { allowedPackages: runtimePackages };
628
- }
629
- function mergeBuiltRuntimeImportPolicy(runtime, importPolicy) {
630
- const generatedImportPolicy = runtime.generatedImportPolicy;
631
- if (generatedImportPolicy === undefined) {
632
- return importPolicy;
633
- }
634
- const allowedPackages = [
635
- ...new Set([
636
- ...(generatedImportPolicy.allowedPackages ?? []),
637
- ...(importPolicy?.allowedPackages ?? []),
638
- ]),
639
- ];
640
- return {
641
- ...(allowedPackages.length === 0 ? {} : { allowedPackages }),
642
- ...(importPolicy?.allowedSourceDirs === undefined
643
- ? {}
644
- : { allowedSourceDirs: importPolicy.allowedSourceDirs }),
645
- ...(importPolicy?.projectRoot === undefined ? {} : { projectRoot: importPolicy.projectRoot }),
646
- };
399
+ });
400
+ return runtime;
647
401
  }
648
402
  function isMissingFileError(error) {
649
403
  return (typeof error === "object" &&
@@ -664,201 +418,6 @@ function builtArtifactReadError(label, artifactPath, error) {
664
418
  const detail = error instanceof Error && error.message !== "" ? `: ${error.message}` : "";
665
419
  return new Error(`${prefix} ${label}: ${artifactPath}${detail}`, { cause: error });
666
420
  }
667
- function parseBuiltJsonArtifact(text, artifactPath, label) {
668
- try {
669
- return JSON.parse(text);
670
- }
671
- catch (error) {
672
- const detail = error instanceof Error && error.message !== "" ? `: ${error.message}` : "";
673
- throw new Error(`Invalid ${label}: ${artifactPath}${detail}`, { cause: error });
674
- }
675
- }
676
- async function loadBuiltServerModuleArtifacts(runtime, files, kind = "all") {
677
- for (const file of files) {
678
- await loadBuiltServerModuleArtifact(runtime, file, kind);
679
- }
680
- }
681
- async function loadBuiltServerModuleArtifact(runtime, file, kind = "all") {
682
- if (kind === "all") {
683
- await loadBuiltServerModuleArtifact(runtime, file, "request");
684
- await loadBuiltServerModuleArtifact(runtime, file, "render");
685
- return;
686
- }
687
- const artifactPath = kind === "request"
688
- ? runtime.serverModuleRequestFiles.get(file) ?? runtime.serverModuleFiles.get(file)
689
- : runtime.serverModuleRenderFiles.get(file) ?? runtime.serverModuleFiles.get(file);
690
- if (artifactPath === undefined) {
691
- return;
692
- }
693
- const cached = runtime.serverModuleArtifactLoads.get(`${kind}\0${file}`);
694
- if (cached !== undefined) {
695
- await cached;
696
- return;
697
- }
698
- const loaded = readFile(artifactPath, "utf8")
699
- .then((text) => {
700
- const existing = runtime.serverModules.get(file) ?? {};
701
- runtime.serverModules.set(file, mergeBuiltServerModuleArtifacts(existing, hydrateBuiltServerModuleArtifact(parseBuiltJsonArtifact(text, artifactPath, `built server module artifact for ${file}`), builtServerDirForArtifactPath(artifactPath))));
702
- })
703
- .catch((error) => {
704
- runtime.serverModuleArtifactLoads.delete(`${kind}\0${file}`);
705
- if (isMissingFileError(error)) {
706
- throw builtArtifactReadError(`built server module artifact for ${file}`, artifactPath, error);
707
- }
708
- throw error;
709
- });
710
- runtime.serverModuleArtifactLoads.set(`${kind}\0${file}`, loaded);
711
- await loaded;
712
- }
713
- function allBuiltServerModuleFiles(runtime) {
714
- return new Set([
715
- ...runtime.serverModuleFiles.keys(),
716
- ...runtime.serverModuleRequestFiles.keys(),
717
- ...runtime.serverModuleRenderFiles.keys(),
718
- ]);
719
- }
720
- function builtServerDirForArtifactPath(artifactPath) {
721
- const marker = `${sep}server-modules${sep}`;
722
- const index = artifactPath.lastIndexOf(marker);
723
- return index === -1 ? dirname(dirname(artifactPath)) : artifactPath.slice(0, index);
724
- }
725
- function hydrateBuiltServerModuleArtifact(artifact, serverDir) {
726
- return {
727
- ...(artifact.analysis === undefined ? {} : { analysis: artifact.analysis }),
728
- ...(artifact.loader === undefined
729
- ? {}
730
- : { loader: hydrateBuiltServerModuleOutput(artifact.loader, serverDir) }),
731
- ...(artifact.routeMetadata === undefined
732
- ? {}
733
- : { routeMetadata: hydrateBuiltServerModuleOutput(artifact.routeMetadata, serverDir) }),
734
- ...(artifact.request === undefined
735
- ? {}
736
- : { request: hydrateBuiltServerModuleOutput(artifact.request, serverDir) }),
737
- ...(artifact.stream === undefined
738
- ? {}
739
- : { stream: hydrateBuiltServerModuleOutput(artifact.stream, serverDir) }),
740
- ...(artifact.string === undefined
741
- ? {}
742
- : { string: hydrateBuiltServerModuleOutput(artifact.string, serverDir) }),
743
- };
744
- }
745
- function hydrateBuiltServerModuleOutput(output, serverDir) {
746
- if (output.moduleFile === undefined || isAbsolute(output.moduleFile)) {
747
- return output;
748
- }
749
- return {
750
- ...output,
751
- moduleFile: join(serverDir, safeManifestFilePath(output.moduleFile)),
752
- };
753
- }
754
- function mergeBuiltServerModuleArtifacts(existing, loaded) {
755
- return {
756
- ...existing,
757
- ...loaded,
758
- };
759
- }
760
- async function loadBuiltServerModuleArtifactsForRequest(runtime, routeFile, options = {}) {
761
- const roots = [
762
- join(runtime.appDir, "middleware.ts"),
763
- join(runtime.appDir, "middleware.mreact.ts"),
764
- ...(routeFile === undefined
765
- ? []
766
- : [
767
- routeFile,
768
- ...(options.includeShells === false ? [] : shellFilesForRoute(runtime, routeFile)),
769
- ]),
770
- ];
771
- const seen = new Set();
772
- for (const file of roots) {
773
- await loadBuiltServerModuleArtifactClosure(runtime, file, seen, "request");
774
- }
775
- if (options.includeRender === true) {
776
- seen.clear();
777
- for (const file of roots) {
778
- await loadBuiltServerModuleArtifactClosure(runtime, file, seen, "render");
779
- }
780
- }
781
- }
782
- async function loadBuiltServerModuleArtifactClosure(runtime, file, seen, kind) {
783
- for (const closureFile of builtServerModuleClosureFiles(runtime, file)) {
784
- if (seen.has(closureFile)) {
785
- continue;
786
- }
787
- seen.add(closureFile);
788
- await loadBuiltServerModuleArtifact(runtime, closureFile, kind);
789
- }
790
- }
791
- function builtServerModuleClosureFiles(runtime, file) {
792
- const cached = runtime.serverModuleClosureFiles.get(file);
793
- if (cached !== undefined) {
794
- return cached;
795
- }
796
- const closure = [];
797
- collectBuiltServerModuleClosureFiles(runtime, file, new Set(), closure);
798
- runtime.serverModuleClosureFiles.set(file, closure);
799
- return closure;
800
- }
801
- function collectBuiltServerModuleClosureFiles(runtime, file, seen, closure) {
802
- if (seen.has(file)) {
803
- return;
804
- }
805
- seen.add(file);
806
- closure.push(file);
807
- const source = runtime.serverSourceFiles.get(file);
808
- if (source === undefined) {
809
- return;
810
- }
811
- for (const specifier of localServerModuleSpecifiers(source)) {
812
- const resolved = resolveBuiltLocalServerSourceImport(runtime, file, specifier);
813
- if (resolved !== undefined) {
814
- collectBuiltServerModuleClosureFiles(runtime, resolved, seen, closure);
815
- }
816
- }
817
- }
818
- const localServerModuleImportPattern = /\b(?:import|export)\s+(?:type\s+)?(?:[^"']*?\s+from\s*)?["'](?<source>\.{1,2}\/[^"']+)["']/g;
819
- function localServerModuleSpecifiers(code) {
820
- const specifiers = new Set();
821
- localServerModuleImportPattern.lastIndex = 0;
822
- for (const match of code.matchAll(localServerModuleImportPattern)) {
823
- const source = match.groups?.source;
824
- if (source !== undefined) {
825
- specifiers.add(source);
826
- }
827
- }
828
- return Array.from(specifiers);
829
- }
830
- function resolveBuiltLocalServerSourceImport(runtime, fromFile, specifier) {
831
- const base = join(dirname(fromFile), specifier);
832
- for (const candidate of localServerSourceImportCandidates(base)) {
833
- if (runtime.serverSourceFiles.has(candidate)) {
834
- return candidate;
835
- }
836
- }
837
- return undefined;
838
- }
839
- function localServerSourceImportCandidates(base) {
840
- const candidates = [base];
841
- if (base.endsWith(".js")) {
842
- const withoutJs = base.slice(0, -".js".length);
843
- candidates.push(`${withoutJs}.ts`, `${withoutJs}.tsx`, `${withoutJs}.mreact.tsx`);
844
- }
845
- else if (base.endsWith(".jsx")) {
846
- const withoutJsx = base.slice(0, -".jsx".length);
847
- candidates.push(`${withoutJsx}.tsx`, `${withoutJsx}.mreact.tsx`);
848
- }
849
- else if (base.endsWith(".mreact")) {
850
- candidates.push(`${base}.tsx`);
851
- }
852
- else {
853
- candidates.push(`${base}.ts`, `${base}.tsx`, `${base}.mreact.tsx`, join(base, "index.ts"), join(base, "index.tsx"), join(base, "index.mreact.tsx"));
854
- }
855
- return candidates;
856
- }
857
- function shellFilesForRoute(runtime, routeFile) {
858
- return routeShellCandidates(runtime.appDir, routeFile)
859
- .map((candidate) => candidate.file)
860
- .filter((file) => runtime.serverSourceFiles.has(file));
861
- }
862
421
  async function readPrerenderedRoute(runtime, path, store) {
863
422
  const stored = await store?.get(path);
864
423
  if (stored !== undefined) {
@@ -875,6 +434,13 @@ function renderBuiltDynamicResponse(options) {
875
434
  return renderAppRequest(builtRenderAppRequestOptions(options));
876
435
  }
877
436
  function builtRenderAppRequestOptions(options) {
437
+ const serverRenderArtifactLoader = {
438
+ async load(routeFile) {
439
+ await loadBuiltServerModuleArtifactsForRequest(options.runtime, routeFile, {
440
+ includeRender: true,
441
+ });
442
+ },
443
+ };
878
444
  const renderOptions = {
879
445
  appDir: options.runtime.appDir,
880
446
  assetBaseUrl: options.runtime.assetBaseUrl,
@@ -895,11 +461,7 @@ function builtRenderAppRequestOptions(options) {
895
461
  routeMatcher: options.runtime.routeMatcher,
896
462
  requestUrl: options.requestUrl,
897
463
  routes: options.runtime.routes,
898
- __mreactLoadServerRenderArtifacts: async (routeFile) => {
899
- await loadBuiltServerModuleArtifactsForRequest(options.runtime, routeFile, {
900
- includeRender: true,
901
- });
902
- },
464
+ serverRenderArtifactLoader,
903
465
  serverModules: options.runtime.serverModules,
904
466
  serverModuleCacheVersion: options.runtime.serverModuleCacheVersion,
905
467
  serverSourceFiles: options.runtime.serverSourceFiles,
@@ -986,64 +548,4 @@ async function cloneResponse(response) {
986
548
  status: response.status,
987
549
  });
988
550
  }
989
- async function materializeBuiltServerApp(runtimeDir, manifest) {
990
- const appDir = join(runtimeDir, "app");
991
- await rm(appDir, { force: true, recursive: true });
992
- await Promise.all(Object.entries(manifest.files).map(async ([file, code]) => {
993
- const outputFile = join(appDir, safeManifestFilePath(file));
994
- await mkdir(dirname(outputFile), { recursive: true });
995
- await writeFile(outputFile, code);
996
- }));
997
- return appDir;
998
- }
999
- function safeManifestFilePath(pathname) {
1000
- const normalized = normalize(pathname);
1001
- if (isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
1002
- throw new Error(`Invalid built app manifest file path: ${pathname}`);
1003
- }
1004
- return normalized;
1005
- }
1006
- function clientAssetHeaders(pathname) {
1007
- if (pathname === "manifest.json") {
1008
- return {
1009
- "cache-control": "no-cache",
1010
- "content-type": "application/json; charset=utf-8",
1011
- };
1012
- }
1013
- return {
1014
- "cache-control": "public, max-age=31536000, immutable",
1015
- "content-type": pathname.endsWith(".css")
1016
- ? "text/css; charset=utf-8"
1017
- : "text/javascript; charset=utf-8",
1018
- };
1019
- }
1020
- function publicAssetHeaders(pathname) {
1021
- return {
1022
- "cache-control": "public, max-age=3600",
1023
- "content-type": publicAssetContentType(pathname),
1024
- };
1025
- }
1026
- function publicAssetContentType(pathname) {
1027
- if (pathname.endsWith(".css"))
1028
- return "text/css; charset=utf-8";
1029
- if (pathname.endsWith(".html"))
1030
- return "text/html; charset=utf-8";
1031
- if (pathname.endsWith(".js"))
1032
- return "text/javascript; charset=utf-8";
1033
- if (pathname.endsWith(".json"))
1034
- return "application/json; charset=utf-8";
1035
- if (pathname.endsWith(".svg"))
1036
- return "image/svg+xml";
1037
- if (pathname.endsWith(".png"))
1038
- return "image/png";
1039
- if (pathname.endsWith(".jpg") || pathname.endsWith(".jpeg"))
1040
- return "image/jpeg";
1041
- if (pathname.endsWith(".webp"))
1042
- return "image/webp";
1043
- if (pathname.endsWith(".ico"))
1044
- return "image/x-icon";
1045
- if (pathname.endsWith(".txt"))
1046
- return "text/plain; charset=utf-8";
1047
- return "application/octet-stream";
1048
- }
1049
551
  //# sourceMappingURL=serve.js.map