astro 7.1.5 → 7.2.0

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 (113) hide show
  1. package/dist/assets/build/generate.d.ts +8 -1
  2. package/dist/assets/build/generate.js +21 -1
  3. package/dist/assets/fonts/providers/index.js +12 -2
  4. package/dist/assets/types.d.ts +13 -0
  5. package/dist/assets/vite-plugin-assets.js +8 -0
  6. package/dist/cli/add/index.js +1 -1
  7. package/dist/cli/agent.d.ts +1 -0
  8. package/dist/cli/agent.js +11 -0
  9. package/dist/cli/dev/background.d.ts +3 -16
  10. package/dist/cli/dev/background.js +7 -93
  11. package/dist/cli/dev/index.d.ts +12 -0
  12. package/dist/cli/dev/index.js +30 -23
  13. package/dist/cli/dev/logs.js +2 -64
  14. package/dist/cli/dev/status.d.ts +2 -9
  15. package/dist/cli/dev/status.js +6 -24
  16. package/dist/cli/dev/stop.d.ts +2 -6
  17. package/dist/cli/dev/stop.js +6 -14
  18. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  19. package/dist/cli/install-package.js +1 -1
  20. package/dist/cli/preview/index.js +77 -3
  21. package/dist/cli/server.d.ts +60 -0
  22. package/dist/cli/server.js +274 -0
  23. package/dist/content/consts.d.ts +4 -0
  24. package/dist/content/consts.js +8 -0
  25. package/dist/content/content-layer.js +3 -3
  26. package/dist/content/data-store-writer.d.ts +1 -1
  27. package/dist/content/data-store-writer.js +4 -3
  28. package/dist/content/data-store.d.ts +3 -3
  29. package/dist/content/data-store.js +3 -3
  30. package/dist/content/mutable-data-store.d.ts +3 -3
  31. package/dist/content/mutable-data-store.js +5 -5
  32. package/dist/content/paths.d.ts +2 -1
  33. package/dist/content/paths.js +11 -0
  34. package/dist/content/runtime.d.ts +2 -0
  35. package/dist/content/runtime.js +2 -0
  36. package/dist/content/types-generator.js +1 -0
  37. package/dist/content/vite-plugin-content-assets.js +6 -1
  38. package/dist/content/vite-plugin-content-imports.js +12 -3
  39. package/dist/content/vite-plugin-content-virtual-mod.js +69 -31
  40. package/dist/core/app/entrypoints/index.d.ts +2 -0
  41. package/dist/core/app/entrypoints/index.js +14 -0
  42. package/dist/core/build/config-hash/index.d.ts +8 -0
  43. package/dist/core/build/config-hash/index.js +23 -0
  44. package/dist/core/build/config-hash/input.d.ts +199 -0
  45. package/dist/core/build/config-hash/input.js +43 -0
  46. package/dist/core/build/generate.d.ts +3 -1
  47. package/dist/core/build/generate.js +204 -62
  48. package/dist/core/build/incremental-content-collector.d.ts +10 -0
  49. package/dist/core/build/incremental-content-collector.js +33 -0
  50. package/dist/core/build/incremental-image-collector.d.ts +11 -0
  51. package/dist/core/build/incremental-image-collector.js +32 -0
  52. package/dist/core/build/incremental-metadata.d.ts +9 -0
  53. package/dist/core/build/incremental-metadata.js +17 -0
  54. package/dist/core/build/incremental.d.ts +123 -0
  55. package/dist/core/build/incremental.js +178 -0
  56. package/dist/core/build/index.d.ts +3 -0
  57. package/dist/core/build/index.js +6 -2
  58. package/dist/core/build/internal.d.ts +19 -0
  59. package/dist/core/build/lockfile/finder.d.ts +22 -0
  60. package/dist/core/build/lockfile/finder.js +45 -0
  61. package/dist/core/build/lockfile/hasher.d.ts +16 -0
  62. package/dist/core/build/lockfile/hasher.js +46 -0
  63. package/dist/core/build/lockfile/index.d.ts +9 -0
  64. package/dist/core/build/lockfile/index.js +16 -0
  65. package/dist/core/build/plugins/index.js +3 -1
  66. package/dist/core/build/plugins/plugin-incremental.d.ts +14 -0
  67. package/dist/core/build/plugins/plugin-incremental.js +134 -0
  68. package/dist/core/build/types.d.ts +2 -0
  69. package/dist/core/config/schemas/base.d.ts +7 -6
  70. package/dist/core/config/schemas/base.js +9 -1
  71. package/dist/core/config/schemas/defaults.d.ts +1 -0
  72. package/dist/core/config/schemas/defaults.js +1 -0
  73. package/dist/core/config/schemas/relative.d.ts +19 -10
  74. package/dist/core/constants.js +1 -1
  75. package/dist/core/create-vite.js +2 -1
  76. package/dist/core/dev/dev.js +5 -4
  77. package/dist/core/dev/lockfile.d.ts +8 -7
  78. package/dist/core/dev/lockfile.js +13 -13
  79. package/dist/core/encryption.d.ts +6 -0
  80. package/dist/core/encryption.js +14 -2
  81. package/dist/core/errors/default-handler.js +4 -5
  82. package/dist/core/fetch/index.js +1 -1
  83. package/dist/core/logger/config.d.ts +1 -1
  84. package/dist/core/logger/load.d.ts +3 -1
  85. package/dist/core/logger/load.js +3 -3
  86. package/dist/core/logger/utils.d.ts +6 -4
  87. package/dist/core/logger/utils.js +13 -5
  88. package/dist/core/logger/vite-plugin.js +1 -1
  89. package/dist/core/messages/runtime.js +1 -1
  90. package/dist/core/preview/static-preview-server.d.ts +2 -0
  91. package/dist/core/preview/static-preview-server.js +1 -0
  92. package/dist/core/routing/handler.js +1 -1
  93. package/dist/core/session/config.d.ts +2 -2
  94. package/dist/core/session/config.js +2 -1
  95. package/dist/core/session/provider-disabled.d.ts +2 -0
  96. package/dist/core/session/provider-disabled.js +7 -0
  97. package/dist/core/session/provider.d.ts +1 -0
  98. package/dist/core/session/provider.js +4 -0
  99. package/dist/core/session/utils.js +3 -0
  100. package/dist/core/session/vite-plugin.d.ts +3 -0
  101. package/dist/core/session/vite-plugin.js +41 -6
  102. package/dist/core/sync/index.js +5 -4
  103. package/dist/integrations/hooks.js +3 -1
  104. package/dist/runtime/prerender/static-paths.js +5 -1
  105. package/dist/runtime/server/render/util.js +3 -0
  106. package/dist/types/public/common.d.ts +1 -0
  107. package/dist/types/public/config.d.ts +73 -7
  108. package/dist/types/public/integrations.d.ts +29 -2
  109. package/dist/types/public/preview.d.ts +2 -0
  110. package/dist/vite-plugin-config-alias/index.js +1 -0
  111. package/dist/vite-plugin-environment/index.js +4 -1
  112. package/dist/vite-plugin-hmr-reload/index.js +60 -18
  113. package/package.json +2 -3
@@ -345,7 +345,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
345
345
  }, z.core.$strip>]>>>>>;
346
346
  validateSecrets: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
347
347
  }, z.core.$strict>>>;
348
- session: z.ZodOptional<z.ZodObject<{
348
+ session: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
349
349
  driver: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
350
350
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
351
351
  entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
@@ -366,7 +366,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
366
366
  name: string;
367
367
  }, string>>]>>;
368
368
  ttl: z.ZodOptional<z.ZodNumber>;
369
- }, z.core.$strip>>;
369
+ }, z.core.$strip>]>>;
370
370
  prerenderConflictBehavior: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
371
371
  error: "error";
372
372
  ignore: "ignore";
@@ -436,14 +436,15 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
436
436
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
437
437
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
438
438
  chromeDevtoolsWorkspace: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
439
+ incrementalBuild: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
439
440
  svgOptimizer: z.ZodOptional<z.ZodObject<{
440
441
  name: z.ZodString;
441
442
  optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
442
443
  }, z.core.$strip>>;
443
- collectionStorage: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
444
- "single-file": "single-file";
445
- chunked: "chunked";
446
- }>>>;
444
+ collectionStorage: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"single-file">, z.ZodLiteral<"chunked">, z.ZodObject<{
445
+ type: z.ZodLiteral<"chunked">;
446
+ chunkSize: z.ZodNumber;
447
+ }, z.core.$strict>]>>>;
447
448
  }, z.core.$strict>>;
448
449
  legacy: z.ZodPrefault<z.ZodObject<{
449
450
  collectionsBackwardsCompat: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -630,7 +631,11 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
630
631
  clientPrerender: boolean;
631
632
  contentIntellisense: boolean;
632
633
  chromeDevtoolsWorkspace: boolean;
633
- collectionStorage: "single-file" | "chunked";
634
+ incrementalBuild: boolean;
635
+ collectionStorage: "single-file" | "chunked" | {
636
+ type: "chunked";
637
+ chunkSize: number;
638
+ };
634
639
  svgOptimizer?: {
635
640
  name: string;
636
641
  optimize: (contents: string) => string | Promise<string>;
@@ -690,7 +695,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
690
695
  domains?: Record<string, string> | undefined;
691
696
  fallback?: Record<string, string> | undefined;
692
697
  } | undefined;
693
- session?: {
698
+ session?: false | {
694
699
  driver?: string | {
695
700
  entrypoint: string | URL;
696
701
  config?: Record<string, any> | undefined;
@@ -893,7 +898,11 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
893
898
  clientPrerender: boolean;
894
899
  contentIntellisense: boolean;
895
900
  chromeDevtoolsWorkspace: boolean;
896
- collectionStorage: "single-file" | "chunked";
901
+ incrementalBuild: boolean;
902
+ collectionStorage: "single-file" | "chunked" | {
903
+ type: "chunked";
904
+ chunkSize: number;
905
+ };
897
906
  svgOptimizer?: {
898
907
  name: string;
899
908
  optimize: (contents: string) => string | Promise<string>;
@@ -953,7 +962,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
953
962
  domains?: Record<string, string> | undefined;
954
963
  fallback?: Record<string, string> | undefined;
955
964
  } | undefined;
956
- session?: {
965
+ session?: false | {
957
966
  driver?: string | {
958
967
  entrypoint: string | URL;
959
968
  config?: Record<string, any> | undefined;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.1.5";
1
+ const ASTRO_VERSION = "7.2.0";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const ASTRO_ERROR_HEADER = "X-Astro-Error";
4
4
  const DEFAULT_404_COMPONENT = "astro-default-404.astro";
@@ -47,7 +47,7 @@ import { joinPaths } from "./path.js";
47
47
  import { ServerIslandsState } from "./server-islands/shared-state.js";
48
48
  import { vitePluginServerIslands } from "./server-islands/vite-plugin-server-islands.js";
49
49
  import { vitePluginCacheProvider } from "./cache/vite-plugin.js";
50
- import { vitePluginSessionDriver } from "./session/vite-plugin.js";
50
+ import { vitePluginSessionDriver, vitePluginSessionProvider } from "./session/vite-plugin.js";
51
51
  import { vitePluginLogger } from "./logger/vite-plugin.js";
52
52
  import { isObject } from "./util-runtime.js";
53
53
  import { vitePluginEnvironment } from "../vite-plugin-environment/index.js";
@@ -180,6 +180,7 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
180
180
  vitePluginActions({ fs, settings }),
181
181
  vitePluginServerIslands({ settings, logger, serverIslandsState }),
182
182
  vitePluginSessionDriver({ settings }),
183
+ vitePluginSessionProvider({ settings }),
183
184
  vitePluginCacheProvider({ settings }),
184
185
  vitePluginLogger({ settings }),
185
186
  astroContainer(),
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import { performance } from "node:perf_hooks";
3
3
  import colors from "piccolore";
4
4
  import { gt, major, minor, patch } from "semver";
5
- import { getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
5
+ import { getDataStoreChunkSize, getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
6
6
  import { globalContentLayer } from "../../content/instance.js";
7
7
  import { attachContentServerListeners } from "../../content/index.js";
8
8
  import { MutableDataStore } from "../../content/mutable-data-store.js";
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
26
26
  await telemetry.record([]);
27
27
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
28
28
  const logger = restart.container.logger;
29
- const currentVersion = "7.1.5";
29
+ const currentVersion = "7.2.0";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -56,9 +56,10 @@ async function dev(inlineConfig) {
56
56
  }
57
57
  let store;
58
58
  try {
59
- if (restart.container.settings.config.experimental.collectionStorage === "chunked") {
59
+ const chunkSize = getDataStoreChunkSize(restart.container.settings);
60
+ if (chunkSize !== void 0) {
60
61
  const dataStoreDir = getDataStoreDir(restart.container.settings, true);
61
- store = await MutableDataStore.fromDir(dataStoreDir);
62
+ store = await MutableDataStore.fromDir(dataStoreDir, chunkSize);
62
63
  } else {
63
64
  const dataStoreFile = getDataStoreFile(restart.container.settings, true);
64
65
  store = await MutableDataStore.fromFile(dataStoreFile);
@@ -1,4 +1,5 @@
1
1
  import type { ResolvedServerUrls } from 'vite';
2
+ export type ServerCommand = 'dev' | 'preview';
2
3
  /** Maximum time (ms) to wait for a process to exit after SIGTERM before escalating to SIGKILL. */
3
4
  export declare const GRACEFUL_SHUTDOWN_TIMEOUT = 5000;
4
5
  export interface LockFileData {
@@ -14,9 +15,9 @@ export interface ExistingServer {
14
15
  stale: boolean;
15
16
  }
16
17
  /**
17
- * Get the URL of the dev log file for a given project root.
18
+ * Get the URL of a server log file for a given project root.
18
19
  */
19
- export declare function getLogFileURL(root: URL): URL;
20
+ export declare function getLogFileURL(root: URL, command?: ServerCommand): URL;
20
21
  /**
21
22
  * Parse a lock file JSON string into a LockFileData object.
22
23
  * Returns null if the content is invalid.
@@ -34,15 +35,15 @@ export declare function isProcessAlive(pid: number): boolean;
34
35
  /**
35
36
  * Read the lock file from disk. Returns null if it doesn't exist or is invalid.
36
37
  */
37
- export declare function readLockFile(root: URL): LockFileData | null;
38
+ export declare function readLockFile(root: URL, command?: ServerCommand): LockFileData | null;
38
39
  /**
39
40
  * Write the lock file to disk.
40
41
  */
41
- export declare function writeLockFile(root: URL, data: LockFileData): void;
42
+ export declare function writeLockFile(root: URL, data: LockFileData, command?: ServerCommand): void;
42
43
  /**
43
44
  * Remove the lock file from disk. No-op if it doesn't exist.
44
45
  */
45
- export declare function removeLockFile(root: URL): void;
46
+ export declare function removeLockFile(root: URL, command?: ServerCommand): void;
46
47
  /**
47
48
  * Given lock file data and a liveness result, determine the state of the existing server.
48
49
  * This is the pure decision logic, separated from I/O for testability.
@@ -57,8 +58,8 @@ export declare function evaluateExistingServer(data: LockFileData | null, alive:
57
58
  */
58
59
  export declare function killDevServer(root: URL, data: LockFileData): Promise<void>;
59
60
  /**
60
- * Check for an existing dev server by reading the lock file and checking process liveness.
61
+ * Check for an existing server by reading the lock file and checking process liveness.
61
62
  * Automatically cleans up stale lock files.
62
63
  * Returns the server info if a live server is found, null otherwise.
63
64
  */
64
- export declare function checkExistingServer(root: URL): LockFileData | null;
65
+ export declare function checkExistingServer(root: URL, command?: ServerCommand): LockFileData | null;
@@ -1,11 +1,11 @@
1
1
  import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
2
2
  import { fileURLToPath } from "node:url";
3
3
  const GRACEFUL_SHUTDOWN_TIMEOUT = 5e3;
4
- function getLockFileURL(root) {
5
- return new URL(".astro/dev.json", root);
4
+ function getLockFileURL(root, command = "dev") {
5
+ return new URL(`.astro/${command}.json`, root);
6
6
  }
7
- function getLogFileURL(root) {
8
- return new URL(".astro/dev.log", root);
7
+ function getLogFileURL(root, command = "dev") {
8
+ return new URL(`.astro/${command}.log`, root);
9
9
  }
10
10
  function isStringArray(value) {
11
11
  return Array.isArray(value) && value.every((item) => typeof item === "string");
@@ -42,8 +42,8 @@ function isProcessAlive(pid) {
42
42
  return false;
43
43
  }
44
44
  }
45
- function readLockFile(root) {
46
- const lockFileURL = getLockFileURL(root);
45
+ function readLockFile(root, command = "dev") {
46
+ const lockFileURL = getLockFileURL(root, command);
47
47
  try {
48
48
  const content = readFileSync(lockFileURL, "utf-8");
49
49
  return parseLockFile(content);
@@ -51,8 +51,8 @@ function readLockFile(root) {
51
51
  return null;
52
52
  }
53
53
  }
54
- function writeLockFile(root, data) {
55
- const lockFileURL = getLockFileURL(root);
54
+ function writeLockFile(root, data, command = "dev") {
55
+ const lockFileURL = getLockFileURL(root, command);
56
56
  const dirPath = fileURLToPath(new URL(".astro/", root));
57
57
  try {
58
58
  if (!existsSync(dirPath)) {
@@ -64,8 +64,8 @@ function writeLockFile(root, data) {
64
64
  throw new Error(`Failed to write lock file: ${message}`);
65
65
  }
66
66
  }
67
- function removeLockFile(root) {
68
- const lockFileURL = getLockFileURL(root);
67
+ function removeLockFile(root, command = "dev") {
68
+ const lockFileURL = getLockFileURL(root, command);
69
69
  try {
70
70
  unlinkSync(lockFileURL);
71
71
  } catch (err) {
@@ -98,14 +98,14 @@ async function killDevServer(root, data) {
98
98
  }
99
99
  removeLockFile(root);
100
100
  }
101
- function checkExistingServer(root) {
102
- const data = readLockFile(root);
101
+ function checkExistingServer(root, command = "dev") {
102
+ const data = readLockFile(root, command);
103
103
  const result = evaluateExistingServer(data, data !== null && isProcessAlive(data.pid));
104
104
  if (result === null) {
105
105
  return null;
106
106
  }
107
107
  if (result.stale) {
108
- removeLockFile(root);
108
+ removeLockFile(root, command);
109
109
  return null;
110
110
  }
111
111
  return result.data;
@@ -12,6 +12,12 @@ export declare function hasEnvironmentKey(): boolean;
12
12
  * Get the environment variable key and decode it into a CryptoKey.
13
13
  */
14
14
  export declare function getEnvironmentKey(): Promise<CryptoKey>;
15
+ /**
16
+ * Hash a CryptoKey into a one-way hex digest safe to persist. Server-island
17
+ * ciphertext is bound to the key, so the incremental build cache uses this to
18
+ * detect when the key changed between builds.
19
+ */
20
+ export declare function hashCryptoKey(key: CryptoKey): Promise<string>;
15
21
  /**
16
22
  * Encodes a CryptoKey to base64 string, so that it can be embedded in JSON / JavaScript
17
23
  */
@@ -1,4 +1,10 @@
1
- import { decodeBase64, decodeHex, encodeBase64, encodeHexUpperCase } from "@oslojs/encoding";
1
+ import {
2
+ decodeBase64,
3
+ decodeHex,
4
+ encodeBase64,
5
+ encodeHexLowerCase,
6
+ encodeHexUpperCase
7
+ } from "@oslojs/encoding";
2
8
  import { ALGORITHMS } from "./csp/config.js";
3
9
  const ALGORITHM = "AES-GCM";
4
10
  async function createKey() {
@@ -28,6 +34,11 @@ async function getEnvironmentKey() {
28
34
  const encodedKey = getEncodedEnvironmentKey();
29
35
  return decodeKey(encodedKey);
30
36
  }
37
+ async function hashCryptoKey(key) {
38
+ const exported = await crypto.subtle.exportKey("raw", key);
39
+ const digest = await crypto.subtle.digest("SHA-256", exported);
40
+ return encodeHexLowerCase(new Uint8Array(digest));
41
+ }
31
42
  async function encodeKey(key) {
32
43
  const exported = await crypto.subtle.exportKey("raw", key);
33
44
  const encodedKey = encodeBase64(new Uint8Array(exported));
@@ -83,5 +94,6 @@ export {
83
94
  generateContentHash,
84
95
  generateCspDigest,
85
96
  getEnvironmentKey,
86
- hasEnvironmentKey
97
+ hasEnvironmentKey,
98
+ hashCryptoKey
87
99
  };
@@ -5,7 +5,7 @@ import { getCookiesFromResponse } from "../cookies/response.js";
5
5
  import { AstroMiddleware } from "../middleware/astro-middleware.js";
6
6
  import { PagesHandler } from "../pages/handler.js";
7
7
  import { matchRoute } from "../routing/match.js";
8
- import { provideSession } from "../session/handler.js";
8
+ import { provideSession } from "../session/provider.js";
9
9
  import { validateHost } from "../app/validate-headers.js";
10
10
  import { getErrorRoutePath } from "../../i18n/error-routes.js";
11
11
  import { getOutputFilename } from "../output-filename.js";
@@ -152,7 +152,8 @@ function mergeResponses(newResponse, originalResponse, override) {
152
152
  seen.add(name.toLowerCase());
153
153
  }
154
154
  for (const [name, value] of newResponseHeaders) {
155
- if (!seen.has(name.toLowerCase())) {
155
+ const lower = name.toLowerCase();
156
+ if (!seen.has(lower) || lower === "set-cookie") {
156
157
  newHeaders.append(name, value);
157
158
  }
158
159
  }
@@ -170,9 +171,7 @@ function mergeResponses(newResponse, originalResponse, override) {
170
171
  const newCookies = getCookiesFromResponse(newResponse);
171
172
  if (originalCookies) {
172
173
  if (newCookies) {
173
- for (const cookieValue of newCookies.consume()) {
174
- originalResponse.headers.append("set-cookie", cookieValue);
175
- }
174
+ originalCookies.merge(newCookies);
176
175
  }
177
176
  attachCookiesToResponse(mergedResponse, originalCookies);
178
177
  } else if (newCookies) {
@@ -7,7 +7,7 @@ import { AstroMiddleware } from "../middleware/astro-middleware.js";
7
7
  import { PagesHandler } from "../pages/handler.js";
8
8
  import { renderRedirect } from "../redirects/render.js";
9
9
  import { AstroHandler } from "../routing/handler.js";
10
- import { provideSession } from "../session/handler.js";
10
+ import { provideSession } from "../session/provider.js";
11
11
  import { TrailingSlashHandler } from "../routing/trailing-slash-handler.js";
12
12
  function getApp(request) {
13
13
  const app = Reflect.get(request, appSymbol);
@@ -1,6 +1,6 @@
1
1
  export interface LoggerHandlerConfig {
2
2
  /** Serializable options used by the driver implementation */
3
3
  config?: Record<string, any> | undefined;
4
- /** URL or package import */
4
+ /** A package import, a path relative to the project root, or a URL */
5
5
  entrypoint: string | URL;
6
6
  }
@@ -5,7 +5,9 @@ import type { AstroConfig, AstroInlineConfig } from '../../types/public/index.js
5
5
  * Loads a logger destination in a Node context, i.e. outside of a built server bundle.
6
6
  * Inside the bundle, the destination comes from the `virtual:astro:logger` module instead.
7
7
  */
8
- export declare function loadLoggerDestination(config: LoggerHandlerConfig): Promise<AstroLoggerDestination>;
8
+ export declare function loadLoggerDestination(config: LoggerHandlerConfig,
9
+ /** The project root, which relative entrypoints are resolved against */
10
+ root: URL): Promise<AstroLoggerDestination>;
9
11
  /**
10
12
  * It attempts to load a logger from the entrypoint.
11
13
  * If not provided, it creates a new logger instance on the fly.
@@ -19,8 +19,8 @@ async function createDestination(config) {
19
19
  }
20
20
  return logger.default(config.config);
21
21
  }
22
- async function loadLoggerDestination(config) {
23
- const normalized = normalizeLoggerConfig(config);
22
+ async function loadLoggerDestination(config, root) {
23
+ const normalized = normalizeLoggerConfig(config, root);
24
24
  try {
25
25
  return await createDestination(normalized);
26
26
  } catch (e) {
@@ -39,7 +39,7 @@ async function loadOrCreateNodeLogger(astroConfig, inlineAstroConfig) {
39
39
  try {
40
40
  if (astroConfig.logger) {
41
41
  return new AstroLogger({
42
- destination: await loadLoggerDestination(astroConfig.logger),
42
+ destination: await loadLoggerDestination(astroConfig.logger, astroConfig.root),
43
43
  level: inlineAstroConfig.logLevel ?? "info"
44
44
  });
45
45
  } else {
@@ -14,8 +14,10 @@ export interface NormalizedLoggerConfig {
14
14
  * (see `loadLoggerDestination`), and by applying the same treatment to the handlers
15
15
  * composed through `astro/logger/compose`.
16
16
  *
17
- * Concretely, a `URL` entrypoint becomes an absolute file path — mirroring what session
18
- * drivers do, since both Vite and `import()` can handle those — while a string entrypoint,
19
- * e.g. a package specifier, is left untouched.
17
+ * Concretely, `URL` and relative entrypoints become absolute file paths — mirroring what
18
+ * session drivers do, since both Vite and `import()` can handle those — while any other
19
+ * string entrypoint, e.g. a package specifier, is left untouched.
20
20
  */
21
- export declare function normalizeLoggerConfig(logger: LoggerHandlerConfig): NormalizedLoggerConfig;
21
+ export declare function normalizeLoggerConfig(logger: LoggerHandlerConfig,
22
+ /** The project root, which relative entrypoints are resolved against */
23
+ root: URL): NormalizedLoggerConfig;
@@ -1,18 +1,26 @@
1
+ import { resolve } from "node:path";
1
2
  import { fileURLToPath } from "node:url";
3
+ import { isRelativePath } from "../path.js";
2
4
  const COMPOSE_LOGGER_ENTRYPOINT = "astro/logger/compose";
3
- function normalizeLoggerConfig(logger) {
4
- const entrypoint = normalizeEntrypoint(logger.entrypoint);
5
+ function normalizeLoggerConfig(logger, root) {
6
+ const entrypoint = normalizeEntrypoint(logger.entrypoint, root);
5
7
  if (entrypoint === COMPOSE_LOGGER_ENTRYPOINT) {
6
8
  const loggers = logger.config?.loggers ?? [];
7
9
  return {
8
10
  entrypoint,
9
- loggers: loggers.map((nested) => normalizeLoggerConfig(nested))
11
+ loggers: loggers.map((nested) => normalizeLoggerConfig(nested, root))
10
12
  };
11
13
  }
12
14
  return { entrypoint, config: logger.config };
13
15
  }
14
- function normalizeEntrypoint(entrypoint) {
15
- return entrypoint instanceof URL ? fileURLToPath(entrypoint) : entrypoint;
16
+ function normalizeEntrypoint(entrypoint, root) {
17
+ if (entrypoint instanceof URL) {
18
+ return fileURLToPath(entrypoint);
19
+ }
20
+ if (isRelativePath(entrypoint)) {
21
+ return resolve(fileURLToPath(root), entrypoint);
22
+ }
23
+ return entrypoint;
16
24
  }
17
25
  export {
18
26
  COMPOSE_LOGGER_ENTRYPOINT,
@@ -60,7 +60,7 @@ function vitePluginLogger({
60
60
  async handler() {
61
61
  const importerPath = fileURLToPath(new URL("package.json", settings.config.root));
62
62
  const { expression, imports } = await emitDestination(
63
- normalizeLoggerConfig(loggerConfig),
63
+ normalizeLoggerConfig(loggerConfig, settings.config.root),
64
64
  async (entrypoint) => (await this.resolve(entrypoint, importerPath))?.id ?? null
65
65
  );
66
66
  return {
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"7.1.5"}`
273
+ `v${"7.2.0"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -1,9 +1,11 @@
1
1
  import type http from 'node:http';
2
+ import type * as vite from 'vite';
2
3
  import type { AstroSettings } from '../../types/astro.js';
3
4
  import type { AstroLogger } from '../logger/core.js';
4
5
  interface PreviewServer {
5
6
  host?: string;
6
7
  port: number;
8
+ urls?: vite.ResolvedServerUrls;
7
9
  server: http.Server;
8
10
  closed(): Promise<void>;
9
11
  stop(): Promise<void>;
@@ -73,6 +73,7 @@ async function createStaticPreviewServer(settings, logger) {
73
73
  return {
74
74
  host: getResolvedHostForHttpServer(settings.config.server.host),
75
75
  port: actualPort,
76
+ urls: previewServer.resolvedUrls ?? { local: [], network: [] },
76
77
  closed,
77
78
  server: previewServer.httpServer,
78
79
  stop: previewServer.close.bind(previewServer)
@@ -6,7 +6,7 @@ import { I18n } from "../i18n/handler.js";
6
6
  import { AstroMiddleware } from "../middleware/astro-middleware.js";
7
7
  import { PagesHandler } from "../pages/handler.js";
8
8
  import { renderRedirect } from "../redirects/render.js";
9
- import { provideSession } from "../session/handler.js";
9
+ import { provideSession } from "../session/provider.js";
10
10
  import { prepareResponse } from "../app/prepare-response.js";
11
11
  import { ALL_PIPELINE_FEATURES, PipelineFeatures } from "../base-pipeline.js";
12
12
  class AstroHandler {
@@ -3,7 +3,7 @@ export declare const SessionDriverConfigSchema: z.ZodObject<{
3
3
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
4
4
  entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
5
5
  }, z.core.$strip>;
6
- export declare const SessionSchema: z.ZodObject<{
6
+ export declare const SessionSchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
7
7
  driver: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
8
8
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
9
9
  entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
@@ -24,4 +24,4 @@ export declare const SessionSchema: z.ZodObject<{
24
24
  name: string;
25
25
  }, string>>]>>;
26
26
  ttl: z.ZodOptional<z.ZodNumber>;
27
- }, z.core.$strip>;
27
+ }, z.core.$strip>]>;
@@ -3,7 +3,7 @@ const SessionDriverConfigSchema = z.object({
3
3
  config: z.record(z.string(), z.any()).optional(),
4
4
  entrypoint: z.union([z.string(), z.instanceof(URL)])
5
5
  });
6
- const SessionSchema = z.object({
6
+ const SessionObjectSchema = z.object({
7
7
  driver: z.union([
8
8
  z.string().superRefine(() => {
9
9
  console.warn(
@@ -26,6 +26,7 @@ const SessionSchema = z.object({
26
26
  ]).optional(),
27
27
  ttl: z.number().optional()
28
28
  });
29
+ const SessionSchema = z.union([z.literal(false), SessionObjectSchema]);
29
30
  export {
30
31
  SessionDriverConfigSchema,
31
32
  SessionSchema
@@ -0,0 +1,2 @@
1
+ import type { FetchState } from '../fetch/fetch-state.js';
2
+ export declare function provideSession(state: FetchState): void;
@@ -0,0 +1,7 @@
1
+ import { PipelineFeatures } from "../base-pipeline.js";
2
+ function provideSession(state) {
3
+ state.pipeline.usedFeatures |= PipelineFeatures.sessions;
4
+ }
5
+ export {
6
+ provideSession
7
+ };
@@ -0,0 +1 @@
1
+ export { provideSession } from './handler.js';
@@ -0,0 +1,4 @@
1
+ import { provideSession } from "./handler.js";
2
+ export {
3
+ provideSession
4
+ };
@@ -31,6 +31,9 @@ function normalizeSessionDriverConfig(driver, options) {
31
31
  };
32
32
  }
33
33
  function sessionConfigToManifest(config) {
34
+ if (config === false) {
35
+ return void 0;
36
+ }
34
37
  const sessionDriver = config?.driver;
35
38
  if (!config || !sessionDriver) {
36
39
  return void 0;
@@ -4,3 +4,6 @@ export declare const VIRTUAL_SESSION_DRIVER_ID = "virtual:astro:session-driver";
4
4
  export declare function vitePluginSessionDriver({ settings }: {
5
5
  settings: AstroSettings;
6
6
  }): VitePlugin;
7
+ export declare function vitePluginSessionProvider({ settings }: {
8
+ settings: AstroSettings;
9
+ }): VitePlugin;
@@ -1,6 +1,8 @@
1
+ import { realpathSync } from "node:fs";
1
2
  import { fileURLToPath } from "node:url";
2
3
  import { SessionStorageInitError } from "../errors/errors-data.js";
3
4
  import { AstroError } from "../errors/index.js";
5
+ import { normalizePath } from "../viteUtils.js";
4
6
  import { normalizeSessionDriverConfig } from "./utils.js";
5
7
  const VIRTUAL_SESSION_DRIVER_ID = "virtual:astro:session-driver";
6
8
  const RESOLVED_VIRTUAL_SESSION_DRIVER_ID = "\0" + VIRTUAL_SESSION_DRIVER_ID;
@@ -21,13 +23,11 @@ function vitePluginSessionDriver({ settings }) {
21
23
  id: new RegExp(`^${RESOLVED_VIRTUAL_SESSION_DRIVER_ID}$`)
22
24
  },
23
25
  async handler() {
24
- if (!settings.config.session?.driver) {
26
+ const session = settings.config.session;
27
+ if (session === false || !session?.driver) {
25
28
  return { code: "export default null;" };
26
29
  }
27
- const driver = normalizeSessionDriverConfig(
28
- settings.config.session.driver,
29
- settings.config.session.options
30
- );
30
+ const driver = normalizeSessionDriverConfig(session.driver, session.options);
31
31
  const importerPath = fileURLToPath(import.meta.url);
32
32
  const resolved = await this.resolve(driver.entrypoint, importerPath);
33
33
  if (!resolved) {
@@ -48,7 +48,42 @@ export default _default;`
48
48
  }
49
49
  };
50
50
  }
51
+ const PROVIDER_FILENAME = "provider.js";
52
+ const DISABLED_PROVIDER_FILENAME = "provider-disabled.js";
53
+ function canonicalizePath(filePath) {
54
+ try {
55
+ return normalizePath(realpathSync(filePath));
56
+ } catch {
57
+ return normalizePath(filePath);
58
+ }
59
+ }
60
+ function vitePluginSessionProvider({ settings }) {
61
+ const providerPath = canonicalizePath(
62
+ fileURLToPath(new URL(`./${PROVIDER_FILENAME}`, import.meta.url))
63
+ );
64
+ const disabledProviderPath = canonicalizePath(
65
+ fileURLToPath(new URL(`./${DISABLED_PROVIDER_FILENAME}`, import.meta.url))
66
+ );
67
+ return {
68
+ name: "astro:session-provider",
69
+ enforce: "pre",
70
+ async resolveId(id, importer) {
71
+ const session = settings.config.session;
72
+ const hasSessionDriver = session !== false && !!session?.driver;
73
+ if (hasSessionDriver) return null;
74
+ if (!normalizePath(id).endsWith(`/session/${PROVIDER_FILENAME}`)) return null;
75
+ if (canonicalizePath(id) === providerPath) return disabledProviderPath;
76
+ if (!importer) return null;
77
+ const resolved = await this.resolve(id, importer, { skipSelf: true });
78
+ if (resolved && canonicalizePath(resolved.id) === providerPath) {
79
+ return disabledProviderPath;
80
+ }
81
+ return null;
82
+ }
83
+ };
84
+ }
51
85
  export {
52
86
  VIRTUAL_SESSION_DRIVER_ID,
53
- vitePluginSessionDriver
87
+ vitePluginSessionDriver,
88
+ vitePluginSessionProvider
54
89
  };