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
@@ -17,16 +17,10 @@ import type { FetchState } from '../core/fetch/fetch-state.js';
17
17
  * page dispatch. That placement preserves the existing behavior where
18
18
  * user middleware sees action requests and response finalization (cookies,
19
19
  * sessions, etc.) runs around the action response.
20
+ *
21
+ * Expects the APIContext that is already being used by the render pipeline.
22
+ * Returns a `Response` when the action fully handles the request (RPC),
23
+ * or `undefined` when the caller should continue processing the request
24
+ * (form actions or non-action requests).
20
25
  */
21
- export declare class ActionHandler {
22
- #private;
23
- /**
24
- * Run action handling for the current request. Expects the APIContext
25
- * that is already being used by the render pipeline.
26
- *
27
- * Returns a `Response` when the action fully handles the request (RPC),
28
- * or `undefined` when the caller should continue processing the
29
- * request (form actions or non-action requests).
30
- */
31
- handle(apiContext: APIContext, state: FetchState): Promise<Response | undefined> | undefined;
32
- }
26
+ export declare function handleAction(apiContext: APIContext, state: FetchState): Promise<Response | undefined> | undefined;
@@ -2,51 +2,41 @@ import {
2
2
  createCrossOriginForbiddenResponse,
3
3
  isForbiddenCrossOriginRequest
4
4
  } from "../core/app/origin-check.js";
5
- import { PipelineFeatures } from "../core/base-pipeline.js";
5
+ import { markFeatureUsed, FetchFeatures } from "../core/fetch/features.js";
6
6
  import { getActionContext, serializeActionResult } from "./runtime/server.js";
7
- class ActionHandler {
8
- /**
9
- * Run action handling for the current request. Expects the APIContext
10
- * that is already being used by the render pipeline.
11
- *
12
- * Returns a `Response` when the action fully handles the request (RPC),
13
- * or `undefined` when the caller should continue processing the
14
- * request (form actions or non-action requests).
15
- */
16
- handle(apiContext, state) {
17
- state.pipeline.usedFeatures |= PipelineFeatures.actions;
18
- if (apiContext.isPrerendered) {
19
- return void 0;
20
- }
21
- const { action, setActionResult } = getActionContext(apiContext);
22
- if (!action) {
23
- return void 0;
24
- }
25
- if (state.pipeline.manifest.checkOrigin && isForbiddenCrossOriginRequest(apiContext.request, apiContext.url, apiContext.isPrerendered)) {
26
- return Promise.resolve(createCrossOriginForbiddenResponse(apiContext.request));
27
- }
28
- return this.#executeAction(action, setActionResult);
7
+ function handleAction(apiContext, state) {
8
+ markFeatureUsed(state.manifest, FetchFeatures.actions);
9
+ if (apiContext.isPrerendered) {
10
+ return void 0;
29
11
  }
30
- async #executeAction(action, setActionResult) {
31
- const actionResult = await action.handler();
32
- const serialized = serializeActionResult(actionResult);
33
- if (action.calledFrom === "rpc") {
34
- if (serialized.type === "empty") {
35
- return new Response(null, {
36
- status: serialized.status
37
- });
38
- }
39
- return new Response(serialized.body, {
40
- status: serialized.status,
41
- headers: {
42
- "Content-Type": serialized.contentType
43
- }
12
+ const { action, setActionResult } = getActionContext(apiContext);
13
+ if (!action) {
14
+ return void 0;
15
+ }
16
+ if (state.manifest.checkOrigin && isForbiddenCrossOriginRequest(apiContext.request, apiContext.url, apiContext.isPrerendered)) {
17
+ return Promise.resolve(createCrossOriginForbiddenResponse(apiContext.request));
18
+ }
19
+ return executeAction(action, setActionResult);
20
+ }
21
+ async function executeAction(action, setActionResult) {
22
+ const actionResult = await action.handler();
23
+ const serialized = serializeActionResult(actionResult);
24
+ if (action.calledFrom === "rpc") {
25
+ if (serialized.type === "empty") {
26
+ return new Response(null, {
27
+ status: serialized.status
44
28
  });
45
29
  }
46
- setActionResult(action.name, serialized);
47
- return void 0;
30
+ return new Response(serialized.body, {
31
+ status: serialized.status,
32
+ headers: {
33
+ "Content-Type": serialized.contentType
34
+ }
35
+ });
48
36
  }
37
+ setActionResult(action.name, serialized);
38
+ return void 0;
49
39
  }
50
40
  export {
51
- ActionHandler
41
+ handleAction
52
42
  };
@@ -0,0 +1,12 @@
1
+ import type { $ZodType } from 'zod/v4/core';
2
+ import type { SSRActions, SSRManifest } from '../types/public/internal.js';
3
+ import type { ActionAccept, ActionClient } from './runtime/types.js';
4
+ /** Resolves the actions module from the manifest (a no-op module when none). */
5
+ export declare function getActions(manifest: SSRManifest): Promise<SSRActions>;
6
+ /**
7
+ * Clears the cached actions so they are re-resolved on the next request.
8
+ * Called via HMR when action files change during development.
9
+ */
10
+ export declare function clearActions(manifest: SSRManifest): void;
11
+ /** Looks up a single action handler by its dot-separated path. */
12
+ export declare function getAction(manifest: SSRManifest, path: string): Promise<ActionClient<unknown, ActionAccept, $ZodType>>;
@@ -0,0 +1,55 @@
1
+ import { FORBIDDEN_PATH_KEYS } from "@astrojs/internal-helpers/object";
2
+ import { ActionNotFoundError } from "../core/errors/errors-data.js";
3
+ import { AstroError } from "../core/errors/index.js";
4
+ import { createAsyncManifestMemo } from "../core/manifest/memo.js";
5
+ import { NOOP_ACTIONS_MOD } from "./noop-actions.js";
6
+ const actionsMemo = createAsyncManifestMemo(
7
+ async (manifest) => manifest.actions ? await manifest.actions() : NOOP_ACTIONS_MOD
8
+ );
9
+ function getActions(manifest) {
10
+ return actionsMemo.get(manifest);
11
+ }
12
+ function clearActions(manifest) {
13
+ actionsMemo.invalidate(manifest);
14
+ }
15
+ async function getAction(manifest, path) {
16
+ const pathKeys = path.split(".").map((key) => decodeURIComponent(key));
17
+ let { server } = await getActions(manifest);
18
+ if (!server || !(typeof server === "object")) {
19
+ throw new TypeError(
20
+ `Expected \`server\` export in actions file to be an object. Received ${typeof server}.`
21
+ );
22
+ }
23
+ for (const key of pathKeys) {
24
+ if (typeof server === "function") {
25
+ throw new AstroError({
26
+ ...ActionNotFoundError,
27
+ message: ActionNotFoundError.message(pathKeys.join("."))
28
+ });
29
+ }
30
+ if (FORBIDDEN_PATH_KEYS.has(key)) {
31
+ throw new AstroError({
32
+ ...ActionNotFoundError,
33
+ message: ActionNotFoundError.message(pathKeys.join("."))
34
+ });
35
+ }
36
+ if (!Object.hasOwn(server, key)) {
37
+ throw new AstroError({
38
+ ...ActionNotFoundError,
39
+ message: ActionNotFoundError.message(pathKeys.join("."))
40
+ });
41
+ }
42
+ server = server[key];
43
+ }
44
+ if (typeof server !== "function") {
45
+ throw new TypeError(
46
+ `Expected handler for action ${pathKeys.join(".")} to be a function. Received ${typeof server}.`
47
+ );
48
+ }
49
+ return server;
50
+ }
51
+ export {
52
+ clearActions,
53
+ getAction,
54
+ getActions
55
+ };
@@ -1,6 +1,7 @@
1
- import { pipelineSymbol } from "../../../core/constants.js";
1
+ import { fetchStateSymbol } from "../../../core/constants.js";
2
2
  import { ActionCalledFromServerError } from "../../../core/errors/errors-data.js";
3
3
  import { AstroError } from "../../../core/errors/errors.js";
4
+ import { getAction } from "../../load.js";
4
5
  import { createGetActionPath, createActionsProxy } from "../client.js";
5
6
  import { shouldAppendTrailingSlash } from "virtual:astro:actions/options";
6
7
  import { ACTION_QUERY_PARAMS } from "../../consts.js";
@@ -12,11 +13,11 @@ const getActionPath = createGetActionPath({
12
13
  });
13
14
  const actions = createActionsProxy({
14
15
  handleAction: async (param, path, context) => {
15
- const pipeline = context ? Reflect.get(context, pipelineSymbol) : void 0;
16
- if (!pipeline) {
16
+ const state = context ? Reflect.get(context, fetchStateSymbol) : void 0;
17
+ if (!state) {
17
18
  throw new AstroError(ActionCalledFromServerError);
18
19
  }
19
- const action = await pipeline.getAction(path);
20
+ const action = await getAction(state.manifest, path);
20
21
  if (!action) throw new Error(`Action not found: ${path}`);
21
22
  return action.bind(context)(param);
22
23
  }
@@ -1,7 +1,9 @@
1
1
  import { stringify as devalueStringify } from "devalue";
2
2
  import * as z from "zod/v4/core";
3
3
  import { shouldAppendForwardSlash } from "../../core/build/util.js";
4
- import { pipelineSymbol, REDIRECT_STATUS_CODES } from "../../core/constants.js";
4
+ import { REDIRECT_STATUS_CODES } from "../../core/constants.js";
5
+ import { getFetchStateFromAPIContext } from "../../core/fetch/fetch-state.js";
6
+ import { getAction } from "../load.js";
5
7
  import {
6
8
  ActionCalledFromServerError,
7
9
  ActionNotFoundError,
@@ -86,21 +88,21 @@ function getActionContext(context) {
86
88
  calledFrom: callerInfo.from,
87
89
  name: callerInfo.name,
88
90
  handler: async () => {
89
- const pipeline = Reflect.get(context, pipelineSymbol);
91
+ const { manifest } = getFetchStateFromAPIContext(context);
90
92
  const callerInfoName = shouldAppendForwardSlash(
91
- pipeline.manifest.trailingSlash,
92
- pipeline.manifest.buildFormat
93
+ manifest.trailingSlash,
94
+ manifest.buildFormat
93
95
  ) ? removeTrailingForwardSlash(callerInfo.name) : callerInfo.name;
94
96
  let baseAction;
95
97
  try {
96
- baseAction = await pipeline.getAction(callerInfoName);
98
+ baseAction = await getAction(manifest, callerInfoName);
97
99
  } catch (error) {
98
100
  if (error instanceof Error && "name" in error && typeof error.name === "string" && error.name === ActionNotFoundError.name) {
99
101
  return { data: void 0, error: new ActionError({ code: "NOT_FOUND" }) };
100
102
  }
101
103
  throw error;
102
104
  }
103
- const bodySizeLimit = pipeline.manifest.actionBodySizeLimit;
105
+ const bodySizeLimit = manifest.actionBodySizeLimit;
104
106
  let input;
105
107
  try {
106
108
  input = await parseRequestBody(context.request, bodySizeLimit);
@@ -15,3 +15,11 @@ export declare const FONT_FORMATS: Array<{
15
15
  }>;
16
16
  export declare const GENERIC_FALLBACK_NAMES: readonly ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded", "emoji", "math", "fangsong"];
17
17
  export declare const FONTS_TYPES_FILE = "fonts.d.ts";
18
+ /**
19
+ * Variable name used in the font-file-url-resolver virtual module to hold
20
+ * the ephemeral font HTTP server address. The incremental build plugin
21
+ * strips the variable declaration (which contains an OS-assigned port that
22
+ * changes every build) from the module source before hashing so that the
23
+ * dependency hash is deterministic across builds.
24
+ */
25
+ export declare const FONTS_SERVER_ADDRESS_PLACEHOLDER = "__ASTRO_FONTS_SERVER_ADDRESS__";
@@ -39,10 +39,12 @@ const GENERIC_FALLBACK_NAMES = [
39
39
  "fangsong"
40
40
  ];
41
41
  const FONTS_TYPES_FILE = "fonts.d.ts";
42
+ const FONTS_SERVER_ADDRESS_PLACEHOLDER = "__ASTRO_FONTS_SERVER_ADDRESS__";
42
43
  export {
43
44
  ASSETS_DIR,
44
45
  CACHE_DIR,
45
46
  DEFAULTS,
47
+ FONTS_SERVER_ADDRESS_PLACEHOLDER,
46
48
  FONTS_TYPES_FILE,
47
49
  FONT_FORMATS,
48
50
  FONT_TYPES,
@@ -26,7 +26,7 @@ declare function npm(options?: Omit<NpmProviderOptions, 'root' | 'readFile'>): F
26
26
  * - [Google](https://docs.astro.build/en/reference/font-provider-reference/#google)
27
27
  * - [Google Icons](https://docs.astro.build/en/reference/font-provider-reference/#google-icons)
28
28
  * - [Local](https://docs.astro.build/en/reference/font-provider-reference/#local)
29
- * - [NPM](TODO:)
29
+ * - [NPM](https://docs.astro.build/en/reference/font-provider-reference/#npm)
30
30
  */
31
31
  export declare const fontProviders: {
32
32
  adobe: typeof adobe;
@@ -94,18 +94,8 @@ function googleicons() {
94
94
  async init(context) {
95
95
  initializedProvider = await provider(context);
96
96
  },
97
- async resolveFont({ familyName, options, ...rest }) {
98
- const patchedOptions = options?.experimental?.glyphs && options.experimental.glyphs.length > 1 ? {
99
- ...options,
100
- experimental: {
101
- ...options.experimental,
102
- glyphs: [options.experimental.glyphs.join(",")]
103
- }
104
- } : options;
105
- return await initializedProvider?.resolveFont(familyName, {
106
- options: patchedOptions,
107
- ...rest
108
- });
97
+ async resolveFont({ familyName, ...rest }) {
98
+ return await initializedProvider?.resolveFont(familyName, rest);
109
99
  },
110
100
  async listFonts() {
111
101
  return await initializedProvider?.listFonts?.();
@@ -13,6 +13,7 @@ import {
13
13
  ASSETS_DIR,
14
14
  CACHE_DIR,
15
15
  DEFAULTS,
16
+ FONTS_SERVER_ADDRESS_PLACEHOLDER,
16
17
  RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID,
17
18
  RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
18
19
  RESOLVED_VIRTUAL_MODULE_ID,
@@ -285,9 +286,10 @@ function fontsPlugin({ settings, sync, logger }) {
285
286
  return {
286
287
  code: `
287
288
  import { RemoteRuntimeFontFileUrlResolver } from ${JSON.stringify(new URL("./infra/remote-runtime-font-file-url-resolver.js", import.meta.url))};
289
+ const ${FONTS_SERVER_ADDRESS_PLACEHOLDER} = ${JSON.stringify(serverAddress)};
288
290
  export const runtimeFontFileUrlResolver = new RemoteRuntimeFontFileUrlResolver({
289
291
  urls: new Set(${JSON.stringify(urls)}),
290
- address: ${JSON.stringify(serverAddress)},
292
+ address: ${FONTS_SERVER_ADDRESS_PLACEHOLDER},
291
293
  });
292
294
  `
293
295
  };
@@ -36,6 +36,35 @@ async function handleSvgDeduplication(fileData, filename, fileEmitter) {
36
36
  return handle;
37
37
  }
38
38
  }
39
+ const TRANSIENT_ERROR_CODES = /* @__PURE__ */ new Set(["EMFILE", "ENFILE", "EAGAIN", "EBUSY"]);
40
+ const MAX_CONCURRENT_READS = 200;
41
+ let activeReads = 0;
42
+ const readQueue = [];
43
+ async function readFileWithRetry(url, maxRetries = 5) {
44
+ if (activeReads >= MAX_CONCURRENT_READS) {
45
+ await new Promise((resolve) => readQueue.push(resolve));
46
+ }
47
+ activeReads++;
48
+ try {
49
+ for (let attempt = 0; ; attempt++) {
50
+ try {
51
+ return await fs.readFile(url);
52
+ } catch (err) {
53
+ const code = err instanceof Error && "code" in err ? err.code : void 0;
54
+ if (code && TRANSIENT_ERROR_CODES.has(code) && attempt < maxRetries) {
55
+ await new Promise((resolve) => setTimeout(resolve, 50 * 2 ** attempt));
56
+ continue;
57
+ }
58
+ throw err;
59
+ }
60
+ }
61
+ } finally {
62
+ activeReads--;
63
+ if (readQueue.length > 0) {
64
+ readQueue.shift()();
65
+ }
66
+ }
67
+ }
39
68
  async function emitImageMetadata(id, fileEmitter) {
40
69
  if (!id) {
41
70
  return void 0;
@@ -43,9 +72,12 @@ async function emitImageMetadata(id, fileEmitter) {
43
72
  const url = pathToFileURL(id);
44
73
  let fileData;
45
74
  try {
46
- fileData = await fs.readFile(url);
47
- } catch {
48
- return void 0;
75
+ fileData = await readFileWithRetry(url);
76
+ } catch (err) {
77
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
78
+ return void 0;
79
+ }
80
+ throw err;
49
81
  }
50
82
  const fileMetadata = await imageMetadata(fileData, id);
51
83
  const emittedImage = {
@@ -128,7 +128,7 @@ Run \`astro dev --help\` to see available commands.`
128
128
  }
129
129
  const root = pathToFileURL(resolveRoot(flags.root) + "/");
130
130
  if (ignoreLock) {
131
- const existingServer2 = checkExistingServer(root);
131
+ const existingServer2 = await checkExistingServer(root);
132
132
  if (existingServer2) {
133
133
  logger.info(
134
134
  "SKIP_FORMAT",
@@ -141,7 +141,7 @@ Run \`astro dev --help\` to see available commands.`
141
141
  const inlineConfig2 = flagsToAstroInlineConfig(flags);
142
142
  return await devServer(inlineConfig2);
143
143
  }
144
- const existingServer = checkExistingServer(root);
144
+ const existingServer = await checkExistingServer(root);
145
145
  if (existingServer) {
146
146
  if (flags.force) {
147
147
  await killDevServer(root, existingServer);
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.2.1";
3
+ version = "7.2.3";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -69,7 +69,7 @@ Run \`astro preview --help\` to see available commands.`
69
69
  process.exit(1);
70
70
  }
71
71
  const root = pathToFileURL(resolveRoot(flags.root) + "/");
72
- const existingServer = checkExistingServer(root, "preview");
72
+ const existingServer = await checkExistingServer(root, "preview");
73
73
  if (existingServer) {
74
74
  const message = [
75
75
  "Another astro preview server is already running.",
@@ -101,7 +101,7 @@ async function background({
101
101
  config
102
102
  }) {
103
103
  const root = getRootURL(flags);
104
- const existing = checkExistingServer(root, config.command);
104
+ const existing = await checkExistingServer(root, config.command);
105
105
  if (existing && !flags.force) {
106
106
  logger.info("SKIP_FORMAT", formatServerRunningMessage(existing, config, { existing: true }));
107
107
  return;
@@ -160,7 +160,7 @@ async function stop({
160
160
  config
161
161
  }) {
162
162
  const root = getRootURL(flags);
163
- const existing = checkExistingServer(root, config.command);
163
+ const existing = await checkExistingServer(root, config.command);
164
164
  if (!existing) {
165
165
  logger.info("SKIP_FORMAT", `No ${config.command} server is running.`);
166
166
  return;
@@ -174,7 +174,7 @@ async function status({
174
174
  config
175
175
  }) {
176
176
  const root = getRootURL(flags);
177
- const existing = checkExistingServer(root, config.command);
177
+ const existing = await checkExistingServer(root, config.command);
178
178
  if (!existing) {
179
179
  logger.info("SKIP_FORMAT", `No ${config.command} server is running.`);
180
180
  return;
@@ -198,7 +198,7 @@ async function logs({
198
198
  config
199
199
  }) {
200
200
  const root = getRootURL(flags);
201
- const existing = checkExistingServer(root, config.command);
201
+ const existing = await checkExistingServer(root, config.command);
202
202
  if (!existing) {
203
203
  logger.error("SKIP_FORMAT", `No ${config.command} server is running.`);
204
204
  process.exit(1);
@@ -0,0 +1,20 @@
1
+ import type { RouteData, SSRLoadedRenderer, SSRResult } from '../types/public/internal.js';
2
+ import type { SinglePageBuiltModule } from '../core/build/types.js';
3
+ import type { RenderEnvironment } from '../core/environment/index.js';
4
+ export interface ContainerEnvironmentOptions {
5
+ /**
6
+ * The route → module interner. Created by `experimental_AstroContainer`'s
7
+ * constructor and shared with its `insertRoute` writes; this record owns
8
+ * the lookups.
9
+ */
10
+ interner: WeakMap<RouteData, SinglePageBuiltModule>;
11
+ resolve: SSRResult['resolve'];
12
+ renderers: SSRLoadedRenderer[];
13
+ streaming: boolean;
14
+ }
15
+ /**
16
+ * The container environment. Registered by `experimental_AstroContainer`'s
17
+ * constructor on its fabricated manifest — the container never touches the
18
+ * ambient manifest, so multiple containers in one process stay isolated.
19
+ */
20
+ export declare function createContainerEnvironment({ interner, resolve, renderers, streaming, }: ContainerEnvironmentOptions): RenderEnvironment;
@@ -0,0 +1,106 @@
1
+ import { RedirectSinglePageBuiltModule } from "../core/redirects/index.js";
2
+ import {
3
+ createModuleScriptElement,
4
+ createStylesheetElementSet
5
+ } from "../core/render/ssr-element.js";
6
+ import { getDefaultRoutes } from "../core/routing/default.js";
7
+ import { findRouteToRewrite } from "../core/routing/rewrite.js";
8
+ async function getModuleForRoute(manifest, route) {
9
+ for (const defaultRoute of getDefaultRoutes(manifest)) {
10
+ if (route.component === defaultRoute.component) {
11
+ return {
12
+ page: () => Promise.resolve(defaultRoute.instance)
13
+ };
14
+ }
15
+ }
16
+ if (route.type === "redirect") {
17
+ return RedirectSinglePageBuiltModule;
18
+ } else {
19
+ if (manifest.pageMap) {
20
+ const importComponentInstance = manifest.pageMap.get(route.component);
21
+ if (!importComponentInstance) {
22
+ throw new Error(
23
+ `Unexpectedly unable to find a component instance for route ${route.route}`
24
+ );
25
+ }
26
+ return await importComponentInstance();
27
+ } else if (manifest.pageModule) {
28
+ return manifest.pageModule;
29
+ }
30
+ throw new Error(
31
+ "Astro couldn't find the correct page to render, probably because it wasn't correctly mapped for SSR usage. This is an internal error, please file an issue."
32
+ );
33
+ }
34
+ }
35
+ function createContainerEnvironment({
36
+ interner,
37
+ resolve,
38
+ renderers,
39
+ streaming
40
+ }) {
41
+ async function getComponentByRoute(_manifest, routeData) {
42
+ const page = interner.get(routeData);
43
+ if (page) {
44
+ return page.page();
45
+ }
46
+ throw new Error("Couldn't find component for route " + routeData.pathname);
47
+ }
48
+ return {
49
+ name: "container",
50
+ runtimeMode: "development",
51
+ defaultStreaming: () => streaming,
52
+ async resolve(_manifest, specifier) {
53
+ return resolve(specifier);
54
+ },
55
+ headElements(manifest, routeData) {
56
+ const routeInfo = manifest.routes.find((route) => route.routeData === routeData);
57
+ const links = /* @__PURE__ */ new Set();
58
+ const scripts = /* @__PURE__ */ new Set();
59
+ const styles = createStylesheetElementSet(routeInfo?.styles ?? []);
60
+ for (const script of routeInfo?.scripts ?? []) {
61
+ if ("stage" in script) {
62
+ if (script.stage === "head-inline") {
63
+ scripts.add({
64
+ props: {},
65
+ children: script.children
66
+ });
67
+ }
68
+ } else {
69
+ scripts.add(createModuleScriptElement(script));
70
+ }
71
+ }
72
+ return { links, styles, scripts };
73
+ },
74
+ componentMetadata() {
75
+ },
76
+ getComponentByRoute,
77
+ getModuleForRoute,
78
+ async tryRewrite(manifest, payload, request) {
79
+ const { newUrl, pathname, routeData } = findRouteToRewrite({
80
+ payload,
81
+ request,
82
+ // PER-CALL scan of the live manifest routes: the container inserts
83
+ // routes at runtime (`insertRoute` pushes into `manifest.routes`),
84
+ // and an uncompiled scan sees them immediately. Reading the derived
85
+ // route table here would miss them.
86
+ routes: manifest.routes.map((r) => r.routeData),
87
+ trailingSlash: manifest.trailingSlash,
88
+ buildFormat: manifest.buildFormat,
89
+ base: manifest.base,
90
+ outDir: manifest.outDir
91
+ });
92
+ const componentInstance = await getComponentByRoute(manifest, routeData);
93
+ return { componentInstance, routeData, newUrl, pathname };
94
+ },
95
+ getRenderers() {
96
+ return renderers;
97
+ },
98
+ errorStrategy: "default",
99
+ injectCspMetaTagsOnErrorPages: false,
100
+ logRequest() {
101
+ }
102
+ };
103
+ }
104
+ export {
105
+ createContainerEnvironment
106
+ };