astro 5.16.2 → 5.16.4

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 (65) hide show
  1. package/dist/actions/runtime/server.d.ts +5 -4
  2. package/dist/actions/runtime/server.js +0 -1
  3. package/dist/assets/fonts/definitions.d.ts +8 -3
  4. package/dist/assets/fonts/infra/build-remote-font-provider-mod-resolver.d.ts +3 -1
  5. package/dist/assets/fonts/infra/build-remote-font-provider-mod-resolver.js +5 -7
  6. package/dist/assets/fonts/infra/build-url-proxy-hash-resolver.d.ts +15 -5
  7. package/dist/assets/fonts/infra/build-url-proxy-hash-resolver.js +17 -10
  8. package/dist/assets/fonts/infra/build-url-resolver.d.ts +10 -5
  9. package/dist/assets/fonts/infra/build-url-resolver.js +33 -27
  10. package/dist/assets/fonts/infra/cached-font-fetcher.d.ts +11 -7
  11. package/dist/assets/fonts/infra/cached-font-fetcher.js +35 -29
  12. package/dist/assets/fonts/infra/capsize-font-metrics-resolver.d.ts +18 -5
  13. package/dist/assets/fonts/infra/capsize-font-metrics-resolver.js +45 -40
  14. package/dist/assets/fonts/infra/data-collector.d.ts +10 -3
  15. package/dist/assets/fonts/infra/data-collector.js +30 -16
  16. package/dist/assets/fonts/infra/dev-remote-font-provider-mod-resolver.d.ts +7 -3
  17. package/dist/assets/fonts/infra/dev-remote-font-provider-mod-resolver.js +11 -9
  18. package/dist/assets/fonts/infra/dev-url-proxy-hash-resolver.d.ts +15 -5
  19. package/dist/assets/fonts/infra/dev-url-proxy-hash-resolver.js +31 -22
  20. package/dist/assets/fonts/infra/dev-url-resolver.d.ts +9 -4
  21. package/dist/assets/fonts/infra/dev-url-resolver.js +24 -20
  22. package/dist/assets/fonts/infra/font-type-extractor.d.ts +4 -1
  23. package/dist/assets/fonts/infra/font-type-extractor.js +14 -16
  24. package/dist/assets/fonts/infra/fontace-font-file-reader.d.ts +10 -1
  25. package/dist/assets/fonts/infra/fontace-font-file-reader.js +18 -20
  26. package/dist/assets/fonts/infra/levenshtein-string-matcher.d.ts +4 -1
  27. package/dist/assets/fonts/infra/levenshtein-string-matcher.js +119 -121
  28. package/dist/assets/fonts/infra/local-url-proxy-content-resolver.d.ts +4 -0
  29. package/dist/assets/fonts/infra/local-url-proxy-content-resolver.js +14 -0
  30. package/dist/assets/fonts/infra/minifiable-css-renderer.d.ts +8 -3
  31. package/dist/assets/fonts/infra/minifiable-css-renderer.js +12 -10
  32. package/dist/assets/fonts/infra/remote-font-provider-resolver.d.ts +9 -4
  33. package/dist/assets/fonts/infra/remote-font-provider-resolver.js +42 -38
  34. package/dist/assets/fonts/infra/remote-url-proxy-content-resolver.d.ts +4 -0
  35. package/dist/assets/fonts/infra/remote-url-proxy-content-resolver.js +9 -0
  36. package/dist/assets/fonts/infra/require-local-provider-url-resolver.d.ts +8 -4
  37. package/dist/assets/fonts/infra/require-local-provider-url-resolver.js +17 -12
  38. package/dist/assets/fonts/infra/system-fallbacks-provider.d.ts +5 -10
  39. package/dist/assets/fonts/infra/system-fallbacks-provider.js +8 -11
  40. package/dist/assets/fonts/infra/unstorage-fs-storage.d.ts +11 -0
  41. package/dist/assets/fonts/infra/unstorage-fs-storage.js +26 -0
  42. package/dist/assets/fonts/infra/url-proxy.d.ts +16 -7
  43. package/dist/assets/fonts/infra/url-proxy.js +46 -27
  44. package/dist/assets/fonts/infra/xxhash-hasher.d.ts +6 -1
  45. package/dist/assets/fonts/infra/xxhash-hasher.js +13 -9
  46. package/dist/assets/fonts/orchestrate.d.ts +1 -2
  47. package/dist/assets/fonts/utils.d.ts +1 -2
  48. package/dist/assets/fonts/vite-plugin-fonts.js +43 -46
  49. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  50. package/dist/content/content-layer.js +3 -3
  51. package/dist/core/app/index.js +8 -2
  52. package/dist/core/constants.js +1 -1
  53. package/dist/core/csp/runtime.d.ts +11 -0
  54. package/dist/core/csp/runtime.js +35 -0
  55. package/dist/core/dev/dev.js +1 -1
  56. package/dist/core/messages.js +2 -2
  57. package/dist/core/render-context.js +25 -5
  58. package/dist/core/util/pathname.d.ts +10 -0
  59. package/dist/core/util/pathname.js +17 -0
  60. package/dist/vite-plugin-astro-server/request.js +9 -2
  61. package/package.json +2 -2
  62. package/dist/assets/fonts/infra/fs-storage.d.ts +0 -4
  63. package/dist/assets/fonts/infra/fs-storage.js +0 -14
  64. package/dist/assets/fonts/infra/url-proxy-content-resolver.d.ts +0 -3
  65. package/dist/assets/fonts/infra/url-proxy-content-resolver.js +0 -23
@@ -1,17 +1,22 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { resolveEntrypoint } from "../utils.js";
3
- function createRequireLocalProviderUrlResolver({
4
- root,
5
- intercept
6
- }) {
7
- return {
8
- resolve(input) {
9
- const path = fileURLToPath(resolveEntrypoint(root, input));
10
- intercept?.(path);
11
- return path;
12
- }
13
- };
3
+ class RequireLocalProviderUrlResolver {
4
+ #root;
5
+ // TODO: remove when stabilizing
6
+ #intercept;
7
+ constructor({
8
+ root,
9
+ intercept
10
+ }) {
11
+ this.#root = root;
12
+ this.#intercept = intercept;
13
+ }
14
+ resolve(input) {
15
+ const path = fileURLToPath(resolveEntrypoint(this.#root, input));
16
+ this.#intercept?.(path);
17
+ return path;
18
+ }
14
19
  }
15
20
  export {
16
- createRequireLocalProviderUrlResolver
21
+ RequireLocalProviderUrlResolver
17
22
  };
@@ -1,11 +1,6 @@
1
1
  import type { SystemFallbacksProvider } from '../definitions.js';
2
- export declare const DEFAULT_FALLBACKS: {
3
- serif: "Times New Roman"[];
4
- 'sans-serif': "Arial"[];
5
- monospace: "Courier New"[];
6
- 'system-ui': ("Arial" | "BlinkMacSystemFont" | "Segoe UI" | "Roboto" | "Helvetica Neue")[];
7
- 'ui-serif': "Times New Roman"[];
8
- 'ui-sans-serif': "Arial"[];
9
- 'ui-monospace': "Courier New"[];
10
- };
11
- export declare function createSystemFallbacksProvider(): SystemFallbacksProvider;
2
+ import type { FontFaceMetrics, GenericFallbackName } from '../types.js';
3
+ export declare class RealSystemFallbacksProvider implements SystemFallbacksProvider {
4
+ getLocalFonts(fallback: GenericFallbackName): Array<string> | null;
5
+ getMetricsForLocalFont(family: string): FontFaceMetrics;
6
+ }
@@ -58,17 +58,14 @@ const DEFAULT_FALLBACKS = {
58
58
  "ui-sans-serif": ["Arial"],
59
59
  "ui-monospace": ["Courier New"]
60
60
  };
61
- function createSystemFallbacksProvider() {
62
- return {
63
- getLocalFonts(fallback) {
64
- return DEFAULT_FALLBACKS[fallback] ?? null;
65
- },
66
- getMetricsForLocalFont(family) {
67
- return SYSTEM_METRICS[family];
68
- }
69
- };
61
+ class RealSystemFallbacksProvider {
62
+ getLocalFonts(fallback) {
63
+ return DEFAULT_FALLBACKS[fallback] ?? null;
64
+ }
65
+ getMetricsForLocalFont(family) {
66
+ return SYSTEM_METRICS[family];
67
+ }
70
68
  }
71
69
  export {
72
- DEFAULT_FALLBACKS,
73
- createSystemFallbacksProvider
70
+ RealSystemFallbacksProvider
74
71
  };
@@ -0,0 +1,11 @@
1
+ import type { Storage } from '../definitions.js';
2
+ export declare class UnstorageFsStorage implements Storage {
3
+ #private;
4
+ constructor({ base }: {
5
+ base: URL;
6
+ });
7
+ getItem(key: string): Promise<any | null>;
8
+ getItemRaw(key: string): Promise<Buffer | null>;
9
+ setItem(key: string, value: any): Promise<void>;
10
+ setItemRaw(key: string, value: any): Promise<void>;
11
+ }
@@ -0,0 +1,26 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import * as unstorage from "unstorage";
3
+ import fsLiteDriver from "unstorage/drivers/fs-lite";
4
+ class UnstorageFsStorage {
5
+ #unstorage;
6
+ constructor({ base }) {
7
+ this.#unstorage = unstorage.createStorage({
8
+ driver: fsLiteDriver({ base: fileURLToPath(base) })
9
+ });
10
+ }
11
+ async getItem(key) {
12
+ return await this.#unstorage.getItem(key);
13
+ }
14
+ async getItemRaw(key) {
15
+ return await this.#unstorage.getItemRaw(key);
16
+ }
17
+ async setItem(key, value) {
18
+ return await this.#unstorage.setItem(key, value);
19
+ }
20
+ async setItemRaw(key, value) {
21
+ return await this.#unstorage.setItemRaw(key, value);
22
+ }
23
+ }
24
+ export {
25
+ UnstorageFsStorage
26
+ };
@@ -1,7 +1,16 @@
1
- import type { DataCollector, UrlProxy, UrlProxyHashResolver, UrlResolver } from '../definitions.js';
2
- export declare function createUrlProxy({ hashResolver, dataCollector, urlResolver, cssVariable, }: {
3
- hashResolver: UrlProxyHashResolver;
4
- dataCollector: DataCollector;
5
- urlResolver: UrlResolver;
6
- cssVariable: string;
7
- }): UrlProxy;
1
+ import type { DataCollector, ProxyData, UrlProxy, UrlProxyHashResolver, UrlResolver } from '../definitions.js';
2
+ import type { FontFileData, FontType } from '../types.js';
3
+ export declare class RealUrlProxy implements UrlProxy {
4
+ #private;
5
+ constructor({ hashResolver, dataCollector, urlResolver, cssVariable, }: {
6
+ hashResolver: UrlProxyHashResolver;
7
+ dataCollector: DataCollector;
8
+ urlResolver: UrlResolver;
9
+ cssVariable: string;
10
+ });
11
+ proxy({ url: originalUrl, type, data, collectPreload, init, }: Pick<FontFileData, 'url' | 'init'> & {
12
+ type: FontType;
13
+ collectPreload: boolean;
14
+ data: ProxyData;
15
+ }): string;
16
+ }
@@ -1,31 +1,50 @@
1
1
  import { renderFontWeight } from "../utils.js";
2
- function createUrlProxy({
3
- hashResolver,
4
- dataCollector,
5
- urlResolver,
6
- cssVariable
7
- }) {
8
- return {
9
- proxy({ url: originalUrl, type, data, collectPreload, init }) {
10
- const hash = hashResolver.resolve({ cssVariable, data, originalUrl, type });
11
- const url = urlResolver.resolve(hash);
12
- dataCollector.collect({
13
- url: originalUrl,
14
- hash,
15
- preload: collectPreload ? {
16
- url,
17
- type,
18
- weight: renderFontWeight(data.weight),
19
- style: data.style,
20
- subset: data.subset
21
- } : null,
22
- data,
23
- init
24
- });
25
- return url;
26
- }
27
- };
2
+ class RealUrlProxy {
3
+ #hashResolver;
4
+ #dataCollector;
5
+ #urlResolver;
6
+ #cssVariable;
7
+ constructor({
8
+ hashResolver,
9
+ dataCollector,
10
+ urlResolver,
11
+ cssVariable
12
+ }) {
13
+ this.#hashResolver = hashResolver;
14
+ this.#dataCollector = dataCollector;
15
+ this.#urlResolver = urlResolver;
16
+ this.#cssVariable = cssVariable;
17
+ }
18
+ proxy({
19
+ url: originalUrl,
20
+ type,
21
+ data,
22
+ collectPreload,
23
+ init
24
+ }) {
25
+ const hash = this.#hashResolver.resolve({
26
+ cssVariable: this.#cssVariable,
27
+ data,
28
+ originalUrl,
29
+ type
30
+ });
31
+ const url = this.#urlResolver.resolve(hash);
32
+ this.#dataCollector.collect({
33
+ url: originalUrl,
34
+ hash,
35
+ preload: collectPreload ? {
36
+ url,
37
+ type,
38
+ weight: renderFontWeight(data.weight),
39
+ style: data.style,
40
+ subset: data.subset
41
+ } : null,
42
+ data,
43
+ init
44
+ });
45
+ return url;
46
+ }
28
47
  }
29
48
  export {
30
- createUrlProxy
49
+ RealUrlProxy
31
50
  };
@@ -1,2 +1,7 @@
1
1
  import type { Hasher } from '../definitions.js';
2
- export declare function createXxhashHasher(): Promise<Hasher>;
2
+ export declare class XxhashHasher implements Hasher {
3
+ hashString: (input: string) => string;
4
+ private constructor();
5
+ static create(): Promise<XxhashHasher>;
6
+ hashObject(input: Record<string, any>): string;
7
+ }
@@ -1,14 +1,18 @@
1
1
  import xxhash from "xxhash-wasm";
2
2
  import { sortObjectByKey } from "../utils.js";
3
- async function createXxhashHasher() {
4
- const { h64ToString: hashString } = await xxhash();
5
- return {
6
- hashString,
7
- hashObject(input) {
8
- return hashString(JSON.stringify(sortObjectByKey(input)));
9
- }
10
- };
3
+ class XxhashHasher {
4
+ hashString;
5
+ constructor(hashString) {
6
+ this.hashString = hashString;
7
+ }
8
+ static async create() {
9
+ const { h64ToString } = await xxhash();
10
+ return new XxhashHasher(h64ToString);
11
+ }
12
+ hashObject(input) {
13
+ return this.hashString(JSON.stringify(sortObjectByKey(input)));
14
+ }
11
15
  }
12
16
  export {
13
- createXxhashHasher
17
+ XxhashHasher
14
18
  };
@@ -1,6 +1,5 @@
1
- import type { Storage } from 'unstorage';
2
1
  import type { Logger } from '../../core/logger/core.js';
3
- import type { CssRenderer, FontFileReader, FontMetricsResolver, FontTypeExtractor, Hasher, LocalProviderUrlResolver, RemoteFontProviderResolver, StringMatcher, SystemFallbacksProvider, UrlProxy } from './definitions.js';
2
+ import type { CssRenderer, FontFileReader, FontMetricsResolver, FontTypeExtractor, Hasher, LocalProviderUrlResolver, RemoteFontProviderResolver, Storage, StringMatcher, SystemFallbacksProvider, UrlProxy } from './definitions.js';
4
3
  import type { ConsumableMap, CreateUrlProxyParams, Defaults, FontFamily, FontFileDataMap, InternalConsumableMap } from './types.js';
5
4
  /**
6
5
  * Manages how fonts are resolved:
@@ -1,6 +1,5 @@
1
1
  import type * as unifont from 'unifont';
2
- import type { Storage } from 'unstorage';
3
- import type { CssProperties } from './definitions.js';
2
+ import type { CssProperties, Storage } from './definitions.js';
4
3
  import type { FontType, GenericFallbackName, ResolvedFontFamily } from './types.js';
5
4
  /**
6
5
  * Turns unifont font face data into generic CSS properties, to be consumed by the CSS renderer.
@@ -17,29 +17,27 @@ import {
17
17
  RESOLVED_VIRTUAL_MODULE_ID,
18
18
  VIRTUAL_MODULE_ID
19
19
  } from "./constants.js";
20
- import { createBuildRemoteFontProviderModResolver } from "./infra/build-remote-font-provider-mod-resolver.js";
21
- import { createBuildUrlProxyHashResolver } from "./infra/build-url-proxy-hash-resolver.js";
22
- import { createBuildUrlResolver } from "./infra/build-url-resolver.js";
23
- import { createCachedFontFetcher } from "./infra/cached-font-fetcher.js";
24
- import { createCapsizeFontMetricsResolver } from "./infra/capsize-font-metrics-resolver.js";
25
- import { createDataCollector } from "./infra/data-collector.js";
26
- import { createDevServerRemoteFontProviderModResolver } from "./infra/dev-remote-font-provider-mod-resolver.js";
27
- import { createDevUrlProxyHashResolver } from "./infra/dev-url-proxy-hash-resolver.js";
28
- import { createDevUrlResolver } from "./infra/dev-url-resolver.js";
29
- import { createFontTypeExtractor } from "./infra/font-type-extractor.js";
30
- import { createFontaceFontFileReader } from "./infra/fontace-font-file-reader.js";
31
- import { createFsStorage } from "./infra/fs-storage.js";
32
- import { createLevenshteinStringMatcher } from "./infra/levenshtein-string-matcher.js";
33
- import { createMinifiableCssRenderer } from "./infra/minifiable-css-renderer.js";
34
- import { createRemoteFontProviderResolver } from "./infra/remote-font-provider-resolver.js";
35
- import { createRequireLocalProviderUrlResolver } from "./infra/require-local-provider-url-resolver.js";
36
- import { createSystemFallbacksProvider } from "./infra/system-fallbacks-provider.js";
37
- import { createUrlProxy } from "./infra/url-proxy.js";
38
- import {
39
- createLocalUrlProxyContentResolver,
40
- createRemoteUrlProxyContentResolver
41
- } from "./infra/url-proxy-content-resolver.js";
42
- import { createXxhashHasher } from "./infra/xxhash-hasher.js";
20
+ import { BuildRemoteFontProviderModResolver } from "./infra/build-remote-font-provider-mod-resolver.js";
21
+ import { BuildUrlProxyHashResolver } from "./infra/build-url-proxy-hash-resolver.js";
22
+ import { BuildUrlResolver } from "./infra/build-url-resolver.js";
23
+ import { CachedFontFetcher } from "./infra/cached-font-fetcher.js";
24
+ import { CapsizeFontMetricsResolver } from "./infra/capsize-font-metrics-resolver.js";
25
+ import { RealDataCollector } from "./infra/data-collector.js";
26
+ import { DevServerRemoteFontProviderModResolver } from "./infra/dev-remote-font-provider-mod-resolver.js";
27
+ import { DevUrlProxyHashResolver } from "./infra/dev-url-proxy-hash-resolver.js";
28
+ import { DevUrlResolver } from "./infra/dev-url-resolver.js";
29
+ import { RealFontTypeExtractor } from "./infra/font-type-extractor.js";
30
+ import { FontaceFontFileReader } from "./infra/fontace-font-file-reader.js";
31
+ import { LevenshteinStringMatcher } from "./infra/levenshtein-string-matcher.js";
32
+ import { LocalUrlProxyContentResolver } from "./infra/local-url-proxy-content-resolver.js";
33
+ import { MinifiableCssRenderer } from "./infra/minifiable-css-renderer.js";
34
+ import { RealRemoteFontProviderResolver } from "./infra/remote-font-provider-resolver.js";
35
+ import { RemoteUrlProxyContentResolver } from "./infra/remote-url-proxy-content-resolver.js";
36
+ import { RequireLocalProviderUrlResolver } from "./infra/require-local-provider-url-resolver.js";
37
+ import { RealSystemFallbacksProvider } from "./infra/system-fallbacks-provider.js";
38
+ import { UnstorageFsStorage } from "./infra/unstorage-fs-storage.js";
39
+ import { RealUrlProxy } from "./infra/url-proxy.js";
40
+ import { XxhashHasher } from "./infra/xxhash-hasher.js";
43
41
  import { orchestrate } from "./orchestrate.js";
44
42
  function fontsPlugin({ settings, sync, logger }) {
45
43
  if (!settings.config.experimental.fonts) {
@@ -83,13 +81,13 @@ function fontsPlugin({ settings, sync, logger }) {
83
81
  createHashResolver
84
82
  }) {
85
83
  const { root } = settings.config;
86
- const hasher = await createXxhashHasher();
87
- const remoteFontProviderResolver = createRemoteFontProviderResolver({
84
+ const hasher = await XxhashHasher.create();
85
+ const remoteFontProviderResolver = new RealRemoteFontProviderResolver({
88
86
  root,
89
87
  modResolver
90
88
  });
91
89
  const pathsToWarn = /* @__PURE__ */ new Set();
92
- const localProviderUrlResolver = createRequireLocalProviderUrlResolver({
90
+ const localProviderUrlResolver = new RequireLocalProviderUrlResolver({
93
91
  root,
94
92
  intercept: (path) => {
95
93
  if (path.startsWith(fileURLToPath(settings.config.publicDir))) {
@@ -104,13 +102,13 @@ function fontsPlugin({ settings, sync, logger }) {
104
102
  }
105
103
  }
106
104
  });
107
- const storage = createFsStorage({ base: cacheDir });
108
- const systemFallbacksProvider = createSystemFallbacksProvider();
109
- fontFetcher = createCachedFontFetcher({ storage, fetch, readFile });
110
- const fontMetricsResolver = createCapsizeFontMetricsResolver({ fontFetcher, cssRenderer });
111
- fontTypeExtractor = createFontTypeExtractor();
112
- const fontFileReader = createFontaceFontFileReader();
113
- const stringMatcher = createLevenshteinStringMatcher();
105
+ const storage = new UnstorageFsStorage({ base: cacheDir });
106
+ const systemFallbacksProvider = new RealSystemFallbacksProvider();
107
+ fontFetcher = new CachedFontFetcher({ storage, fetch, readFile });
108
+ const fontMetricsResolver = new CapsizeFontMetricsResolver({ fontFetcher, cssRenderer });
109
+ fontTypeExtractor = new RealFontTypeExtractor();
110
+ const fontFileReader = new FontaceFontFileReader();
111
+ const stringMatcher = new LevenshteinStringMatcher();
114
112
  const res = await orchestrate({
115
113
  families: settings.config.experimental.fonts,
116
114
  hasher,
@@ -124,9 +122,9 @@ function fontsPlugin({ settings, sync, logger }) {
124
122
  fontFileReader,
125
123
  logger,
126
124
  createUrlProxy: ({ local, cssVariable, ...params }) => {
127
- const dataCollector = createDataCollector(params);
128
- const contentResolver = local ? createLocalUrlProxyContentResolver() : createRemoteUrlProxyContentResolver();
129
- return createUrlProxy({
125
+ const dataCollector = new RealDataCollector(params);
126
+ const contentResolver = local ? new LocalUrlProxyContentResolver() : new RemoteUrlProxyContentResolver();
127
+ return new RealUrlProxy({
130
128
  urlResolver,
131
129
  hashResolver: createHashResolver({ hasher, contentResolver }),
132
130
  dataCollector,
@@ -145,8 +143,7 @@ function fontsPlugin({ settings, sync, logger }) {
145
143
  for (const { css } of internalConsumableMap.values()) {
146
144
  settings.injectedCsp.styleHashes.push(await generateCspDigest(css, algorithm));
147
145
  }
148
- const resources = urlResolver.getCspResources();
149
- for (const resource of resources) {
146
+ for (const resource of urlResolver.cspResources) {
150
147
  settings.injectedCsp.fontResources.add(resource);
151
148
  }
152
149
  }
@@ -160,14 +157,14 @@ function fontsPlugin({ settings, sync, logger }) {
160
157
  if (isBuild) {
161
158
  await initialize({
162
159
  cacheDir: new URL(CACHE_DIR, settings.config.cacheDir),
163
- modResolver: createBuildRemoteFontProviderModResolver(),
164
- cssRenderer: createMinifiableCssRenderer({ minify: true }),
165
- urlResolver: createBuildUrlResolver({
160
+ modResolver: new BuildRemoteFontProviderModResolver(),
161
+ cssRenderer: new MinifiableCssRenderer({ minify: true }),
162
+ urlResolver: new BuildUrlResolver({
166
163
  base: baseUrl,
167
164
  assetsPrefix: settings.config.build.assetsPrefix,
168
165
  searchParams: settings.adapter?.client?.assetQueryParams ?? new URLSearchParams()
169
166
  }),
170
- createHashResolver: createBuildUrlProxyHashResolver
167
+ createHashResolver: (dependencies) => new BuildUrlProxyHashResolver(dependencies)
171
168
  });
172
169
  }
173
170
  },
@@ -175,13 +172,13 @@ function fontsPlugin({ settings, sync, logger }) {
175
172
  await initialize({
176
173
  // In dev, we cache fonts data in .astro so it can be easily inspected and cleared
177
174
  cacheDir: new URL(CACHE_DIR, settings.dotAstroDir),
178
- modResolver: createDevServerRemoteFontProviderModResolver({ server }),
179
- cssRenderer: createMinifiableCssRenderer({ minify: false }),
180
- urlResolver: createDevUrlResolver({
175
+ modResolver: new DevServerRemoteFontProviderModResolver({ server }),
176
+ cssRenderer: new MinifiableCssRenderer({ minify: false }),
177
+ urlResolver: new DevUrlResolver({
181
178
  base: baseUrl,
182
179
  searchParams: settings.adapter?.client?.assetQueryParams ?? new URLSearchParams()
183
180
  }),
184
- createHashResolver: createDevUrlProxyHashResolver
181
+ createHashResolver: (dependencies) => new DevUrlProxyHashResolver(dependencies)
185
182
  });
186
183
  const localPaths = [...fontFileDataMap.values()].filter(({ url }) => isAbsolute(url)).map((v) => v.url);
187
184
  server.watcher.on("change", (path) => {
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "5.16.2";
3
+ version = "5.16.4";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -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.16.2") {
167
+ if (previousAstroVersion && previousAstroVersion !== "5.16.4") {
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.16.2") {
176
- await this.#store.metaStore().set("astro-version", "5.16.2");
175
+ if ("5.16.4") {
176
+ await this.#store.metaStore().set("astro-version", "5.16.4");
177
177
  }
178
178
  if (currentConfigDigest) {
179
179
  await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -30,6 +30,7 @@ import { ensure404Route } from "../routing/astro-designed-error-pages.js";
30
30
  import { createDefaultRoutes } from "../routing/default.js";
31
31
  import { matchRoute } from "../routing/match.js";
32
32
  import { PERSIST_SYMBOL } from "../session.js";
33
+ import { validateAndDecodePathname } from "../util/pathname.js";
33
34
  import { AppPipeline } from "./pipeline.js";
34
35
  import { deserializeManifest } from "./common.js";
35
36
  class App {
@@ -197,7 +198,7 @@ class App {
197
198
  const url = new URL(request.url);
198
199
  const pathname = prependForwardSlash(this.removeBase(url.pathname));
199
200
  try {
200
- return decodeURI(pathname);
201
+ return validateAndDecodePathname(pathname);
201
202
  } catch (e) {
202
203
  this.getAdapterLogger().error(e.toString());
203
204
  return pathname;
@@ -218,7 +219,12 @@ class App {
218
219
  if (!pathname) {
219
220
  pathname = prependForwardSlash(this.removeBase(url.pathname));
220
221
  }
221
- let routeData = matchRoute(decodeURI(pathname), this.#manifestData);
222
+ try {
223
+ pathname = validateAndDecodePathname(pathname);
224
+ } catch {
225
+ return void 0;
226
+ }
227
+ let routeData = matchRoute(pathname, this.#manifestData);
222
228
  if (!routeData) return void 0;
223
229
  if (allowPrerenderedRoutes) {
224
230
  return routeData;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.16.2";
1
+ const ASTRO_VERSION = "5.16.4";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -0,0 +1,11 @@
1
+ import type { SSRManifestCSP } from '../app/types.js';
2
+ import type { CspDirective } from './config.js';
3
+ /**
4
+ * `existingDirective` is something like `img-src 'self'`. Same as `newDirective`.
5
+ *
6
+ * Returns `undefined` if no directive has been deduped
7
+ * @param existingDirective
8
+ * @param newDirective
9
+ */
10
+ export declare function deduplicateDirectiveValues(existingDirective: CspDirective, newDirective: CspDirective): CspDirective | undefined;
11
+ export declare function pushDirective(directives: SSRManifestCSP['directives'], newDirective: CspDirective): SSRManifestCSP['directives'];
@@ -0,0 +1,35 @@
1
+ function deduplicateDirectiveValues(existingDirective, newDirective) {
2
+ const [directiveName, ...existingValues] = existingDirective.split(/\s+/).filter(Boolean);
3
+ const [newDirectiveName, ...newValues] = newDirective.split(/\s+/).filter(Boolean);
4
+ if (directiveName !== newDirectiveName) {
5
+ return void 0;
6
+ }
7
+ const finalDirectives = Array.from(/* @__PURE__ */ new Set([...existingValues, ...newValues]));
8
+ return `${directiveName} ${finalDirectives.join(" ")}`;
9
+ }
10
+ function pushDirective(directives, newDirective) {
11
+ let deduplicated = false;
12
+ if (directives.length === 0) {
13
+ return [newDirective];
14
+ }
15
+ const finalDirectives = [];
16
+ for (const directive of directives) {
17
+ if (deduplicated) {
18
+ finalDirectives.push(directive);
19
+ continue;
20
+ }
21
+ const result = deduplicateDirectiveValues(directive, newDirective);
22
+ if (result) {
23
+ finalDirectives.push(result);
24
+ deduplicated = true;
25
+ } else {
26
+ finalDirectives.push(directive);
27
+ finalDirectives.push(newDirective);
28
+ }
29
+ }
30
+ return finalDirectives;
31
+ }
32
+ export {
33
+ deduplicateDirectiveValues,
34
+ pushDirective
35
+ };
@@ -22,7 +22,7 @@ async function dev(inlineConfig) {
22
22
  await telemetry.record([]);
23
23
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
24
24
  const logger = restart.container.logger;
25
- const currentVersion = "5.16.2";
25
+ const currentVersion = "5.16.4";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "5.16.2";
41
+ const version = "5.16.4";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -275,7 +275,7 @@ function printHelp({
275
275
  message.push(
276
276
  linebreak(),
277
277
  ` ${bgGreen(black(` ${commandName} `))} ${green(
278
- `v${"5.16.2"}`
278
+ `v${"5.16.4"}`
279
279
  )} ${headline}`
280
280
  );
281
281
  }
@@ -20,6 +20,7 @@ import {
20
20
  } from "./constants.js";
21
21
  import { AstroCookies, attachCookiesToResponse } from "./cookies/index.js";
22
22
  import { getCookiesFromResponse } from "./cookies/response.js";
23
+ import { pushDirective } from "./csp/runtime.js";
23
24
  import { generateCspDigest } from "./encryption.js";
24
25
  import { CspNotEnabled, ForbiddenRewrite } from "./errors/errors-data.js";
25
26
  import { AstroError, AstroErrorData } from "./errors/index.js";
@@ -30,6 +31,7 @@ import { getParams, getProps, Slots } from "./render/index.js";
30
31
  import { isRoute404or500, isRouteExternalRedirect, isRouteServerIsland } from "./routing/match.js";
31
32
  import { copyRequest, getOriginPathname, setOriginPathname } from "./routing/rewrite.js";
32
33
  import { AstroSession } from "./session.js";
34
+ import { validateAndDecodePathname } from "./util/pathname.js";
33
35
  const apiContextRoutesSymbol = Symbol.for("context.routes");
34
36
  class RenderContext {
35
37
  constructor(pipeline, locals, middleware, actions, pathname, request, routeData, status, clientAddress, cookies = new AstroCookies(request), params = getParams(routeData, pathname), url = RenderContext.#createNormalizedUrl(request.url), props = {}, partial = void 0, shouldInjectCspMetaTags = !!pipeline.manifest.csp, session = pipeline.manifest.sessionConfig ? new AstroSession(cookies, pipeline.manifest.sessionConfig, pipeline.runtimeMode) : void 0) {
@@ -53,10 +55,14 @@ class RenderContext {
53
55
  static #createNormalizedUrl(requestUrl) {
54
56
  const url = new URL(requestUrl);
55
57
  try {
56
- url.pathname = decodeURI(url.pathname);
57
- } finally {
58
- return url;
58
+ url.pathname = validateAndDecodePathname(url.pathname);
59
+ } catch {
60
+ try {
61
+ url.pathname = decodeURI(url.pathname);
62
+ } catch {
63
+ }
59
64
  }
65
+ return url;
60
66
  }
61
67
  /**
62
68
  * A flag that tells the render content if the rewriting was triggered
@@ -367,7 +373,14 @@ class RenderContext {
367
373
  if (!pipeline.manifest.csp) {
368
374
  throw new AstroError(CspNotEnabled);
369
375
  }
370
- renderContext.result?.directives.push(payload);
376
+ if (renderContext?.result?.directives) {
377
+ renderContext.result.directives = pushDirective(
378
+ renderContext.result.directives,
379
+ payload
380
+ );
381
+ } else {
382
+ renderContext?.result?.directives.push(payload);
383
+ }
371
384
  },
372
385
  insertScriptResource(resource) {
373
386
  if (!pipeline.manifest.csp) {
@@ -596,7 +609,14 @@ class RenderContext {
596
609
  if (!pipeline.manifest.csp) {
597
610
  throw new AstroError(CspNotEnabled);
598
611
  }
599
- renderContext.result?.directives.push(payload);
612
+ if (renderContext?.result?.directives) {
613
+ renderContext.result.directives = pushDirective(
614
+ renderContext.result.directives,
615
+ payload
616
+ );
617
+ } else {
618
+ renderContext?.result?.directives.push(payload);
619
+ }
600
620
  },
601
621
  insertScriptResource(resource) {
602
622
  if (!pipeline.manifest.csp) {