astro 7.2.1 → 7.2.3

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 (166) hide show
  1. package/dist/actions/handler.d.ts +6 -12
  2. package/dist/actions/handler.js +30 -40
  3. package/dist/actions/load.d.ts +12 -0
  4. package/dist/actions/load.js +55 -0
  5. package/dist/actions/runtime/entrypoints/server.js +5 -4
  6. package/dist/actions/runtime/server.js +8 -6
  7. package/dist/assets/fonts/constants.d.ts +8 -0
  8. package/dist/assets/fonts/constants.js +2 -0
  9. package/dist/assets/fonts/providers/index.d.ts +1 -1
  10. package/dist/assets/fonts/providers/index.js +2 -12
  11. package/dist/assets/fonts/vite-plugin-fonts.js +3 -1
  12. package/dist/assets/utils/node.js +35 -3
  13. package/dist/cli/dev/index.js +2 -2
  14. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  15. package/dist/cli/preview/index.js +1 -1
  16. package/dist/cli/server.js +4 -4
  17. package/dist/container/environment.d.ts +20 -0
  18. package/dist/container/environment.js +106 -0
  19. package/dist/container/index.js +65 -32
  20. package/dist/content/content-layer.js +3 -3
  21. package/dist/content/data-store-writer.d.ts +7 -10
  22. package/dist/content/data-store-writer.js +62 -27
  23. package/dist/content/data-store.d.ts +20 -3
  24. package/dist/content/data-store.js +28 -7
  25. package/dist/content/loaders/file.js +19 -4
  26. package/dist/content/loaders/glob.js +15 -2
  27. package/dist/content/mutable-data-store.js +15 -10
  28. package/dist/content/runtime.d.ts +3 -2
  29. package/dist/content/runtime.js +43 -26
  30. package/dist/core/app/app.d.ts +0 -2
  31. package/dist/core/app/app.js +0 -7
  32. package/dist/core/app/base.d.ts +32 -20
  33. package/dist/core/app/base.js +76 -66
  34. package/dist/core/app/dev-facade.d.ts +27 -0
  35. package/dist/core/app/dev-facade.js +51 -0
  36. package/dist/core/app/entrypoints/index.d.ts +0 -1
  37. package/dist/core/app/entrypoints/index.js +0 -2
  38. package/dist/core/app/entrypoints/virtual/dev.js +24 -19
  39. package/dist/core/app/node.js +13 -14
  40. package/dist/core/app/prepare-response.d.ts +1 -1
  41. package/dist/core/app/validate-headers.js +7 -3
  42. package/dist/core/build/app.d.ts +31 -6
  43. package/dist/core/build/app.js +31 -13
  44. package/dist/core/build/environment.d.ts +25 -0
  45. package/dist/core/build/environment.js +157 -0
  46. package/dist/core/build/generate.js +10 -1
  47. package/dist/core/build/plugins/plugin-incremental.js +145 -37
  48. package/dist/core/cache/handler.d.ts +13 -7
  49. package/dist/core/cache/handler.js +55 -51
  50. package/dist/core/cache/provider.d.ts +4 -0
  51. package/dist/core/cache/provider.js +15 -0
  52. package/dist/core/constants.d.ts +0 -11
  53. package/dist/core/constants.js +1 -5
  54. package/dist/core/dev/dev.js +1 -1
  55. package/dist/core/dev/lockfile.d.ts +19 -2
  56. package/dist/core/dev/lockfile.js +25 -2
  57. package/dist/core/environment/dev-nonrunnable.d.ts +6 -0
  58. package/dist/core/environment/dev-nonrunnable.js +170 -0
  59. package/dist/core/environment/index.d.ts +90 -0
  60. package/dist/core/environment/index.js +12 -0
  61. package/dist/core/environment/production.d.ts +6 -0
  62. package/dist/core/environment/production.js +117 -0
  63. package/dist/core/errors/build-handler.d.ts +5 -10
  64. package/dist/core/errors/build-handler.js +11 -17
  65. package/dist/core/errors/default-handler.d.ts +4 -9
  66. package/dist/core/errors/default-handler.js +92 -107
  67. package/dist/core/errors/dev-handler.d.ts +7 -11
  68. package/dist/core/errors/dev-handler.js +71 -69
  69. package/dist/core/errors/errors-data.d.ts +18 -0
  70. package/dist/core/errors/errors-data.js +7 -0
  71. package/dist/core/errors/handler.d.ts +22 -3
  72. package/dist/core/errors/handler.js +25 -0
  73. package/dist/core/fetch/default-handler.d.ts +15 -8
  74. package/dist/core/fetch/default-handler.js +12 -34
  75. package/dist/core/fetch/features.d.ts +23 -0
  76. package/dist/core/fetch/features.js +27 -0
  77. package/dist/core/fetch/fetch-state.d.ts +52 -7
  78. package/dist/core/fetch/fetch-state.js +92 -81
  79. package/dist/core/fetch/index.d.ts +9 -2
  80. package/dist/core/fetch/index.js +18 -79
  81. package/dist/core/fetch/vite-plugin.js +2 -1
  82. package/dist/core/i18n/handler.d.ts +28 -13
  83. package/dist/core/i18n/handler.js +100 -100
  84. package/dist/core/logger/manifest-logger.d.ts +31 -0
  85. package/dist/core/logger/manifest-logger.js +37 -0
  86. package/dist/core/manifest/ambient-source.d.ts +2 -0
  87. package/dist/core/manifest/ambient-source.js +4 -0
  88. package/dist/core/manifest/ambient.d.ts +16 -0
  89. package/dist/core/manifest/ambient.js +22 -0
  90. package/dist/core/manifest/derived.d.ts +3 -0
  91. package/dist/core/manifest/derived.js +10 -0
  92. package/dist/core/manifest/memo.d.ts +31 -0
  93. package/dist/core/manifest/memo.js +47 -0
  94. package/dist/core/messages/runtime.js +1 -1
  95. package/dist/core/middleware/astro-middleware.d.ts +25 -35
  96. package/dist/core/middleware/astro-middleware.js +61 -81
  97. package/dist/core/middleware/load.d.ts +19 -0
  98. package/dist/core/middleware/load.js +36 -0
  99. package/dist/core/middleware/sequence.js +15 -7
  100. package/dist/core/pages/handler.d.ts +18 -25
  101. package/dist/core/pages/handler.js +68 -84
  102. package/dist/core/redirects/render.js +3 -8
  103. package/dist/core/render/index.d.ts +0 -1
  104. package/dist/core/render/index.js +0 -2
  105. package/dist/core/render/route-cache.d.ts +6 -1
  106. package/dist/core/render/route-cache.js +11 -1
  107. package/dist/core/rewrites/handler.d.ts +4 -6
  108. package/dist/core/rewrites/handler.js +19 -20
  109. package/dist/core/routing/default.d.ts +2 -0
  110. package/dist/core/routing/default.js +7 -1
  111. package/dist/core/routing/dev.d.ts +1 -3
  112. package/dist/core/routing/dev.js +12 -5
  113. package/dist/core/routing/handler.d.ts +6 -16
  114. package/dist/core/routing/handler.js +126 -164
  115. package/dist/core/routing/helpers.d.ts +7 -1
  116. package/dist/core/routing/helpers.js +21 -0
  117. package/dist/core/routing/match-request.d.ts +10 -0
  118. package/dist/core/routing/match-request.js +57 -0
  119. package/dist/core/routing/route-table.d.ts +34 -0
  120. package/dist/core/routing/route-table.js +41 -0
  121. package/dist/core/routing/trailing-slash-handler.d.ts +4 -14
  122. package/dist/core/routing/trailing-slash-handler.js +39 -50
  123. package/dist/core/server-islands/mappings.d.ts +6 -0
  124. package/dist/core/server-islands/mappings.js +12 -0
  125. package/dist/core/session/driver.d.ts +4 -0
  126. package/dist/core/session/driver.js +14 -0
  127. package/dist/core/session/handler.d.ts +1 -1
  128. package/dist/core/session/handler.js +8 -8
  129. package/dist/core/session/provider-disabled.js +2 -2
  130. package/dist/core/util.js +2 -2
  131. package/dist/entrypoints/prerender.js +5 -1
  132. package/dist/i18n/middleware.d.ts +4 -4
  133. package/dist/i18n/middleware.js +3 -3
  134. package/dist/manifest/serialized.d.ts +1 -0
  135. package/dist/manifest/serialized.js +9 -2
  136. package/dist/runtime/prerender/static-paths.d.ts +14 -2
  137. package/dist/runtime/prerender/static-paths.js +4 -3
  138. package/dist/types/public/config.d.ts +433 -241
  139. package/dist/vite-plugin-app/createAstroServerApp.js +22 -18
  140. package/dist/vite-plugin-app/environment.d.ts +18 -0
  141. package/dist/vite-plugin-app/environment.js +210 -0
  142. package/dist/vite-plugin-app/handle-request.d.ts +30 -0
  143. package/dist/vite-plugin-app/handle-request.js +129 -0
  144. package/dist/vite-plugin-app/index.d.ts +1 -1
  145. package/dist/vite-plugin-app/index.js +1 -1
  146. package/dist/vite-plugin-css/index.js +2 -2
  147. package/package.json +14 -6
  148. package/src/core/README.md +37 -0
  149. package/src/core/manifest/ambient-source.ts +9 -0
  150. package/src/types/README.md +5 -0
  151. package/dist/container/pipeline.d.ts +0 -14
  152. package/dist/container/pipeline.js +0 -78
  153. package/dist/core/app/dev/app.d.ts +0 -31
  154. package/dist/core/app/dev/app.js +0 -80
  155. package/dist/core/app/dev/pipeline.d.ts +0 -17
  156. package/dist/core/app/dev/pipeline.js +0 -133
  157. package/dist/core/app/pipeline.d.ts +0 -14
  158. package/dist/core/app/pipeline.js +0 -123
  159. package/dist/core/base-pipeline.d.ts +0 -183
  160. package/dist/core/base-pipeline.js +0 -293
  161. package/dist/core/build/pipeline.d.ts +0 -38
  162. package/dist/core/build/pipeline.js +0 -202
  163. package/dist/vite-plugin-app/app.d.ts +0 -62
  164. package/dist/vite-plugin-app/app.js +0 -237
  165. package/dist/vite-plugin-app/pipeline.d.ts +0 -25
  166. package/dist/vite-plugin-app/pipeline.js +0 -189
@@ -1,5 +1,4 @@
1
1
  import { escape } from "html-escaper";
2
- import { forEach } from "neotraverse";
3
2
  import * as z from "zod/v4";
4
3
  import { createSvgComponent } from "../assets/runtime.js";
5
4
  import { imageSrcToImportId } from "../assets/utils/resolveImports.js";
@@ -17,7 +16,6 @@ import {
17
16
  unescapeHTML
18
17
  } from "../runtime/server/index.js";
19
18
  import { defineCollection as defineCollectionOrig } from "./config.js";
20
- import { IMAGE_IMPORT_PREFIX } from "./consts.js";
21
19
  import { globalDataStore } from "./data-store.js";
22
20
  import {
23
21
  LiveCollectionCacheHintError,
@@ -357,33 +355,52 @@ async function updateImageReferencesInBody(html, fileName) {
357
355
  }).filter(([, value]) => value != null).map(([key, value]) => value === "" ? `${key}=""` : `${key}="${escape(String(value))}"`).join(" ");
358
356
  });
359
357
  }
360
- function updateImageReferencesInData(data, fileName, imageAssetMap) {
361
- const copy = structuredClone(data);
362
- forEach(copy, function(ctx, val) {
363
- if (typeof val === "string" && val.startsWith(IMAGE_IMPORT_PREFIX)) {
364
- const src = val.replace(IMAGE_IMPORT_PREFIX, "");
365
- const id = imageSrcToImportId(src, fileName);
366
- if (!id) {
367
- ctx.update(src);
368
- return;
369
- }
370
- const imported = imageAssetMap?.get(id);
371
- if (imported) {
372
- if (imported.__svgData) {
373
- const { __svgData: svgData, ...meta } = imported;
374
- ctx.update(createSvgComponent({ meta, ...svgData }));
375
- } else {
376
- ctx.update(imported);
377
- }
378
- } else {
379
- ctx.update(src);
380
- }
381
- }
382
- });
358
+ function resolveImageAtPath(src, fileName, imageAssetMap) {
359
+ const id = imageSrcToImportId(src, fileName);
360
+ if (!id) {
361
+ return void 0;
362
+ }
363
+ const imported = imageAssetMap?.get(id);
364
+ if (!imported) {
365
+ return void 0;
366
+ }
367
+ if (imported.__svgData) {
368
+ const { __svgData: svgData, ...meta } = imported;
369
+ return createSvgComponent({ meta, ...svgData });
370
+ }
371
+ return imported;
372
+ }
373
+ function setAtPathCopying(target, path, value) {
374
+ if (path.length === 0) {
375
+ return target;
376
+ }
377
+ const [key, ...rest] = path;
378
+ const copy = Array.isArray(target) ? target.slice() : { ...target };
379
+ copy[key] = rest.length === 0 ? value : setAtPathCopying(copy[key], rest, value);
383
380
  return copy;
384
381
  }
382
+ function updateImageReferencesInData(data, fileName, imageAssetMap, imageImports) {
383
+ if (!imageImports?.length) {
384
+ return data;
385
+ }
386
+ let result = data;
387
+ for (const path of imageImports) {
388
+ let src = result;
389
+ for (const key of path) {
390
+ src = src?.[key];
391
+ }
392
+ if (typeof src !== "string") {
393
+ continue;
394
+ }
395
+ const resolved = resolveImageAtPath(src, fileName, imageAssetMap);
396
+ if (resolved !== void 0) {
397
+ result = setAtPathCopying(result, path, resolved);
398
+ }
399
+ }
400
+ return result;
401
+ }
385
402
  function resolveEntryData(entry, imageAssetMap) {
386
- return entry.assetImports?.length ? updateImageReferencesInData(entry.data, entry.filePath, imageAssetMap) : structuredClone(entry.data);
403
+ return updateImageReferencesInData(entry.data, entry.filePath, imageAssetMap, entry.imageImports);
387
404
  }
388
405
  async function renderEntry(entry) {
389
406
  if (!entry) {
@@ -1,7 +1,5 @@
1
1
  import { BaseApp, type LogRequestPayload } from './base.js';
2
- import { AppPipeline } from './pipeline.js';
3
2
  export declare class App extends BaseApp {
4
- createPipeline(streaming: boolean): AppPipeline;
5
3
  isDev(): boolean;
6
4
  logRequest(_options: LogRequestPayload): void;
7
5
  }
@@ -1,12 +1,5 @@
1
1
  import { BaseApp } from "./base.js";
2
- import { AppPipeline } from "./pipeline.js";
3
2
  class App extends BaseApp {
4
- createPipeline(streaming) {
5
- return AppPipeline.create({
6
- manifest: this.manifest,
7
- streaming
8
- });
9
- }
10
3
  isDev() {
11
4
  return false;
12
5
  }
@@ -1,12 +1,10 @@
1
1
  import type { RoutesList } from '../../types/astro.js';
2
2
  import type { RemotePattern, RouteData } from '../../types/public/index.js';
3
- import { type Pipeline } from '../base-pipeline.js';
4
3
  import { getSetCookiesFromResponse } from '../cookies/index.js';
5
4
  import { AstroIntegrationLogger, type AstroLogger } from '../logger/core.js';
6
5
  import type { FetchHandler } from '../fetch/types.js';
7
- import type { ErrorHandler } from '../errors/handler.js';
6
+ import { type ErrorHandler } from '../errors/handler.js';
8
7
  import type { WaitUntilHook } from '../wait-until.js';
9
- import type { AppPipeline } from './pipeline.js';
10
8
  import type { SSRManifest } from './types.js';
11
9
  export interface DevMatch {
12
10
  routeData: RouteData;
@@ -87,17 +85,38 @@ export interface RenderErrorOptions extends ResolvedRenderOptions {
87
85
  pathname?: string;
88
86
  }
89
87
  type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}/404/index.html` | `${string}/500/index.html` | `${string}404.html` | `${string}500.html`;
90
- export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
88
+ export declare abstract class BaseApp {
91
89
  #private;
92
90
  manifest: SSRManifest;
93
- manifestData: {
94
- routes: RouteData[];
95
- };
96
- pipeline: P;
97
91
  baseWithoutTrailingSlash: string;
98
92
  get logger(): AstroLogger;
93
+ /**
94
+ * Route data derived from the manifest, used for route matching. Reads and
95
+ * writes go through the single per-manifest route table, so HMR updates are
96
+ * visible to every consumer at once.
97
+ */
98
+ get manifestData(): {
99
+ routes: RouteData[];
100
+ };
101
+ set manifestData(routesList: {
102
+ routes: RouteData[];
103
+ });
99
104
  get adapterLogger(): AstroIntegrationLogger;
100
- constructor(manifest: SSRManifest, streaming?: boolean, ...args: any[]);
105
+ constructor(manifest: SSRManifest, streaming?: boolean);
106
+ /**
107
+ * Resolves the user-configured logger destination from the manifest and
108
+ * returns the logger. Lazy and only resolves once; safe to call before
109
+ * the first render (adapters use this to log startup messages through
110
+ * the configured destination).
111
+ */
112
+ getLogger(): Promise<AstroLogger>;
113
+ /**
114
+ * The streaming flag fed into the internal `FetchState` facade hooks on
115
+ * the fast path. Returns the constructor flag by
116
+ * default; `BuildApp` overrides this to return `undefined` so streaming
117
+ * falls through to the environment default (`manifest.serverLike`).
118
+ */
119
+ protected resolveStreaming(): boolean | undefined;
101
120
  /**
102
121
  * Override the fetch handler used to dispatch requests. Entrypoints
103
122
  * call this with the default export of `virtual:astro:fetchable` to
@@ -107,8 +126,10 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
107
126
  fetch: FetchHandler;
108
127
  }): void;
109
128
  /**
110
- * Returns the error handler strategy used by this app. Override to
111
- * provide environment-specific behavior (dev overlay, build-time throws, etc.).
129
+ * Returns the error handler used by this app. The default is a thin
130
+ * bridge over the functional error API strategy selection (production
131
+ * default / dev / build) is environment-driven inside `renderErrorPage`.
132
+ * External subclasses can override this to customize error rendering.
112
133
  */
113
134
  protected createErrorHandler(): ErrorHandler;
114
135
  abstract isDev(): boolean;
@@ -120,15 +141,6 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
120
141
  getAllowedDomains(): Partial<RemotePattern>[] | undefined;
121
142
  protected matchesAllowedDomains(forwardedHost: string, protocol?: string): boolean;
122
143
  static validateForwardedHost(forwardedHost: string, allowedDomains?: Partial<RemotePattern>[], protocol?: string): boolean;
123
- /**
124
- * Creates a pipeline by reading the stored manifest
125
- *
126
- * @param streaming
127
- * @param manifest
128
- * @param args
129
- * @private
130
- */
131
- abstract createPipeline(streaming: boolean, manifest: SSRManifest, ...args: any[]): P;
132
144
  set setManifestData(newManifestData: RoutesList);
133
145
  removeBase(pathname: string): string;
134
146
  /**
@@ -5,23 +5,30 @@ import {
5
5
  } from "@astrojs/internal-helpers/path";
6
6
  import { matchPattern } from "@astrojs/internal-helpers/remote";
7
7
  import { computePathnameFromDomain } from "../i18n/domain.js";
8
- import { isLocalizedErrorRoute } from "../../i18n/error-routes.js";
9
- import { PipelineFeatures } from "../base-pipeline.js";
10
8
  import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
11
9
  import { getSetCookiesFromResponse } from "../cookies/index.js";
12
10
  import { AstroError, AstroErrorData } from "../errors/index.js";
13
11
  import { AstroIntegrationLogger } from "../logger/core.js";
14
12
  import { DefaultFetchHandler } from "../fetch/default-handler.js";
15
- import { appSymbol } from "../constants.js";
16
- import { DefaultErrorHandler } from "../errors/default-handler.js";
17
- import { isRoute404, isRoute500 } from "../routing/internal/route-errors.js";
13
+ import { getUsedFeatures, FetchFeatures } from "../fetch/features.js";
14
+ import { FetchState } from "../fetch/fetch-state.js";
15
+ import { renderErrorPage } from "../errors/handler.js";
16
+ import { getLogger, getResolvedLogger } from "../logger/manifest-logger.js";
17
+ import { handleRequest } from "../routing/handler.js";
18
+ import { getDefaultStatusCode } from "../routing/helpers.js";
19
+ import { matchRequest } from "../routing/match-request.js";
20
+ import { getRouteTable, matchRoute, updateRouteTable } from "../routing/route-table.js";
18
21
  import { setRenderOptions } from "./render-options.js";
19
22
  class BaseApp {
20
23
  manifest;
21
- manifestData;
22
- pipeline;
23
24
  #adapterLogger;
24
25
  baseWithoutTrailingSlash;
26
+ /**
27
+ * The streaming flag passed to the constructor, surfaced through the
28
+ * protected `resolveStreaming()` hook and fed into the internal
29
+ * `FetchState` facade hooks on the fast path.
30
+ */
31
+ #streaming;
25
32
  /**
26
33
  * The handler that turns incoming `Request` objects into `Response`s.
27
34
  * Defaults to a `DefaultFetchHandler` pinned to this app and can be
@@ -42,7 +49,18 @@ class BaseApp {
42
49
  */
43
50
  #featureCheckDone = false;
44
51
  get logger() {
45
- return this.pipeline.logger;
52
+ return getLogger(this.manifest);
53
+ }
54
+ /**
55
+ * Route data derived from the manifest, used for route matching. Reads and
56
+ * writes go through the single per-manifest route table, so HMR updates are
57
+ * visible to every consumer at once.
58
+ */
59
+ get manifestData() {
60
+ return getRouteTable(this.manifest);
61
+ }
62
+ set manifestData(routesList) {
63
+ updateRouteTable(this.manifest, routesList.routes);
46
64
  }
47
65
  get adapterLogger() {
48
66
  const currentOptions = this.logger.options;
@@ -51,14 +69,33 @@ class BaseApp {
51
69
  }
52
70
  return this.#adapterLogger;
53
71
  }
54
- constructor(manifest, streaming = true, ...args) {
72
+ constructor(manifest, streaming = true) {
55
73
  this.manifest = manifest;
56
74
  this.baseWithoutTrailingSlash = removeTrailingForwardSlash(manifest.base);
57
- this.pipeline = this.createPipeline(streaming, manifest, ...args);
58
- this.manifestData = this.pipeline.manifestData;
75
+ this.#streaming = streaming;
76
+ getRouteTable(manifest);
77
+ getLogger(manifest);
59
78
  this.#fetchHandler = new DefaultFetchHandler(this);
60
79
  this.#errorHandler = this.createErrorHandler();
61
80
  }
81
+ /**
82
+ * Resolves the user-configured logger destination from the manifest and
83
+ * returns the logger. Lazy and only resolves once; safe to call before
84
+ * the first render (adapters use this to log startup messages through
85
+ * the configured destination).
86
+ */
87
+ getLogger() {
88
+ return getResolvedLogger(this.manifest);
89
+ }
90
+ /**
91
+ * The streaming flag fed into the internal `FetchState` facade hooks on
92
+ * the fast path. Returns the constructor flag by
93
+ * default; `BuildApp` overrides this to return `undefined` so streaming
94
+ * falls through to the environment default (`manifest.serverLike`).
95
+ */
96
+ resolveStreaming() {
97
+ return this.#streaming;
98
+ }
62
99
  /**
63
100
  * Override the fetch handler used to dispatch requests. Entrypoints
64
101
  * call this with the default export of `virtual:astro:fetchable` to
@@ -69,11 +106,15 @@ class BaseApp {
69
106
  this.#hasCustomFetchHandler = !(handler instanceof DefaultFetchHandler);
70
107
  }
71
108
  /**
72
- * Returns the error handler strategy used by this app. Override to
73
- * provide environment-specific behavior (dev overlay, build-time throws, etc.).
109
+ * Returns the error handler used by this app. The default is a thin
110
+ * bridge over the functional error API strategy selection (production
111
+ * default / dev / build) is environment-driven inside `renderErrorPage`.
112
+ * External subclasses can override this to customize error rendering.
74
113
  */
75
114
  createErrorHandler() {
76
- return new DefaultErrorHandler(this);
115
+ return {
116
+ renderError: (request, options) => renderErrorPage(this.manifest, request, options)
117
+ };
77
118
  }
78
119
  /**
79
120
  * Resets the cached adapter logger so it picks up a new logger instance.
@@ -102,9 +143,7 @@ class BaseApp {
102
143
  }
103
144
  }
104
145
  set setManifestData(newManifestData) {
105
- this.manifestData = newManifestData;
106
- this.pipeline.manifestData = newManifestData;
107
- this.pipeline.rebuildRouter();
146
+ updateRouteTable(this.manifest, newManifestData.routes);
108
147
  }
109
148
  removeBase(pathname) {
110
149
  pathname = collapseDuplicateLeadingSlashes(pathname);
@@ -147,25 +186,7 @@ class BaseApp {
147
186
  * @param allowPrerenderedRoutes
148
187
  */
149
188
  match(request, allowPrerenderedRoutes = false) {
150
- const url = new URL(request.url);
151
- if (this.manifest.assets.has(url.pathname)) return void 0;
152
- let pathname = this.computePathnameFromDomain(request);
153
- if (!pathname) {
154
- pathname = prependForwardSlash(this.removeBase(url.pathname));
155
- }
156
- const routeData = this.pipeline.matchRoute(this.safeDecodeURI(pathname));
157
- if (!routeData) return void 0;
158
- if (allowPrerenderedRoutes) {
159
- return routeData;
160
- }
161
- if (routeData.prerender) {
162
- if (routeData.params.length > 0) {
163
- const allMatches = this.pipeline.matchAllRoutes(this.safeDecodeURI(pathname));
164
- return allMatches.find((r) => !r.prerender);
165
- }
166
- return void 0;
167
- }
168
- return routeData;
189
+ return matchRequest(this.manifest, request, allowPrerenderedRoutes);
169
190
  }
170
191
  /**
171
192
  * A matching route function to use in the development server.
@@ -195,7 +216,7 @@ class BaseApp {
195
216
  routeData,
196
217
  waitUntil
197
218
  } = {}) {
198
- await this.pipeline.getLogger();
219
+ await getResolvedLogger(this.manifest);
199
220
  if (routeData) {
200
221
  this.logger.debug(
201
222
  "router",
@@ -226,7 +247,7 @@ class BaseApp {
226
247
  if (!routeData) {
227
248
  const domainPathname = this.computePathnameFromDomain(request);
228
249
  if (domainPathname) {
229
- routeData = this.pipeline.matchRoute(this.safeDecodeURI(domainPathname));
250
+ routeData = matchRoute(this.manifest, this.safeDecodeURI(domainPathname));
230
251
  }
231
252
  }
232
253
  const resolvedOptions = {
@@ -239,11 +260,15 @@ class BaseApp {
239
260
  };
240
261
  let response;
241
262
  if (this.#fetchHandler instanceof DefaultFetchHandler) {
242
- Reflect.set(request, appSymbol, this);
243
- response = await this.#fetchHandler.renderWithOptions(request, resolvedOptions);
263
+ response = await handleRequest(
264
+ new FetchState(this.manifest, request, resolvedOptions, {
265
+ streaming: this.resolveStreaming(),
266
+ renderError: (req, opts) => this.renderError(req, opts),
267
+ logRequest: (payload) => this.logThisRequest(payload)
268
+ })
269
+ );
244
270
  } else {
245
271
  setRenderOptions(request, resolvedOptions);
246
- Reflect.set(request, appSymbol, this);
247
272
  response = await this.#fetchHandler.fetch(request);
248
273
  }
249
274
  this.#warnMissingFeatures();
@@ -299,52 +324,37 @@ class BaseApp {
299
324
  this.#featureCheckDone = true;
300
325
  const manifest = this.manifest;
301
326
  const missing = [];
302
- const used = this.pipeline.usedFeatures;
303
- if (manifest.routes.some((r) => r.routeData.type === "redirect") && !(used & PipelineFeatures.redirects)) {
327
+ const used = getUsedFeatures(this.manifest);
328
+ if (manifest.routes.some((r) => r.routeData.type === "redirect") && !(used & FetchFeatures.redirects)) {
304
329
  missing.push("redirects");
305
330
  }
306
- if (manifest.sessionConfig && !(used & PipelineFeatures.sessions)) {
331
+ if (manifest.sessionConfig && !(used & FetchFeatures.sessions)) {
307
332
  missing.push("sessions");
308
333
  }
309
- if (manifest.actions && !(used & PipelineFeatures.actions)) {
334
+ if (manifest.actions && !(used & FetchFeatures.actions)) {
310
335
  missing.push("actions");
311
336
  }
312
- if (manifest.middleware && !(used & PipelineFeatures.middleware)) {
337
+ if (manifest.middleware && !(used & FetchFeatures.middleware)) {
313
338
  missing.push("middleware");
314
339
  }
315
- if (manifest.i18n && manifest.i18n.strategy !== "manual" && !(used & PipelineFeatures.i18n)) {
340
+ if (manifest.i18n && manifest.i18n.strategy !== "manual" && !(used & FetchFeatures.i18n)) {
316
341
  missing.push("i18n");
317
342
  }
318
- if (manifest.cacheConfig && !(used & PipelineFeatures.cache)) {
343
+ if (manifest.cacheConfig && !(used & FetchFeatures.cache)) {
319
344
  missing.push("cache");
320
345
  }
321
346
  for (const feature of missing) {
322
347
  this.logger.warn(
323
348
  "router",
324
- `Your project uses ${feature}, but your custom src/fetch.ts does not call the ${feature}() handler. This feature will not work unless you add it to your fetch.ts pipeline.`
349
+ `Your project uses ${feature}, but your custom src/fetch.ts does not call the ${feature}() handler. This feature will not work unless your fetch handler calls it.`
325
350
  );
326
351
  }
327
352
  }
328
353
  getDefaultStatusCode(routeData, pathname) {
329
- if (!routeData.pattern.test(pathname)) {
330
- for (const fallbackRoute of routeData.fallbackRoutes) {
331
- if (fallbackRoute.pattern.test(pathname)) {
332
- return 302;
333
- }
334
- }
335
- }
336
- const route = removeTrailingForwardSlash(routeData.route);
337
- const locales = this.manifest.i18n?.locales;
338
- if (isRoute404(route) || isLocalizedErrorRoute(route, 404, locales)) {
339
- return 404;
340
- }
341
- if (isRoute500(route) || isLocalizedErrorRoute(route, 500, locales)) {
342
- return 500;
343
- }
344
- return 200;
354
+ return getDefaultStatusCode(this.manifest, routeData, pathname);
345
355
  }
346
356
  getManifest() {
347
- return this.pipeline.manifest;
357
+ return this.manifest;
348
358
  }
349
359
  logThisRequest({
350
360
  pathname,
@@ -0,0 +1,27 @@
1
+ import type { RouteData } from '../../types/public/index.js';
2
+ import { BaseApp, type DevMatch, type LogRequestPayload } from './base.js';
3
+ import type { SSRManifest } from './types.js';
4
+ /**
5
+ * The shared thin dev facade: used by BOTH dev paths —
6
+ * the workerd / non-runnable dev entrypoint (`entrypoints/virtual/dev.ts`)
7
+ * and the runnable dev server (`vite-plugin-app/createAstroServerApp.ts`).
8
+ * Everything environment-specific (module loading, error strategy, request
9
+ * logging behavior) comes from the `RenderEnvironment` record registered on
10
+ * the manifest before construction, and the runnable dev server's HTTP glue
11
+ * lives in `vite-plugin-app/handle-request.ts`.
12
+ */
13
+ export declare class DevFacadeApp extends BaseApp {
14
+ constructor(manifest: SSRManifest, streaming?: boolean);
15
+ isDev(): boolean;
16
+ /** Dev always allows prerendered routes to match. */
17
+ match(request: Request): RouteData | undefined;
18
+ /**
19
+ * A matching route function for the development server. Contrary to
20
+ * `.match`, this resolves props and params, returning the correct route
21
+ * based on priority and segments, plus the resolved pathname.
22
+ */
23
+ devMatch(pathname?: string, { prerenderOnly }?: {
24
+ prerenderOnly?: boolean;
25
+ }): Promise<DevMatch | undefined>;
26
+ logRequest({ pathname, method, statusCode, isRewrite, reqTime }: LogRequestPayload): void;
27
+ }
@@ -0,0 +1,51 @@
1
+ import { req } from "../messages/runtime.js";
2
+ import { matchRoute as devMatchRoute } from "../routing/dev.js";
3
+ import { BaseApp } from "./base.js";
4
+ class DevFacadeApp extends BaseApp {
5
+ constructor(manifest, streaming = true) {
6
+ super(manifest, streaming);
7
+ }
8
+ isDev() {
9
+ return true;
10
+ }
11
+ /** Dev always allows prerendered routes to match. */
12
+ match(request) {
13
+ return super.match(request, true);
14
+ }
15
+ /**
16
+ * A matching route function for the development server. Contrary to
17
+ * `.match`, this resolves props and params, returning the correct route
18
+ * based on priority and segments, plus the resolved pathname.
19
+ */
20
+ async devMatch(pathname, { prerenderOnly } = {}) {
21
+ if (pathname === void 0) {
22
+ return void 0;
23
+ }
24
+ const matchedRoute = await devMatchRoute(this.manifest, pathname, { prerenderOnly });
25
+ if (!matchedRoute) {
26
+ return void 0;
27
+ }
28
+ return {
29
+ routeData: matchedRoute.route,
30
+ resolvedPathname: matchedRoute.resolvedPathname
31
+ };
32
+ }
33
+ logRequest({ pathname, method, statusCode, isRewrite, reqTime }) {
34
+ if (pathname === "/favicon.ico") {
35
+ return;
36
+ }
37
+ this.logger.info(
38
+ null,
39
+ req({
40
+ url: pathname,
41
+ method,
42
+ statusCode,
43
+ isRewrite,
44
+ reqTime
45
+ })
46
+ );
47
+ }
48
+ }
49
+ export {
50
+ DevFacadeApp
51
+ };
@@ -4,6 +4,5 @@ export { BaseApp, type RenderErrorOptions, type RenderOptions, type LogRequestPa
4
4
  export { fromRoutingStrategy, toRoutingStrategy } from '../common.js';
5
5
  export { createConsoleLogger } from '../../logger/impls/console.js';
6
6
  export { deserializeManifest, deserializeRouteData, deserializeRouteInfo, serializeRouteData, serializeRouteInfo, } from '../manifest.js';
7
- export { AppPipeline } from '../pipeline.js';
8
7
  export { beginContentEntryCollection, endContentEntryCollection, } from '../../build/incremental-content-collector.js';
9
8
  export { beginImageCollection, endImageCollection, recordStaticImage, } from '../../build/incremental-image-collector.js';
@@ -11,7 +11,6 @@ import {
11
11
  serializeRouteData,
12
12
  serializeRouteInfo
13
13
  } from "../manifest.js";
14
- import { AppPipeline } from "../pipeline.js";
15
14
  import {
16
15
  beginContentEntryCollection,
17
16
  endContentEntryCollection
@@ -23,7 +22,6 @@ import {
23
22
  } from "../../build/incremental-image-collector.js";
24
23
  export {
25
24
  App,
26
- AppPipeline,
27
25
  BaseApp,
28
26
  beginContentEntryCollection,
29
27
  beginImageCollection,
@@ -1,40 +1,45 @@
1
1
  import fetchable from "virtual:astro:fetchable";
2
2
  import { manifest } from "virtual:astro:manifest";
3
- import { DevApp } from "../../dev/app.js";
3
+ import { clearActions } from "../../../../actions/load.js";
4
+ import { createNonRunnableEnvironment } from "../../../environment/dev-nonrunnable.js";
5
+ import { setEnvironment } from "../../../environment/index.js";
4
6
  import { createConsoleLogger } from "../../../logger/impls/console.js";
5
- let currentDevApp = null;
7
+ import { getLogger, setLogger } from "../../../logger/manifest-logger.js";
8
+ import { clearMiddleware } from "../../../middleware/load.js";
9
+ import { getRouteCache } from "../../../render/route-cache.js";
10
+ import { updateRouteTable } from "../../../routing/route-table.js";
11
+ import { DevFacadeApp } from "../../dev-facade.js";
12
+ let hmrWired = false;
6
13
  const createApp = ({ streaming } = {}) => {
7
- const logger = createConsoleLogger(manifest.logLevel);
8
- currentDevApp = new DevApp(manifest, streaming, logger);
9
- currentDevApp.setFetchHandler(fetchable);
10
- if (import.meta.hot) {
14
+ setLogger(manifest, createConsoleLogger(manifest.logLevel));
15
+ setEnvironment(manifest, createNonRunnableEnvironment());
16
+ const app = new DevFacadeApp(manifest, streaming);
17
+ app.setFetchHandler(fetchable);
18
+ if (import.meta.hot && !hmrWired) {
19
+ hmrWired = true;
11
20
  import.meta.hot.on("astro:routes-updated", async () => {
12
- if (!currentDevApp) return;
13
21
  try {
14
22
  const { routes: newRoutes } = await import("virtual:astro:routes");
15
- const newRoutesList = {
16
- routes: newRoutes.map((r) => r.routeData)
17
- };
18
- currentDevApp.updateRoutes(newRoutesList);
23
+ updateRouteTable(
24
+ manifest,
25
+ newRoutes.map((r) => r.routeData)
26
+ );
19
27
  } catch (e) {
20
- logger.error("router", `Failed to update routes via HMR:
28
+ getLogger(manifest).error("router", `Failed to update routes via HMR:
21
29
  ${e}`);
22
30
  }
23
31
  });
24
32
  import.meta.hot.on("astro:content-changed", () => {
25
- if (!currentDevApp) return;
26
- currentDevApp.pipeline.routeCache.clearAll();
33
+ getRouteCache(manifest).clearAll();
27
34
  });
28
35
  import.meta.hot.on("astro:middleware-updated", () => {
29
- if (!currentDevApp) return;
30
- currentDevApp.clearMiddleware();
36
+ clearMiddleware(manifest);
31
37
  });
32
38
  import.meta.hot.on("astro:actions-updated", () => {
33
- if (!currentDevApp) return;
34
- currentDevApp.clearActions();
39
+ clearActions(manifest);
35
40
  });
36
41
  }
37
- return currentDevApp;
42
+ return app;
38
43
  };
39
44
  export {
40
45
  createApp
@@ -19,12 +19,7 @@ function createRequestFromNodeRequest(req, {
19
19
  const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
20
20
  const protocol = isEncrypted ? "https" : "http";
21
21
  const hostname = typeof req.headers.host === "string" ? req.headers.host : typeof req.headers[":authority"] === "string" ? req.headers[":authority"] : serverPort ? `localhost:${serverPort}` : "localhost";
22
- let url;
23
- try {
24
- url = new URL(`${protocol}://${hostname}${req.url}`);
25
- } catch {
26
- url = new URL(`${protocol}://${hostname}`);
27
- }
22
+ const url = buildRequestUrl(protocol, hostname, req.url, serverPort);
28
23
  const options = {
29
24
  method: req.method || "GET",
30
25
  headers: makeRequestHeaders(req),
@@ -80,14 +75,7 @@ function createRequest(req, {
80
75
  );
81
76
  const hostname = validated.host ?? validatedHostname ?? "localhost";
82
77
  const port = validated.port ?? (!validated.host && !validatedHostname && serverPort ? String(serverPort) : void 0);
83
- let url;
84
- try {
85
- const hostnamePort = getHostnamePort(hostname, port);
86
- url = new URL(`${protocol}://${hostnamePort}${req.url}`);
87
- } catch {
88
- const hostnamePort = getHostnamePort(hostname, port);
89
- url = new URL(`${protocol}://${hostnamePort}`);
90
- }
78
+ const url = buildRequestUrl(protocol, getHostnamePort(hostname, port), req.url, serverPort);
91
79
  const options = {
92
80
  method: req.method || "GET",
93
81
  headers: makeRequestHeaders(req),
@@ -245,6 +233,17 @@ function getHostnamePort(hostname, port) {
245
233
  const hostnamePort = portInHostname ? hostname : `${hostname}${port ? `:${port}` : ""}`;
246
234
  return hostnamePort;
247
235
  }
236
+ function buildRequestUrl(protocol, hostnamePort, requestPath, serverPort) {
237
+ const path = requestPath ?? "";
238
+ if (URL.canParse(`${protocol}://${hostnamePort}${path}`)) {
239
+ return new URL(`${protocol}://${hostnamePort}${path}`);
240
+ }
241
+ if (URL.canParse(`${protocol}://${hostnamePort}`)) {
242
+ return new URL(`${protocol}://${hostnamePort}`);
243
+ }
244
+ const fallbackHost = serverPort ? `localhost:${serverPort}` : "localhost";
245
+ return new URL(`${protocol}://${fallbackHost}`);
246
+ }
248
247
  function makeRequestHeaders(req) {
249
248
  const headers = new Headers();
250
249
  for (const [name, value] of Object.entries(req.headers)) {