astro 5.13.10 → 5.13.11

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 (34) hide show
  1. package/dist/assets/fonts/definitions.d.ts +8 -0
  2. package/dist/assets/fonts/implementations/data-collector.d.ts +1 -1
  3. package/dist/assets/fonts/implementations/url-proxy-hash-resolver.d.ts +8 -0
  4. package/dist/assets/fonts/implementations/url-proxy-hash-resolver.js +24 -0
  5. package/dist/assets/fonts/implementations/url-proxy.d.ts +4 -4
  6. package/dist/assets/fonts/implementations/url-proxy.js +4 -4
  7. package/dist/assets/fonts/orchestrate.js +2 -1
  8. package/dist/assets/fonts/types.d.ts +1 -0
  9. package/dist/assets/fonts/vite-plugin-fonts.js +16 -7
  10. package/dist/assets/services/sharp.js +2 -1
  11. package/dist/cli/info/index.js +1 -2
  12. package/dist/cli/preview/index.d.ts +1 -1
  13. package/dist/container/index.d.ts +0 -1
  14. package/dist/container/index.js +7 -3
  15. package/dist/content/content-layer.js +3 -3
  16. package/dist/core/app/node.js +70 -2
  17. package/dist/core/build/pipeline.d.ts +1 -1
  18. package/dist/core/config/schemas/base.d.ts +70 -70
  19. package/dist/core/config/schemas/relative.d.ts +125 -125
  20. package/dist/core/constants.d.ts +4 -0
  21. package/dist/core/constants.js +5 -1
  22. package/dist/core/dev/dev.js +1 -1
  23. package/dist/core/messages.js +2 -2
  24. package/dist/env/schema.d.ts +22 -22
  25. package/dist/i18n/index.d.ts +1 -1
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.js +1 -0
  28. package/dist/types/public/config.d.ts +12 -12
  29. package/dist/vite-plugin-astro-server/pipeline.d.ts +1 -1
  30. package/{zod.d.ts → dist/zod.d.ts} +0 -1
  31. package/dist/zod.js +7 -0
  32. package/package.json +5 -15
  33. package/index.d.ts +0 -2
  34. package/zod.mjs +0 -3
@@ -86,4 +86,12 @@ export interface FontFileReader {
86
86
  style: Style;
87
87
  };
88
88
  }
89
+ export interface UrlProxyHashResolver {
90
+ resolve: (input: {
91
+ originalUrl: string;
92
+ type: FontType;
93
+ cssVariable: string;
94
+ data: Partial<unifont.FontFaceData>;
95
+ }) => string;
96
+ }
89
97
  export {};
@@ -1,3 +1,3 @@
1
1
  import type { DataCollector } from '../definitions.js';
2
2
  import type { CreateUrlProxyParams } from '../types.js';
3
- export declare function createDataCollector({ hasUrl, saveUrl, savePreload, saveFontData, }: Omit<CreateUrlProxyParams, 'local'>): DataCollector;
3
+ export declare function createDataCollector({ hasUrl, saveUrl, savePreload, saveFontData, }: Pick<CreateUrlProxyParams, 'hasUrl' | 'saveUrl' | 'savePreload' | 'saveFontData'>): DataCollector;
@@ -0,0 +1,8 @@
1
+ import type { Hasher, UrlProxyContentResolver, UrlProxyHashResolver } from '../definitions.js';
2
+ export declare function createBuildUrlProxyHashResolver({ hasher, contentResolver, }: {
3
+ hasher: Hasher;
4
+ contentResolver: UrlProxyContentResolver;
5
+ }): UrlProxyHashResolver;
6
+ export declare function createDevUrlProxyHashResolver({ baseHashResolver, }: {
7
+ baseHashResolver: UrlProxyHashResolver;
8
+ }): UrlProxyHashResolver;
@@ -0,0 +1,24 @@
1
+ function createBuildUrlProxyHashResolver({
2
+ hasher,
3
+ contentResolver
4
+ }) {
5
+ return {
6
+ resolve({ originalUrl, type }) {
7
+ return `${hasher.hashString(contentResolver.resolve(originalUrl))}.${type}`;
8
+ }
9
+ };
10
+ }
11
+ function createDevUrlProxyHashResolver({
12
+ baseHashResolver
13
+ }) {
14
+ return {
15
+ resolve(input) {
16
+ const { cssVariable, data } = input;
17
+ return [cssVariable.slice(2), data.weight, data.style, baseHashResolver.resolve(input)].filter(Boolean).join("-");
18
+ }
19
+ };
20
+ }
21
+ export {
22
+ createBuildUrlProxyHashResolver,
23
+ createDevUrlProxyHashResolver
24
+ };
@@ -1,7 +1,7 @@
1
- import type { DataCollector, Hasher, UrlProxy, UrlProxyContentResolver, UrlResolver } from '../definitions.js';
2
- export declare function createUrlProxy({ contentResolver, hasher, dataCollector, urlResolver, }: {
3
- contentResolver: UrlProxyContentResolver;
4
- hasher: Hasher;
1
+ import type { DataCollector, UrlProxy, UrlProxyHashResolver, UrlResolver } from '../definitions.js';
2
+ export declare function createUrlProxy({ hashResolver, dataCollector, urlResolver, cssVariable, }: {
3
+ hashResolver: UrlProxyHashResolver;
5
4
  dataCollector: DataCollector;
6
5
  urlResolver: UrlResolver;
6
+ cssVariable: string;
7
7
  }): UrlProxy;
@@ -1,12 +1,12 @@
1
1
  function createUrlProxy({
2
- contentResolver,
3
- hasher,
2
+ hashResolver,
4
3
  dataCollector,
5
- urlResolver
4
+ urlResolver,
5
+ cssVariable
6
6
  }) {
7
7
  return {
8
8
  proxy({ url: originalUrl, type, data, collectPreload, init }) {
9
- const hash = `${hasher.hashString(contentResolver.resolve(originalUrl))}.${type}`;
9
+ const hash = hashResolver.resolve({ cssVariable, data, originalUrl, type });
10
10
  const url = urlResolver.resolve(hash);
11
11
  dataCollector.collect({
12
12
  url: originalUrl,
@@ -59,7 +59,8 @@ async function orchestrate({
59
59
  !collectedFonts.some((f) => JSON.stringify(f.data) === JSON.stringify(collected.data))) {
60
60
  collectedFonts.push(collected);
61
61
  }
62
- }
62
+ },
63
+ cssVariable: family.cssVariable
63
64
  });
64
65
  let fonts;
65
66
  if (family.provider === LOCAL_PROVIDER_NAME) {
@@ -59,6 +59,7 @@ export interface CreateUrlProxyParams {
59
59
  saveUrl: (input: FontFileData) => void;
60
60
  savePreload: (preload: PreloadData) => void;
61
61
  saveFontData: (collected: CollectedFontForMetrics) => void;
62
+ cssVariable: string;
62
63
  }
63
64
  /**
64
65
  * Holds associations of hash and original font file URLs, so they can be
@@ -37,6 +37,10 @@ import {
37
37
  createLocalUrlProxyContentResolver,
38
38
  createRemoteUrlProxyContentResolver
39
39
  } from "./implementations/url-proxy-content-resolver.js";
40
+ import {
41
+ createBuildUrlProxyHashResolver,
42
+ createDevUrlProxyHashResolver
43
+ } from "./implementations/url-proxy-hash-resolver.js";
40
44
  import { createBuildUrlResolver, createDevUrlResolver } from "./implementations/url-resolver.js";
41
45
  import { orchestrate } from "./orchestrate.js";
42
46
  function fontsPlugin({ settings, sync, logger }) {
@@ -75,7 +79,8 @@ function fontsPlugin({ settings, sync, logger }) {
75
79
  cacheDir,
76
80
  modResolver,
77
81
  cssRenderer,
78
- urlResolver
82
+ urlResolver,
83
+ createHashResolver
79
84
  }) {
80
85
  const { root } = settings.config;
81
86
  const hasher = await createXxHasher();
@@ -119,14 +124,14 @@ function fontsPlugin({ settings, sync, logger }) {
119
124
  fontTypeExtractor,
120
125
  fontFileReader,
121
126
  logger,
122
- createUrlProxy: ({ local, ...params }) => {
127
+ createUrlProxy: ({ local, cssVariable, ...params }) => {
123
128
  const dataCollector = createDataCollector(params);
124
129
  const contentResolver = local ? createLocalUrlProxyContentResolver({ errorHandler }) : createRemoteUrlProxyContentResolver();
125
130
  return createUrlProxy({
126
131
  urlResolver,
127
- contentResolver,
128
- hasher,
129
- dataCollector
132
+ hashResolver: createHashResolver({ hasher, contentResolver }),
133
+ dataCollector,
134
+ cssVariable
130
135
  });
131
136
  },
132
137
  defaults: DEFAULTS
@@ -158,7 +163,8 @@ function fontsPlugin({ settings, sync, logger }) {
158
163
  urlResolver: createBuildUrlResolver({
159
164
  base: baseUrl,
160
165
  assetsPrefix: settings.config.build.assetsPrefix
161
- })
166
+ }),
167
+ createHashResolver: (dependencies) => createBuildUrlProxyHashResolver(dependencies)
162
168
  });
163
169
  }
164
170
  },
@@ -168,7 +174,10 @@ function fontsPlugin({ settings, sync, logger }) {
168
174
  cacheDir: new URL(CACHE_DIR, settings.dotAstroDir),
169
175
  modResolver: createDevServerRemoteFontProviderModResolver({ server }),
170
176
  cssRenderer: createMinifiableCssRenderer({ minify: false }),
171
- urlResolver: createDevUrlResolver({ base: baseUrl })
177
+ urlResolver: createDevUrlResolver({ base: baseUrl }),
178
+ createHashResolver: (dependencies) => createDevUrlProxyHashResolver({
179
+ baseHashResolver: createBuildUrlProxyHashResolver(dependencies)
180
+ })
172
181
  });
173
182
  const localPaths = [...fontFileDataMap.values()].filter(({ url }) => isAbsolute(url)).map((v) => v.url);
174
183
  server.watcher.on("change", (path) => {
@@ -89,8 +89,9 @@ const sharpService = {
89
89
  }
90
90
  }
91
91
  const { data, info } = await result.toBuffer({ resolveWithObject: true });
92
+ const needsCopy = "buffer" in data && data.buffer instanceof SharedArrayBuffer;
92
93
  return {
93
- data,
94
+ data: needsCopy ? new Uint8Array(data) : data,
94
95
  format: info.format
95
96
  };
96
97
  }
@@ -258,8 +258,7 @@ async function getVersion(packageManager, dependency) {
258
258
  return void 0;
259
259
  }
260
260
  return void 0;
261
- } catch (err) {
262
- console.error(err);
261
+ } catch {
263
262
  return void 0;
264
263
  }
265
264
  }
@@ -2,5 +2,5 @@ import { type Flags } from '../flags.js';
2
2
  interface PreviewOptions {
3
3
  flags: Flags;
4
4
  }
5
- export declare function preview({ flags }: PreviewOptions): Promise<import("../../types/public/preview.js").PreviewServer | undefined>;
5
+ export declare function preview({ flags }: PreviewOptions): Promise<import("../../index.js").PreviewServer | undefined>;
6
6
  export {};
@@ -82,7 +82,6 @@ export type ContainerRenderOptions = {
82
82
  };
83
83
  export type AddServerRenderer = {
84
84
  renderer: NamedSSRLoadedRendererValue;
85
- name: never;
86
85
  } | {
87
86
  renderer: SSRLoadedRendererValue;
88
87
  name: string;
@@ -129,7 +129,7 @@ class experimental_AstroContainer {
129
129
  * @param options.renderer The server renderer exported by integration.
130
130
  */
131
131
  addServerRenderer(options) {
132
- const { renderer, name } = options;
132
+ const { renderer } = options;
133
133
  if (!renderer.check || !renderer.renderToStaticMarkup) {
134
134
  throw new Error(
135
135
  "The renderer you passed isn't valid. A renderer is usually an object that exposes the `check` and `renderToStaticMarkup` functions.\nUsually, the renderer is exported by a /server.js entrypoint e.g. `import renderer from '@astrojs/react/server.js'`"
@@ -140,11 +140,15 @@ class experimental_AstroContainer {
140
140
  name: renderer.name,
141
141
  ssr: renderer
142
142
  });
143
- } else {
143
+ } else if ("name" in options) {
144
144
  this.#pipeline.manifest.renderers.push({
145
- name,
145
+ name: options.name,
146
146
  ssr: renderer
147
147
  });
148
+ } else {
149
+ throw new Error(
150
+ "The renderer name must be provided when adding a server renderer that is not a named renderer."
151
+ );
148
152
  }
149
153
  }
150
154
  /**
@@ -164,7 +164,7 @@ ${contentConfig.error.message}`);
164
164
  logger.info("Content config changed");
165
165
  shouldClear = true;
166
166
  }
167
- if (previousAstroVersion && previousAstroVersion !== "5.13.10") {
167
+ if (previousAstroVersion && previousAstroVersion !== "5.13.11") {
168
168
  logger.info("Astro version changed");
169
169
  shouldClear = true;
170
170
  }
@@ -172,8 +172,8 @@ ${contentConfig.error.message}`);
172
172
  logger.info("Clearing content store");
173
173
  this.#store.clearAll();
174
174
  }
175
- if ("5.13.10") {
176
- await this.#store.metaStore().set("astro-version", "5.13.10");
175
+ if ("5.13.11") {
176
+ await this.#store.metaStore().set("astro-version", "5.13.11");
177
177
  }
178
178
  if (currentConfigDigest) {
179
179
  await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import { Http2ServerResponse } from "node:http2";
3
- import { clientAddressSymbol } from "../constants.js";
3
+ import { clientAddressSymbol, nodeRequestAbortControllerCleanupSymbol } from "../constants.js";
4
4
  import { deserializeManifest } from "./common.js";
5
5
  import { createOutgoingHttpHeaders } from "./createOutgoingHttpHeaders.js";
6
6
  import { App } from "./index.js";
@@ -38,6 +38,7 @@ class NodeApp extends App {
38
38
  * ```
39
39
  */
40
40
  static createRequest(req, { skipBody = false } = {}) {
41
+ const controller = new AbortController();
41
42
  const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
42
43
  const getFirstForwardedValue = (multiValueHeader) => {
43
44
  return multiValueHeader?.toString()?.split(",").map((e) => e.trim())?.[0];
@@ -59,13 +60,48 @@ class NodeApp extends App {
59
60
  }
60
61
  const options = {
61
62
  method: req.method || "GET",
62
- headers: makeRequestHeaders(req)
63
+ headers: makeRequestHeaders(req),
64
+ signal: controller.signal
63
65
  };
64
66
  const bodyAllowed = options.method !== "HEAD" && options.method !== "GET" && skipBody === false;
65
67
  if (bodyAllowed) {
66
68
  Object.assign(options, makeRequestBody(req));
67
69
  }
68
70
  const request = new Request(url, options);
71
+ const socket = getRequestSocket(req);
72
+ if (socket && typeof socket.on === "function") {
73
+ const existingCleanup = getAbortControllerCleanup(req);
74
+ if (existingCleanup) {
75
+ existingCleanup();
76
+ }
77
+ let cleanedUp = false;
78
+ const removeSocketListener = () => {
79
+ if (typeof socket.off === "function") {
80
+ socket.off("close", onSocketClose);
81
+ } else if (typeof socket.removeListener === "function") {
82
+ socket.removeListener("close", onSocketClose);
83
+ }
84
+ };
85
+ const cleanup = () => {
86
+ if (cleanedUp) return;
87
+ cleanedUp = true;
88
+ removeSocketListener();
89
+ controller.signal.removeEventListener("abort", cleanup);
90
+ Reflect.deleteProperty(req, nodeRequestAbortControllerCleanupSymbol);
91
+ };
92
+ const onSocketClose = () => {
93
+ cleanup();
94
+ if (!controller.signal.aborted) {
95
+ controller.abort();
96
+ }
97
+ };
98
+ socket.on("close", onSocketClose);
99
+ controller.signal.addEventListener("abort", cleanup, { once: true });
100
+ Reflect.set(req, nodeRequestAbortControllerCleanupSymbol, cleanup);
101
+ if (socket.destroyed) {
102
+ onSocketClose();
103
+ }
104
+ }
69
105
  const forwardedClientIp = getFirstForwardedValue(req.headers["x-forwarded-for"]);
70
106
  const clientIp = forwardedClientIp || req.socket?.remoteAddress;
71
107
  if (clientIp) {
@@ -94,6 +130,23 @@ class NodeApp extends App {
94
130
  destination.statusMessage = statusText;
95
131
  }
96
132
  destination.writeHead(status, createOutgoingHttpHeaders(headers));
133
+ const cleanupAbortFromDestination = getAbortControllerCleanup(
134
+ destination.req ?? void 0
135
+ );
136
+ if (cleanupAbortFromDestination) {
137
+ const runCleanup = () => {
138
+ cleanupAbortFromDestination();
139
+ if (typeof destination.off === "function") {
140
+ destination.off("finish", runCleanup);
141
+ destination.off("close", runCleanup);
142
+ } else {
143
+ destination.removeListener?.("finish", runCleanup);
144
+ destination.removeListener?.("close", runCleanup);
145
+ }
146
+ };
147
+ destination.on("finish", runCleanup);
148
+ destination.on("close", runCleanup);
149
+ }
97
150
  if (!body) return destination.end();
98
151
  try {
99
152
  const reader = body.getReader();
@@ -165,6 +218,21 @@ function asyncIterableToBodyProps(iterable) {
165
218
  duplex: "half"
166
219
  };
167
220
  }
221
+ function getAbortControllerCleanup(req) {
222
+ if (!req) return void 0;
223
+ const cleanup = Reflect.get(req, nodeRequestAbortControllerCleanupSymbol);
224
+ return typeof cleanup === "function" ? cleanup : void 0;
225
+ }
226
+ function getRequestSocket(req) {
227
+ if (req.socket && typeof req.socket.on === "function") {
228
+ return req.socket;
229
+ }
230
+ const http2Socket = req.stream?.session?.socket;
231
+ if (http2Socket && typeof http2Socket.on === "function") {
232
+ return http2Socket;
233
+ }
234
+ return void 0;
235
+ }
168
236
  async function loadManifest(rootFolder) {
169
237
  const manifestFile = new URL("./manifest.json", rootFolder);
170
238
  const rawManifest = await fs.promises.readFile(manifestFile, "utf-8");
@@ -14,7 +14,7 @@ export declare class BuildPipeline extends Pipeline {
14
14
  readonly internals: BuildInternals;
15
15
  readonly manifest: SSRManifest;
16
16
  readonly options: StaticBuildOptions;
17
- readonly config: import("../../types/public/config.js").AstroConfig;
17
+ readonly config: import("../../index.js").AstroConfig;
18
18
  readonly settings: AstroSettings;
19
19
  readonly defaultRoutes: {
20
20
  instance: ComponentInstance;