astro 6.1.10 → 6.2.1

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 (128) hide show
  1. package/client.d.ts +1 -0
  2. package/dist/actions/runtime/types.d.ts +1 -1
  3. package/dist/assets/fonts/constants.d.ts +2 -0
  4. package/dist/assets/fonts/constants.js +4 -0
  5. package/dist/assets/fonts/core/create-get-font-file-url.d.ts +2 -0
  6. package/dist/assets/fonts/core/create-get-font-file-url.js +23 -0
  7. package/dist/assets/fonts/core/font-file-middleware.d.ts +21 -0
  8. package/dist/assets/fonts/core/font-file-middleware.js +59 -0
  9. package/dist/assets/fonts/definitions.d.ts +13 -0
  10. package/dist/assets/fonts/infra/build-url-resolver.d.ts +1 -0
  11. package/dist/assets/fonts/infra/build-url-resolver.js +7 -1
  12. package/dist/assets/fonts/infra/dev-url-resolver.d.ts +1 -0
  13. package/dist/assets/fonts/infra/dev-url-resolver.js +7 -1
  14. package/dist/assets/fonts/infra/remote-runtime-font-file-url-resolver.d.ts +19 -0
  15. package/dist/assets/fonts/infra/remote-runtime-font-file-url-resolver.js +27 -0
  16. package/dist/assets/fonts/infra/ssr-runtime-font-file-url-resolver.d.ts +12 -0
  17. package/dist/assets/fonts/infra/ssr-runtime-font-file-url-resolver.js +25 -0
  18. package/dist/assets/fonts/runtime.d.ts +1 -0
  19. package/dist/assets/fonts/runtime.js +4 -0
  20. package/dist/assets/fonts/vite-plugin-fonts.js +88 -49
  21. package/dist/assets/index.d.ts +1 -1
  22. package/dist/assets/index.js +3 -2
  23. package/dist/assets/svg/config.d.ts +5 -0
  24. package/dist/assets/svg/config.js +8 -0
  25. package/dist/assets/svg/svgo.d.ts +4 -0
  26. package/dist/assets/svg/svgo.js +10 -0
  27. package/dist/assets/svg/types.d.ts +4 -0
  28. package/dist/assets/svg/types.js +0 -0
  29. package/dist/assets/svg/utils.d.ts +3 -0
  30. package/dist/assets/{utils/svg.js → svg/utils.js} +11 -14
  31. package/dist/assets/vite-plugin-assets.js +8 -4
  32. package/dist/cli/flags.js +19 -9
  33. package/dist/cli/help/index.js +2 -1
  34. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  35. package/dist/cli/preferences/index.js +3 -2
  36. package/dist/config/entrypoint.d.ts +2 -0
  37. package/dist/config/entrypoint.js +4 -0
  38. package/dist/config/index.js +9 -7
  39. package/dist/container/index.js +4 -7
  40. package/dist/content/content-layer.js +3 -3
  41. package/dist/core/app/base.d.ts +18 -4
  42. package/dist/core/app/base.js +29 -12
  43. package/dist/core/app/dev/app.d.ts +0 -1
  44. package/dist/core/app/dev/app.js +0 -2
  45. package/dist/core/app/entrypoints/index.d.ts +1 -1
  46. package/dist/core/app/entrypoints/index.js +1 -1
  47. package/dist/core/app/entrypoints/virtual/dev.js +1 -1
  48. package/dist/core/app/pipeline.js +2 -2
  49. package/dist/core/app/types.d.ts +10 -3
  50. package/dist/core/base-pipeline.d.ts +9 -2
  51. package/dist/core/base-pipeline.js +17 -0
  52. package/dist/core/build/app.js +2 -1
  53. package/dist/core/build/index.js +13 -2
  54. package/dist/core/build/internal.d.ts +1 -0
  55. package/dist/core/build/internal.js +1 -0
  56. package/dist/core/build/pipeline.js +1 -1
  57. package/dist/core/build/plugins/plugin-manifest.js +6 -1
  58. package/dist/core/cache/types.d.ts +2 -0
  59. package/dist/core/config/schemas/base.d.ts +16 -8
  60. package/dist/core/config/schemas/base.js +17 -10
  61. package/dist/core/config/schemas/relative.d.ts +31 -13
  62. package/dist/core/config/schemas/relative.js +3 -4
  63. package/dist/core/config/settings.js +2 -1
  64. package/dist/core/config/vite-load.js +4 -17
  65. package/dist/core/constants.js +1 -1
  66. package/dist/core/createMinimalViteDevServer.d.ts +8 -0
  67. package/dist/core/createMinimalViteDevServer.js +15 -0
  68. package/dist/core/dev/dev.js +1 -1
  69. package/dist/core/dev/restart.js +2 -2
  70. package/dist/core/errors/errors-data.d.ts +48 -2
  71. package/dist/core/errors/errors-data.js +26 -2
  72. package/dist/core/errors/zod-error-map.js +27 -0
  73. package/dist/core/logger/config.d.ts +6 -0
  74. package/dist/core/logger/config.js +0 -0
  75. package/dist/core/logger/core.d.ts +33 -13
  76. package/dist/core/logger/core.js +50 -5
  77. package/dist/core/logger/handlers.d.ts +60 -0
  78. package/dist/core/logger/handlers.js +81 -0
  79. package/dist/core/logger/impls/compose.d.ts +2 -0
  80. package/dist/core/logger/impls/compose.js +26 -0
  81. package/dist/core/logger/impls/console.d.ts +9 -0
  82. package/dist/core/logger/impls/console.js +38 -0
  83. package/dist/core/logger/impls/json.d.ts +15 -0
  84. package/dist/core/logger/impls/json.js +42 -0
  85. package/dist/core/logger/impls/node.d.ts +7 -0
  86. package/dist/core/logger/impls/node.js +40 -0
  87. package/dist/core/logger/load.d.ts +11 -0
  88. package/dist/core/logger/load.js +88 -0
  89. package/dist/core/logger/node.d.ts +0 -5
  90. package/dist/core/logger/node.js +1 -39
  91. package/dist/core/logger/public.d.ts +17 -0
  92. package/dist/core/logger/public.js +7 -0
  93. package/dist/core/messages/runtime.js +1 -1
  94. package/dist/core/middleware/index.js +2 -1
  95. package/dist/core/preview/index.js +4 -3
  96. package/dist/core/render-context.js +35 -1
  97. package/dist/core/sync/index.js +2 -2
  98. package/dist/core/wait-until.d.ts +1 -0
  99. package/dist/core/wait-until.js +0 -0
  100. package/dist/manifest/serialized.js +6 -1
  101. package/dist/runtime/compiler/index.d.ts +1 -1
  102. package/dist/runtime/compiler/index.js +4 -0
  103. package/dist/runtime/server/astro-global.js +3 -0
  104. package/dist/runtime/server/index.d.ts +1 -0
  105. package/dist/runtime/server/index.js +3 -0
  106. package/dist/runtime/server/render/common.js +16 -0
  107. package/dist/runtime/server/render/instruction.d.ts +7 -1
  108. package/dist/runtime/server/render/template-depth.d.ts +13 -0
  109. package/dist/runtime/server/render/template-depth.js +11 -0
  110. package/dist/types/astro.d.ts +2 -0
  111. package/dist/types/public/common.d.ts +1 -0
  112. package/dist/types/public/config.d.ts +54 -42
  113. package/dist/types/public/context.d.ts +17 -0
  114. package/dist/types/public/index.d.ts +1 -0
  115. package/dist/types/public/internal.d.ts +7 -1
  116. package/dist/types/public/preview.d.ts +5 -0
  117. package/dist/vite-plugin-app/app.d.ts +0 -1
  118. package/dist/vite-plugin-app/app.js +0 -2
  119. package/dist/vite-plugin-app/createAstroServerApp.d.ts +1 -1
  120. package/dist/vite-plugin-app/createAstroServerApp.js +2 -6
  121. package/dist/vite-plugin-load-fallback/index.d.ts +1 -1
  122. package/dist/vite-plugin-load-fallback/index.js +2 -5
  123. package/package.json +8 -3
  124. package/dist/assets/utils/svg.d.ts +0 -3
  125. package/dist/core/app/logging.d.ts +0 -3
  126. package/dist/core/app/logging.js +0 -11
  127. package/dist/core/logger/console.d.ts +0 -2
  128. package/dist/core/logger/console.js +0 -21
package/client.d.ts CHANGED
@@ -60,6 +60,7 @@ declare module 'astro:assets' {
60
60
  import('astro:assets').CssVariable,
61
61
  Array<import('astro:assets').FontData>
62
62
  >;
63
+ export const experimental_getFontFileURL: typeof import('./dist/assets/fonts/runtime.js').experimental_getFontFileURL;
63
64
 
64
65
  type ImgAttributes = import('./dist/type-utils.js').WithRequired<
65
66
  Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>,
@@ -49,7 +49,7 @@ export interface ActionsLocals {
49
49
  actionName: string;
50
50
  };
51
51
  }
52
- export type ActionAPIContext = Pick<APIContext, 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'cache' | 'csp'>;
52
+ export type ActionAPIContext = Pick<APIContext, 'request' | 'url' | 'isPrerendered' | 'locals' | 'clientAddress' | 'cookies' | 'currentLocale' | 'generator' | 'routePattern' | 'site' | 'params' | 'preferredLocale' | 'preferredLocaleList' | 'originPathname' | 'session' | 'cache' | 'csp' | 'logger'>;
53
53
  export type MaybePromise<T> = T | Promise<T>;
54
54
  /**
55
55
  * Used to preserve the input schema type in the error object.
@@ -4,6 +4,8 @@ export declare const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
4
4
  export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
5
5
  export declare const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
6
6
  export declare const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID: string;
7
+ export declare const RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime/font-file-url-resolver";
8
+ export declare const RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID: string;
7
9
  export declare const ASSETS_DIR = "fonts";
8
10
  export declare const CACHE_DIR = "./fonts/";
9
11
  export declare const FONT_TYPES: readonly ["woff2", "woff", "otf", "ttf", "eot"];
@@ -11,6 +11,8 @@ const VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/internal";
11
11
  const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
12
12
  const RUNTIME_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime";
13
13
  const RESOLVED_RUNTIME_VIRTUAL_MODULE_ID = "\0" + RUNTIME_VIRTUAL_MODULE_ID;
14
+ const RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID = "virtual:astro:assets/fonts/runtime/font-file-url-resolver";
15
+ const RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID = "\0" + RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID;
14
16
  const ASSETS_DIR = "fonts";
15
17
  const CACHE_DIR = "./fonts/";
16
18
  const FONT_TYPES = ["woff2", "woff", "otf", "ttf", "eot"];
@@ -45,8 +47,10 @@ export {
45
47
  FONT_FORMATS,
46
48
  FONT_TYPES,
47
49
  GENERIC_FALLBACK_NAMES,
50
+ RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID,
48
51
  RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
49
52
  RESOLVED_VIRTUAL_MODULE_ID,
53
+ RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID,
50
54
  RUNTIME_VIRTUAL_MODULE_ID,
51
55
  VIRTUAL_MODULE_ID
52
56
  };
@@ -0,0 +1,2 @@
1
+ import type { RuntimeFontFileUrlResolver } from '../definitions.js';
2
+ export declare function createGetFontFileURL(runtimeFontFileUrlResolver: RuntimeFontFileUrlResolver): (url: string, requestUrl?: URL) => string;
@@ -0,0 +1,23 @@
1
+ import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
2
+ function createGetFontFileURL(runtimeFontFileUrlResolver) {
3
+ return function getFontFileURL(url, requestUrl) {
4
+ try {
5
+ const result = runtimeFontFileUrlResolver.resolve(url, requestUrl);
6
+ if (result === null) {
7
+ throw new Error("Not found");
8
+ }
9
+ return result;
10
+ } catch (cause) {
11
+ throw new AstroError(
12
+ {
13
+ ...AstroErrorData.FontFileUrlNotFound,
14
+ message: AstroErrorData.FontFileUrlNotFound.message(url)
15
+ },
16
+ { cause }
17
+ );
18
+ }
19
+ };
20
+ }
21
+ export {
22
+ createGetFontFileURL
23
+ };
@@ -0,0 +1,21 @@
1
+ import type { AstroLogger } from '../../../core/logger/core.js';
2
+ import type { FontFetcher, FontTypeExtractor } from '../definitions.js';
3
+ import type { FontFileById } from '../types.js';
4
+ import type { ServerResponse } from 'node:http';
5
+ interface MinimalResponse {
6
+ setHeader: (name: string, value: string) => void;
7
+ end: (buffer?: Buffer) => void;
8
+ setStatusCode: (statusCode: number) => void;
9
+ }
10
+ interface Options {
11
+ url: string | undefined;
12
+ response: MinimalResponse;
13
+ next: () => void;
14
+ fontFetcher: FontFetcher | null;
15
+ fontTypeExtractor: FontTypeExtractor | null;
16
+ logger: AstroLogger;
17
+ fontFileById: FontFileById | null;
18
+ }
19
+ export declare function resToMinimalResponse(res: ServerResponse): MinimalResponse;
20
+ export declare function fontFileMiddleware({ url: _url, response, next, fontFetcher, fontTypeExtractor, logger, fontFileById, }: Options): Promise<void>;
21
+ export {};
@@ -0,0 +1,59 @@
1
+ import { isAstroError } from "../../../core/errors/errors.js";
2
+ import { formatErrorMessage } from "../../../core/messages/runtime.js";
3
+ import { collectErrorMetadata } from "../../../core/errors/dev/utils.js";
4
+ function resToMinimalResponse(res) {
5
+ return {
6
+ setHeader: (...args) => res.setHeader(...args),
7
+ end: (...args) => res.end(...args),
8
+ setStatusCode: (statusCode) => {
9
+ res.statusCode = statusCode;
10
+ }
11
+ };
12
+ }
13
+ async function fontFileMiddleware({
14
+ url: _url,
15
+ response,
16
+ next,
17
+ fontFetcher,
18
+ fontTypeExtractor,
19
+ logger,
20
+ fontFileById
21
+ }) {
22
+ if (!fontFetcher || !fontTypeExtractor || !fontFileById) {
23
+ logger.debug("assets", "Fonts dependencies should be initialized by now, skipping middleware.");
24
+ return next();
25
+ }
26
+ if (!_url) {
27
+ return next();
28
+ }
29
+ const url = new URL(_url, "http://localhost");
30
+ const fontId = url.pathname.slice(1);
31
+ const fontData = fontFileById.get(fontId);
32
+ if (!fontData) {
33
+ return next();
34
+ }
35
+ response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
36
+ response.setHeader("Pragma", "no-cache");
37
+ response.setHeader("Expires", "0");
38
+ try {
39
+ const buffer = await fontFetcher.fetch({ id: fontId, ...fontData });
40
+ response.setHeader("Content-Length", buffer.byteLength.toString());
41
+ response.setHeader("Content-Type", `font/${fontTypeExtractor.extract(fontId)}`);
42
+ response.setStatusCode(200);
43
+ response.end(buffer);
44
+ } catch (err) {
45
+ logger.error("assets", "Cannot download font file");
46
+ if (isAstroError(err)) {
47
+ logger.error(
48
+ "SKIP_FORMAT",
49
+ formatErrorMessage(collectErrorMetadata(err), logger.level() === "debug")
50
+ );
51
+ }
52
+ response.setStatusCode(500);
53
+ response.end();
54
+ }
55
+ }
56
+ export {
57
+ fontFileMiddleware,
58
+ resToMinimalResponse
59
+ };
@@ -8,6 +8,7 @@ export interface Hasher {
8
8
  export interface UrlResolver {
9
9
  resolve: (id: string) => string;
10
10
  readonly cspResources: Array<string>;
11
+ readonly urls: Array<string>;
11
12
  }
12
13
  export interface FontFileContentResolver {
13
14
  resolve: (url: string) => string;
@@ -70,3 +71,15 @@ export interface FontResolver {
70
71
  provider: FontProvider;
71
72
  }) => Promise<string[] | undefined>;
72
73
  }
74
+ export interface RuntimeFontFileUrlResolver {
75
+ /**
76
+ * @param url
77
+ * URL obtained from `fontData` and provided by the user. Can look like
78
+ * `/_astro/fonts/<hash>.<ext>` or be a full URL when using assetsPrefix.
79
+ *
80
+ * @param requestUrl
81
+ * The current request URL. It can be used to construct a full URL to the
82
+ * font file, for example in SSR.
83
+ */
84
+ resolve: (url: string, requestUrl: URL | undefined) => string | null;
85
+ }
@@ -9,4 +9,5 @@ export declare class BuildUrlResolver implements UrlResolver {
9
9
  });
10
10
  resolve(id: string): string;
11
11
  get cspResources(): Array<string>;
12
+ get urls(): Array<string>;
12
13
  }
@@ -3,6 +3,7 @@ import { getAssetsPrefix } from "../../utils/getAssetsPrefix.js";
3
3
  import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
4
4
  class BuildUrlResolver {
5
5
  #resources = /* @__PURE__ */ new Set();
6
+ #urls = /* @__PURE__ */ new Set();
6
7
  #base;
7
8
  #assetsPrefix;
8
9
  #searchParams;
@@ -29,11 +30,16 @@ class BuildUrlResolver {
29
30
  this.#searchParams.forEach((value, key) => {
30
31
  url.searchParams.set(key, value);
31
32
  });
32
- return stringifyPlaceholderURL(url);
33
+ const result = stringifyPlaceholderURL(url);
34
+ this.#urls.add(result);
35
+ return result;
33
36
  }
34
37
  get cspResources() {
35
38
  return Array.from(this.#resources);
36
39
  }
40
+ get urls() {
41
+ return Array.from(this.#urls);
42
+ }
37
43
  }
38
44
  export {
39
45
  BuildUrlResolver
@@ -7,4 +7,5 @@ export declare class DevUrlResolver implements UrlResolver {
7
7
  });
8
8
  resolve(id: string): string;
9
9
  get cspResources(): Array<string>;
10
+ get urls(): Array<string>;
10
11
  }
@@ -1,6 +1,7 @@
1
1
  import { joinPaths, prependForwardSlash } from "../../../core/path.js";
2
2
  import { createPlaceholderURL, stringifyPlaceholderURL } from "../../utils/url.js";
3
3
  class DevUrlResolver {
4
+ #urls = /* @__PURE__ */ new Set();
4
5
  #resolved = false;
5
6
  #base;
6
7
  #searchParams;
@@ -18,11 +19,16 @@ class DevUrlResolver {
18
19
  this.#searchParams.forEach((value, key) => {
19
20
  url.searchParams.set(key, value);
20
21
  });
21
- return stringifyPlaceholderURL(url);
22
+ const result = stringifyPlaceholderURL(url);
23
+ this.#urls.add(result);
24
+ return result;
22
25
  }
23
26
  get cspResources() {
24
27
  return this.#resolved ? ["'self'"] : [];
25
28
  }
29
+ get urls() {
30
+ return Array.from(this.#urls);
31
+ }
26
32
  }
27
33
  export {
28
34
  DevUrlResolver
@@ -0,0 +1,19 @@
1
+ import type { AddressInfo } from 'node:net';
2
+ import type { RuntimeFontFileUrlResolver } from '../definitions.js';
3
+ /**
4
+ * In development, font files are served through a Vite middleware.
5
+ * During prerendering, a temporary Node HTTP server is started to
6
+ * serve font files.
7
+ *
8
+ * We send request to the provided server address. `requestUrl` on
9
+ * `fetch` is not implemented because we have the information from
10
+ * within the Vite plugin already.
11
+ */
12
+ export declare class RemoteRuntimeFontFileUrlResolver implements RuntimeFontFileUrlResolver {
13
+ #private;
14
+ constructor({ urls, address, }: {
15
+ urls: Set<string>;
16
+ address: AddressInfo | null;
17
+ });
18
+ resolve(url: string): string | null;
19
+ }
@@ -0,0 +1,27 @@
1
+ class RemoteRuntimeFontFileUrlResolver {
2
+ #urls;
3
+ #address;
4
+ constructor({
5
+ urls,
6
+ address
7
+ }) {
8
+ this.#urls = urls;
9
+ this.#address = address;
10
+ }
11
+ resolve(url) {
12
+ if (!this.#urls.has(url)) {
13
+ return null;
14
+ }
15
+ if (!this.#address) {
16
+ throw new Error("Server address unavailable, this should not happen. Open an issue.");
17
+ }
18
+ if (!url.startsWith("/")) {
19
+ url = new URL(url).pathname;
20
+ }
21
+ const host = this.#address.family === "IPv6" ? `[${this.#address.address}]` : this.#address.address;
22
+ return `http://${host}:${this.#address.port}${url}`;
23
+ }
24
+ }
25
+ export {
26
+ RemoteRuntimeFontFileUrlResolver
27
+ };
@@ -0,0 +1,12 @@
1
+ import type { RuntimeFontFileUrlResolver } from '../definitions.js';
2
+ /**
3
+ * During SSR, we don't know ahead of time where the server is located.
4
+ * We rely on `requestUrl` (provided by the user) to construct the URL.
5
+ */
6
+ export declare class SsrRuntimeFontFileUrlResolver implements RuntimeFontFileUrlResolver {
7
+ #private;
8
+ constructor({ urls, }: {
9
+ urls: Set<string>;
10
+ });
11
+ resolve(url: string, requestUrl: URL | undefined): string | null;
12
+ }
@@ -0,0 +1,25 @@
1
+ import { MissingGetFontFileRequestUrl } from "../../../core/errors/errors-data.js";
2
+ import { AstroError } from "../../../core/errors/errors.js";
3
+ class SsrRuntimeFontFileUrlResolver {
4
+ #urls;
5
+ constructor({
6
+ urls
7
+ }) {
8
+ this.#urls = urls;
9
+ }
10
+ resolve(url, requestUrl) {
11
+ if (!this.#urls.has(url)) {
12
+ return null;
13
+ }
14
+ if (!url.startsWith("/")) {
15
+ return url;
16
+ }
17
+ if (!requestUrl) {
18
+ throw new AstroError(MissingGetFontFileRequestUrl);
19
+ }
20
+ return `${requestUrl.origin}${url}`;
21
+ }
22
+ }
23
+ export {
24
+ SsrRuntimeFontFileUrlResolver
25
+ };
@@ -1 +1,2 @@
1
1
  export declare const fontData: import("./types.js").FontDataByCssVariable;
2
+ export declare const experimental_getFontFileURL: (url: string, requestUrl?: URL) => string;
@@ -1,5 +1,9 @@
1
1
  import { fontDataByCssVariable } from "virtual:astro:assets/fonts/internal";
2
+ import { runtimeFontFileUrlResolver } from "virtual:astro:assets/fonts/runtime/font-file-url-resolver";
3
+ import { createGetFontFileURL } from "./core/create-get-font-file-url.js";
2
4
  const fontData = fontDataByCssVariable;
5
+ const experimental_getFontFileURL = createGetFontFileURL(runtimeFontFileUrlResolver);
3
6
  export {
7
+ experimental_getFontFileURL,
4
8
  fontData
5
9
  };
@@ -1,20 +1,22 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { readFile } from "node:fs/promises";
3
+ import { createServer } from "node:http";
3
4
  import { isAbsolute } from "node:path";
4
5
  import colors from "piccolore";
6
+ import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../../core/constants.js";
5
7
  import { getAlgorithm, shouldTrackCspHashes } from "../../core/csp/common.js";
6
8
  import { generateCspDigest } from "../../core/encryption.js";
7
- import { collectErrorMetadata } from "../../core/errors/dev/utils.js";
8
- import { AstroError, AstroErrorData, isAstroError } from "../../core/errors/index.js";
9
- import { formatErrorMessage } from "../../core/messages/runtime.js";
9
+ import { AstroError, AstroErrorData } from "../../core/errors/index.js";
10
10
  import { appendForwardSlash, joinPaths, prependForwardSlash } from "../../core/path.js";
11
11
  import { getClientOutputDirectory } from "../../prerender/utils.js";
12
12
  import {
13
13
  ASSETS_DIR,
14
14
  CACHE_DIR,
15
15
  DEFAULTS,
16
+ RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID,
16
17
  RESOLVED_RUNTIME_VIRTUAL_MODULE_ID,
17
18
  RESOLVED_VIRTUAL_MODULE_ID,
19
+ RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID,
18
20
  RUNTIME_VIRTUAL_MODULE_ID,
19
21
  VIRTUAL_MODULE_ID
20
22
  } from "./constants.js";
@@ -40,6 +42,7 @@ import { RealSystemFallbacksProvider } from "./infra/system-fallbacks-provider.j
40
42
  import { UnifontFontResolver } from "./infra/unifont-font-resolver.js";
41
43
  import { UnstorageFsStorage } from "./infra/unstorage-fs-storage.js";
42
44
  import { XxhashHasher } from "./infra/xxhash-hasher.js";
45
+ import { fontFileMiddleware, resToMinimalResponse } from "./core/font-file-middleware.js";
43
46
  function fontsPlugin({ settings, sync, logger }) {
44
47
  const assetsDir = prependForwardSlash(
45
48
  appendForwardSlash(joinPaths(settings.config.build.assets, ASSETS_DIR))
@@ -48,26 +51,27 @@ function fontsPlugin({ settings, sync, logger }) {
48
51
  let fontFileById = null;
49
52
  let componentDataByCssVariable = null;
50
53
  let fontDataByCssVariable = null;
51
- let isBuild;
52
54
  let fontFetcher = null;
53
55
  let fontTypeExtractor = null;
54
56
  let built = false;
55
- const cleanup = () => {
57
+ let serverAddress = null;
58
+ let urls = null;
59
+ function cleanup() {
56
60
  componentDataByCssVariable = null;
57
61
  fontDataByCssVariable = null;
58
62
  fontFileById = null;
59
63
  fontFetcher = null;
60
- };
64
+ serverAddress = null;
65
+ urls = null;
66
+ }
61
67
  return {
62
68
  name: "astro:fonts",
63
- config(_, { command }) {
64
- isBuild = command === "build";
65
- },
66
69
  async buildStart() {
67
70
  if (sync) {
68
71
  return;
69
72
  }
70
73
  const { root } = settings.config;
74
+ const isBuild = this.environment.config.command === "build";
71
75
  const hasher = await XxhashHasher.create();
72
76
  const storage = new UnstorageFsStorage({
73
77
  // In dev, we cache fonts data in .astro so it can be easily inspected and cleared
@@ -160,8 +164,39 @@ function fontsPlugin({ settings, sync, logger }) {
160
164
  settings.injectedCsp.fontResources.add(resource);
161
165
  }
162
166
  }
167
+ urls = urlResolver.urls;
168
+ if (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender && fontFileById.size > 0) {
169
+ settings.fontsHttpServer = await new Promise((r) => {
170
+ const server = createServer((req, res) => {
171
+ const next = () => {
172
+ if (!res.writableEnded) {
173
+ res.writeHead(404);
174
+ res.end();
175
+ }
176
+ };
177
+ if (req.url?.startsWith(baseUrl)) {
178
+ return fontFileMiddleware({
179
+ url: req.url.slice(baseUrl.length - 1),
180
+ response: resToMinimalResponse(res),
181
+ next,
182
+ fontFetcher,
183
+ fontFileById,
184
+ fontTypeExtractor,
185
+ logger
186
+ });
187
+ }
188
+ return next();
189
+ }).listen(() => {
190
+ r(server);
191
+ });
192
+ });
193
+ serverAddress = settings.fontsHttpServer.address();
194
+ }
163
195
  },
164
196
  async configureServer(server) {
197
+ server.httpServer?.on("listening", () => {
198
+ serverAddress = server.httpServer?.address();
199
+ });
165
200
  server.watcher.on("change", (path) => {
166
201
  if (!fontFileById) {
167
202
  return;
@@ -184,47 +219,24 @@ function fontsPlugin({ settings, sync, logger }) {
184
219
  );
185
220
  }
186
221
  });
187
- server.middlewares.use(assetsDir, async (req, res, next) => {
188
- if (!fontFetcher || !fontTypeExtractor) {
189
- logger.debug(
190
- "assets",
191
- "Fonts dependencies should be initialized by now, skipping dev middleware."
192
- );
193
- return next();
194
- }
195
- if (!req.url) {
196
- return next();
197
- }
198
- const url = new URL(req.url, "http://localhost");
199
- const fontId = url.pathname.slice(1);
200
- const fontData = fontFileById?.get(fontId);
201
- if (!fontData) {
202
- return next();
203
- }
204
- res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
205
- res.setHeader("Pragma", "no-cache");
206
- res.setHeader("Expires", 0);
207
- try {
208
- const buffer = await fontFetcher.fetch({ id: fontId, ...fontData });
209
- res.setHeader("Content-Length", buffer.length);
210
- res.setHeader("Content-Type", `font/${fontTypeExtractor.extract(fontId)}`);
211
- res.end(buffer);
212
- } catch (err) {
213
- logger.error("assets", "Cannot download font file");
214
- if (isAstroError(err)) {
215
- logger.error(
216
- "SKIP_FORMAT",
217
- formatErrorMessage(collectErrorMetadata(err), logger.level() === "debug")
218
- );
219
- }
220
- res.statusCode = 500;
221
- res.end();
222
- }
223
- });
222
+ server.middlewares.use(
223
+ assetsDir,
224
+ (req, res, next) => fontFileMiddleware({
225
+ url: req.url,
226
+ response: resToMinimalResponse(res),
227
+ next,
228
+ fontFetcher,
229
+ fontFileById,
230
+ fontTypeExtractor,
231
+ logger
232
+ })
233
+ );
224
234
  },
225
235
  resolveId: {
226
236
  filter: {
227
- id: new RegExp(`^(${VIRTUAL_MODULE_ID}|${RUNTIME_VIRTUAL_MODULE_ID})$`)
237
+ id: new RegExp(
238
+ `^(${VIRTUAL_MODULE_ID}|${RUNTIME_VIRTUAL_MODULE_ID}|${RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID})$`
239
+ )
228
240
  },
229
241
  handler(id) {
230
242
  if (id === VIRTUAL_MODULE_ID) {
@@ -233,11 +245,16 @@ function fontsPlugin({ settings, sync, logger }) {
233
245
  if (id === RUNTIME_VIRTUAL_MODULE_ID) {
234
246
  return RESOLVED_RUNTIME_VIRTUAL_MODULE_ID;
235
247
  }
248
+ if (id === RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID) {
249
+ return RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID;
250
+ }
236
251
  }
237
252
  },
238
253
  load: {
239
254
  filter: {
240
- id: new RegExp(`^(${RESOLVED_VIRTUAL_MODULE_ID}|${RESOLVED_RUNTIME_VIRTUAL_MODULE_ID})$`)
255
+ id: new RegExp(
256
+ `^(${RESOLVED_VIRTUAL_MODULE_ID}|${RESOLVED_RUNTIME_VIRTUAL_MODULE_ID}|${RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID})$`
257
+ )
241
258
  },
242
259
  async handler(id) {
243
260
  if (id === RESOLVED_VIRTUAL_MODULE_ID) {
@@ -253,13 +270,35 @@ function fontsPlugin({ settings, sync, logger }) {
253
270
  code: `export * from 'astro/assets/fonts/runtime.js';`
254
271
  };
255
272
  }
273
+ if (id === RESOLVED_RUNTIME_FONT_FILE_URL_RESOLVER_VIRTUAL_MODULE_ID) {
274
+ const isPrerender = this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender;
275
+ if (this.environment.config.command === "build" && !isPrerender) {
276
+ return {
277
+ code: `
278
+ import { SsrRuntimeFontFileUrlResolver } from ${JSON.stringify(new URL("./infra/ssr-runtime-font-file-url-resolver.js", import.meta.url))};
279
+ export const runtimeFontFileUrlResolver = new SsrRuntimeFontFileUrlResolver({
280
+ urls: new Set(${JSON.stringify(urls)}),
281
+ });
282
+ `
283
+ };
284
+ }
285
+ return {
286
+ code: `
287
+ import { RemoteRuntimeFontFileUrlResolver } from ${JSON.stringify(new URL("./infra/remote-runtime-font-file-url-resolver.js", import.meta.url))};
288
+ export const runtimeFontFileUrlResolver = new RemoteRuntimeFontFileUrlResolver({
289
+ urls: new Set(${JSON.stringify(urls)}),
290
+ address: ${JSON.stringify(serverAddress)},
291
+ });
292
+ `
293
+ };
294
+ }
256
295
  }
257
296
  },
258
297
  async buildEnd() {
259
298
  if (built) {
260
299
  return;
261
300
  }
262
- if (sync || !settings.config.fonts?.length || !isBuild) {
301
+ if (sync || !settings.config.fonts?.length || this.environment.config.command === "serve") {
263
302
  cleanup();
264
303
  return;
265
304
  }
@@ -1,4 +1,4 @@
1
- export { getConfiguredImageService, getImage } from './internal.js';
1
+ export { getConfiguredImageService, getImage, verifyOptions } from './internal.js';
2
2
  export { baseService, isLocalService } from './services/service.js';
3
3
  export { hashTransform, propsToFilename } from './utils/hash.js';
4
4
  export type { LocalImageProps, RemoteImageProps } from './types.js';
@@ -1,4 +1,4 @@
1
- import { getConfiguredImageService, getImage } from "./internal.js";
1
+ import { getConfiguredImageService, getImage, verifyOptions } from "./internal.js";
2
2
  import { baseService, isLocalService } from "./services/service.js";
3
3
  import { hashTransform, propsToFilename } from "./utils/hash.js";
4
4
  export {
@@ -7,5 +7,6 @@ export {
7
7
  getImage,
8
8
  hashTransform,
9
9
  isLocalService,
10
- propsToFilename
10
+ propsToFilename,
11
+ verifyOptions
11
12
  };
@@ -0,0 +1,5 @@
1
+ import * as z from 'zod/v4';
2
+ export declare const SvgOptimizerSchema: z.ZodObject<{
3
+ name: z.ZodString;
4
+ optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
5
+ }, z.core.$strip>;
@@ -0,0 +1,8 @@
1
+ import * as z from "zod/v4";
2
+ const SvgOptimizerSchema = z.object({
3
+ name: z.string(),
4
+ optimize: z.custom((v) => typeof v === "function")
5
+ });
6
+ export {
7
+ SvgOptimizerSchema
8
+ };
@@ -0,0 +1,4 @@
1
+ import type { SvgOptimizer } from './types.js';
2
+ import { type Config } from 'svgo';
3
+ /** SVG optimizer using [SVGO](https://svgo.dev/). */
4
+ export declare function svgoOptimizer(config?: Config): SvgOptimizer;
@@ -0,0 +1,10 @@
1
+ import { optimize } from "svgo";
2
+ function svgoOptimizer(config) {
3
+ return {
4
+ name: "svgo",
5
+ optimize: (contents) => optimize(contents, config).data
6
+ };
7
+ }
8
+ export {
9
+ svgoOptimizer
10
+ };
@@ -0,0 +1,4 @@
1
+ export interface SvgOptimizer {
2
+ name: string;
3
+ optimize: (contents: string) => string | Promise<string>;
4
+ }
File without changes
@@ -0,0 +1,3 @@
1
+ import type { ImageMetadata } from '../types.js';
2
+ import type { SvgOptimizer } from './types.js';
3
+ export declare function makeSvgComponent(meta: ImageMetadata, contents: Buffer | string, svgOptimizer: SvgOptimizer | undefined): Promise<string>;