astro 7.1.6 → 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 (101) 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/content-layer.js +3 -3
  24. package/dist/content/runtime.d.ts +2 -0
  25. package/dist/content/runtime.js +2 -0
  26. package/dist/content/types-generator.js +1 -0
  27. package/dist/content/vite-plugin-content-assets.js +6 -1
  28. package/dist/content/vite-plugin-content-imports.js +12 -3
  29. package/dist/content/vite-plugin-content-virtual-mod.js +28 -16
  30. package/dist/core/app/entrypoints/index.d.ts +2 -0
  31. package/dist/core/app/entrypoints/index.js +14 -0
  32. package/dist/core/build/config-hash/index.d.ts +8 -0
  33. package/dist/core/build/config-hash/index.js +23 -0
  34. package/dist/core/build/config-hash/input.d.ts +199 -0
  35. package/dist/core/build/config-hash/input.js +43 -0
  36. package/dist/core/build/generate.d.ts +3 -1
  37. package/dist/core/build/generate.js +149 -14
  38. package/dist/core/build/incremental-content-collector.d.ts +10 -0
  39. package/dist/core/build/incremental-content-collector.js +33 -0
  40. package/dist/core/build/incremental-image-collector.d.ts +11 -0
  41. package/dist/core/build/incremental-image-collector.js +32 -0
  42. package/dist/core/build/incremental-metadata.d.ts +9 -0
  43. package/dist/core/build/incremental-metadata.js +17 -0
  44. package/dist/core/build/incremental.d.ts +123 -0
  45. package/dist/core/build/incremental.js +178 -0
  46. package/dist/core/build/index.d.ts +3 -0
  47. package/dist/core/build/index.js +6 -2
  48. package/dist/core/build/internal.d.ts +19 -0
  49. package/dist/core/build/lockfile/finder.d.ts +22 -0
  50. package/dist/core/build/lockfile/finder.js +45 -0
  51. package/dist/core/build/lockfile/hasher.d.ts +16 -0
  52. package/dist/core/build/lockfile/hasher.js +46 -0
  53. package/dist/core/build/lockfile/index.d.ts +9 -0
  54. package/dist/core/build/lockfile/index.js +16 -0
  55. package/dist/core/build/plugins/index.js +3 -1
  56. package/dist/core/build/plugins/plugin-incremental.d.ts +14 -0
  57. package/dist/core/build/plugins/plugin-incremental.js +134 -0
  58. package/dist/core/build/types.d.ts +2 -0
  59. package/dist/core/config/schemas/base.d.ts +3 -2
  60. package/dist/core/config/schemas/base.js +1 -0
  61. package/dist/core/config/schemas/defaults.d.ts +1 -0
  62. package/dist/core/config/schemas/defaults.js +1 -0
  63. package/dist/core/config/schemas/relative.d.ts +7 -4
  64. package/dist/core/constants.js +1 -1
  65. package/dist/core/create-vite.js +2 -1
  66. package/dist/core/dev/dev.js +1 -1
  67. package/dist/core/dev/lockfile.d.ts +8 -7
  68. package/dist/core/dev/lockfile.js +13 -13
  69. package/dist/core/encryption.d.ts +6 -0
  70. package/dist/core/encryption.js +14 -2
  71. package/dist/core/errors/default-handler.js +4 -5
  72. package/dist/core/fetch/index.js +1 -1
  73. package/dist/core/logger/config.d.ts +1 -1
  74. package/dist/core/logger/load.d.ts +3 -1
  75. package/dist/core/logger/load.js +3 -3
  76. package/dist/core/logger/utils.d.ts +6 -4
  77. package/dist/core/logger/utils.js +13 -5
  78. package/dist/core/logger/vite-plugin.js +1 -1
  79. package/dist/core/messages/runtime.js +1 -1
  80. package/dist/core/preview/static-preview-server.d.ts +2 -0
  81. package/dist/core/preview/static-preview-server.js +1 -0
  82. package/dist/core/routing/handler.js +1 -1
  83. package/dist/core/session/config.d.ts +2 -2
  84. package/dist/core/session/config.js +2 -1
  85. package/dist/core/session/provider-disabled.d.ts +2 -0
  86. package/dist/core/session/provider-disabled.js +7 -0
  87. package/dist/core/session/provider.d.ts +1 -0
  88. package/dist/core/session/provider.js +4 -0
  89. package/dist/core/session/utils.js +3 -0
  90. package/dist/core/session/vite-plugin.d.ts +3 -0
  91. package/dist/core/session/vite-plugin.js +41 -6
  92. package/dist/integrations/hooks.js +3 -1
  93. package/dist/runtime/prerender/static-paths.js +5 -1
  94. package/dist/runtime/server/render/util.js +3 -0
  95. package/dist/types/public/common.d.ts +1 -0
  96. package/dist/types/public/config.d.ts +59 -2
  97. package/dist/types/public/integrations.d.ts +29 -2
  98. package/dist/types/public/preview.d.ts +2 -0
  99. package/dist/vite-plugin-config-alias/index.js +1 -0
  100. package/dist/vite-plugin-environment/index.js +4 -1
  101. package/package.json +1 -2
@@ -0,0 +1,134 @@
1
+ import crypto from "node:crypto";
2
+ import { PROPAGATED_ASSET_FLAG } from "../../../content/consts.js";
3
+ import { hasContentFlag } from "../../../content/utils.js";
4
+ import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../../constants.js";
5
+ import { removeQueryString } from "../../path.js";
6
+ import { rootRelativePath } from "../../viteUtils.js";
7
+ import { moduleIsTopLevelPage } from "../graph.js";
8
+ import { isContentDataIncrementalModule } from "../incremental-metadata.js";
9
+ import { getPageDataByViteID } from "../internal.js";
10
+ function collectTransitiveDeps(graph, rootId) {
11
+ const deps = /* @__PURE__ */ new Set();
12
+ const queue = [rootId];
13
+ while (queue.length > 0) {
14
+ const current = queue.pop();
15
+ if (deps.has(current)) continue;
16
+ const modInfo = graph.getModuleInfo(current);
17
+ if (isContentDataIncrementalModule(modInfo)) continue;
18
+ deps.add(current);
19
+ if (!modInfo) continue;
20
+ for (const dep of modInfo.importedIds) {
21
+ if (!deps.has(dep)) queue.push(dep);
22
+ }
23
+ for (const dep of modInfo.dynamicallyImportedIds) {
24
+ if (!deps.has(dep)) queue.push(dep);
25
+ }
26
+ }
27
+ return [...deps].sort();
28
+ }
29
+ function hashModules(graph, sortedIds) {
30
+ const hasher = crypto.createHash("sha256");
31
+ for (const id of sortedIds) {
32
+ hasher.update(id);
33
+ hasher.update("\n");
34
+ const code = graph.getModuleInfo(id)?.code;
35
+ if (code != null) {
36
+ hasher.update(code);
37
+ }
38
+ hasher.update("\n");
39
+ }
40
+ return hasher.digest("hex");
41
+ }
42
+ function collectClientEntrypointHashes(graph, entrypointIds, pagesByEntrypoint, hashesByComponent) {
43
+ for (const entrypointId of entrypointIds) {
44
+ const pages = pagesByEntrypoint.get(entrypointId);
45
+ if (!pages?.size) continue;
46
+ const hash = hashModules(graph, collectTransitiveDeps(graph, entrypointId));
47
+ for (const pageData of pages) {
48
+ let list = hashesByComponent.get(pageData.component);
49
+ if (!list) {
50
+ list = [];
51
+ hashesByComponent.set(pageData.component, list);
52
+ }
53
+ list.push(hash);
54
+ }
55
+ }
56
+ }
57
+ function foldClientDependencies(graph, internals) {
58
+ const baseHashes = internals.pageDependencyHashes;
59
+ if (!baseHashes) return;
60
+ const hashesByComponent = /* @__PURE__ */ new Map();
61
+ collectClientEntrypointHashes(
62
+ graph,
63
+ internals.discoveredClientOnlyComponents.keys(),
64
+ internals.pagesByClientOnly,
65
+ hashesByComponent
66
+ );
67
+ collectClientEntrypointHashes(
68
+ graph,
69
+ internals.discoveredScripts,
70
+ internals.pagesByScriptId,
71
+ hashesByComponent
72
+ );
73
+ for (const [component, clientHashes] of hashesByComponent) {
74
+ const hasher = crypto.createHash("sha256");
75
+ hasher.update(baseHashes.get(component) ?? "");
76
+ for (const hash of clientHashes.sort()) {
77
+ hasher.update("\n");
78
+ hasher.update(hash);
79
+ }
80
+ baseHashes.set(component, hasher.digest("hex"));
81
+ }
82
+ }
83
+ function collectContentEntryHashes(graph, root) {
84
+ const entryHashes = /* @__PURE__ */ new Map();
85
+ for (const id of graph.getModuleIds()) {
86
+ if (!hasContentFlag(id, PROPAGATED_ASSET_FLAG)) continue;
87
+ const renderModuleId = removeQueryString(id);
88
+ const key = rootRelativePath(root, renderModuleId, false);
89
+ const deps = collectTransitiveDeps(graph, renderModuleId);
90
+ entryHashes.set(key, hashModules(graph, deps));
91
+ }
92
+ return entryHashes;
93
+ }
94
+ function pageContainsServerIsland(graph, ids) {
95
+ for (const id of ids) {
96
+ const serverComponents = graph.getModuleInfo(id)?.meta?.astro?.serverComponents;
97
+ if (serverComponents?.length) return true;
98
+ }
99
+ return false;
100
+ }
101
+ function pluginIncremental(internals, root) {
102
+ return {
103
+ name: "@astro/plugin-incremental",
104
+ applyToEnvironment(environment) {
105
+ return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client;
106
+ },
107
+ generateBundle() {
108
+ if (this.environment?.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
109
+ foldClientDependencies(this, internals);
110
+ return;
111
+ }
112
+ const hashes = /* @__PURE__ */ new Map();
113
+ const serverIslandComponents = /* @__PURE__ */ new Set();
114
+ for (const id of this.getModuleIds()) {
115
+ const info = this.getModuleInfo(id);
116
+ if (!info) continue;
117
+ if (!moduleIsTopLevelPage(info)) continue;
118
+ const pageData = getPageDataByViteID(internals, info.id);
119
+ if (!pageData) continue;
120
+ const deps = collectTransitiveDeps(this, info.id);
121
+ hashes.set(pageData.component, hashModules(this, deps));
122
+ if (pageContainsServerIsland(this, deps)) {
123
+ serverIslandComponents.add(pageData.component);
124
+ }
125
+ }
126
+ internals.pageDependencyHashes = hashes;
127
+ internals.contentEntryRenderHashes = collectContentEntryHashes(this, root);
128
+ internals.serverIslandPageComponents = serverIslandComponents;
129
+ }
130
+ };
131
+ }
132
+ export {
133
+ pluginIncremental
134
+ };
@@ -38,6 +38,8 @@ export interface StaticBuildOptions {
38
38
  pageNames: string[];
39
39
  viteConfig: InlineConfig;
40
40
  key: Promise<CryptoKey>;
41
+ /** Set by `astro build --force` to rebuild every page and ignore the incremental cache. */
42
+ force: boolean;
41
43
  }
42
44
  type ImportComponentInstance = () => Promise<ComponentInstance>;
43
45
  export interface SinglePageBuiltModule {
@@ -393,7 +393,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
393
393
  }, z.core.$strip>]>>>>>;
394
394
  validateSecrets: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
395
395
  }, z.core.$strict>>>;
396
- session: z.ZodOptional<z.ZodObject<{
396
+ session: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
397
397
  driver: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
398
398
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
399
399
  entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
@@ -414,7 +414,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
414
414
  name: string;
415
415
  }, string>>]>>;
416
416
  ttl: z.ZodOptional<z.ZodNumber>;
417
- }, z.core.$strip>>;
417
+ }, z.core.$strip>]>>;
418
418
  prerenderConflictBehavior: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
419
419
  error: "error";
420
420
  ignore: "ignore";
@@ -484,6 +484,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
484
484
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
485
485
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
486
486
  chromeDevtoolsWorkspace: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
487
+ incrementalBuild: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
487
488
  svgOptimizer: z.ZodOptional<z.ZodObject<{
488
489
  name: z.ZodString;
489
490
  optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
@@ -276,6 +276,7 @@ const AstroConfigSchema = z.object({
276
276
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
277
277
  contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
278
278
  chromeDevtoolsWorkspace: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.chromeDevtoolsWorkspace),
279
+ incrementalBuild: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.incrementalBuild),
279
280
  svgOptimizer: SvgOptimizerSchema.optional(),
280
281
  collectionStorage: z.union([
281
282
  z.literal("single-file"),
@@ -62,6 +62,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
62
62
  clientPrerender: false;
63
63
  contentIntellisense: false;
64
64
  chromeDevtoolsWorkspace: false;
65
+ incrementalBuild: false;
65
66
  collectionStorage: "single-file";
66
67
  };
67
68
  };
@@ -57,6 +57,7 @@ const ASTRO_CONFIG_DEFAULTS = {
57
57
  clientPrerender: false,
58
58
  contentIntellisense: false,
59
59
  chromeDevtoolsWorkspace: false,
60
+ incrementalBuild: false,
60
61
  collectionStorage: "single-file"
61
62
  }
62
63
  };
@@ -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,6 +436,7 @@ 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>>;
@@ -630,6 +631,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
630
631
  clientPrerender: boolean;
631
632
  contentIntellisense: boolean;
632
633
  chromeDevtoolsWorkspace: boolean;
634
+ incrementalBuild: boolean;
633
635
  collectionStorage: "single-file" | "chunked" | {
634
636
  type: "chunked";
635
637
  chunkSize: number;
@@ -693,7 +695,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
693
695
  domains?: Record<string, string> | undefined;
694
696
  fallback?: Record<string, string> | undefined;
695
697
  } | undefined;
696
- session?: {
698
+ session?: false | {
697
699
  driver?: string | {
698
700
  entrypoint: string | URL;
699
701
  config?: Record<string, any> | undefined;
@@ -896,6 +898,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
896
898
  clientPrerender: boolean;
897
899
  contentIntellisense: boolean;
898
900
  chromeDevtoolsWorkspace: boolean;
901
+ incrementalBuild: boolean;
899
902
  collectionStorage: "single-file" | "chunked" | {
900
903
  type: "chunked";
901
904
  chunkSize: number;
@@ -959,7 +962,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
959
962
  domains?: Record<string, string> | undefined;
960
963
  fallback?: Record<string, string> | undefined;
961
964
  } | undefined;
962
- session?: {
965
+ session?: false | {
963
966
  driver?: string | {
964
967
  entrypoint: string | URL;
965
968
  config?: Record<string, any> | undefined;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.1.6";
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(),
@@ -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.6";
29
+ const currentVersion = "7.2.0";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -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.6"}`
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>]>;