astro 5.0.0-alpha.6 → 5.0.0-alpha.7

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 (40) hide show
  1. package/config.d.ts +1 -0
  2. package/dist/actions/runtime/virtual/server.js +10 -2
  3. package/dist/assets/build/generate.js +8 -5
  4. package/dist/assets/endpoint/config.js +21 -5
  5. package/dist/assets/services/service.d.ts +1 -1
  6. package/dist/assets/services/service.js +1 -1
  7. package/dist/assets/vite-plugin-assets.js +1 -1
  8. package/dist/cli/add/index.d.ts +1 -1
  9. package/dist/cli/add/index.js +3 -3
  10. package/dist/cli/create-key/index.d.ts +6 -0
  11. package/dist/cli/create-key/index.js +27 -0
  12. package/dist/cli/index.js +7 -0
  13. package/dist/core/build/generate.js +5 -2
  14. package/dist/core/build/index.js +9 -5
  15. package/dist/core/build/plugins/plugin-manifest.js +2 -1
  16. package/dist/core/build/plugins/plugin-ssr.js +1 -2
  17. package/dist/core/config/schema.d.ts +80 -33
  18. package/dist/core/config/schema.js +5 -3
  19. package/dist/core/constants.js +1 -1
  20. package/dist/core/create-vite.js +1 -1
  21. package/dist/core/dev/dev.js +1 -1
  22. package/dist/core/encryption.d.ts +12 -0
  23. package/dist/core/encryption.js +19 -0
  24. package/dist/core/errors/errors-data.d.ts +16 -3
  25. package/dist/core/errors/errors-data.js +7 -0
  26. package/dist/core/logger/core.d.ts +1 -1
  27. package/dist/core/messages.js +2 -2
  28. package/dist/core/request.d.ts +0 -1
  29. package/dist/core/routing/manifest/create.js +6 -3
  30. package/dist/core/sync/index.js +9 -1
  31. package/dist/integrations/features-validation.d.ts +11 -2
  32. package/dist/integrations/features-validation.js +72 -54
  33. package/dist/integrations/hooks.js +24 -13
  34. package/dist/types/public/config.d.ts +12 -8
  35. package/dist/types/public/integrations.d.ts +27 -25
  36. package/dist/types/public/internal.d.ts +85 -1
  37. package/dist/vite-plugin-astro-server/css.js +9 -6
  38. package/dist/vite-plugin-astro-server/route.js +0 -1
  39. package/package.json +6 -6
  40. package/templates/content/types.d.ts +1 -1
package/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference path='./client.d.ts' />
1
2
  type ViteUserConfig = import('vite').UserConfig;
2
3
  type ViteUserConfigFn = import('vite').UserConfigFn;
3
4
  type AstroUserConfig = import('./dist/types/public/config.js').AstroUserConfig;
@@ -34,7 +34,7 @@ function getFormServerHandler(handler, inputSchema) {
34
34
  });
35
35
  }
36
36
  if (!inputSchema) return await handler(unparsedInput, context);
37
- const baseSchema = unwrapSchemaEffects(inputSchema);
37
+ const baseSchema = unwrapBaseObjectSchema(inputSchema, unparsedInput);
38
38
  const parsed = await inputSchema.safeParseAsync(
39
39
  baseSchema instanceof z.ZodObject ? formDataToObject(unparsedInput, baseSchema) : unparsedInput
40
40
  );
@@ -100,7 +100,7 @@ function handleFormDataGet(key, formData, validator, baseValidator) {
100
100
  }
101
101
  return validator instanceof z.ZodNumber ? Number(value) : value;
102
102
  }
103
- function unwrapSchemaEffects(schema) {
103
+ function unwrapBaseObjectSchema(schema, unparsedInput) {
104
104
  while (schema instanceof z.ZodEffects || schema instanceof z.ZodPipeline) {
105
105
  if (schema instanceof z.ZodEffects) {
106
106
  schema = schema._def.schema;
@@ -109,6 +109,14 @@ function unwrapSchemaEffects(schema) {
109
109
  schema = schema._def.in;
110
110
  }
111
111
  }
112
+ if (schema instanceof z.ZodDiscriminatedUnion) {
113
+ const typeKey = schema._def.discriminator;
114
+ const typeValue = unparsedInput.get(typeKey);
115
+ if (typeof typeValue !== "string") return schema;
116
+ const objSchema = schema._def.optionsMap.get(typeValue);
117
+ if (!objSchema) return schema;
118
+ return objSchema;
119
+ }
112
120
  return schema;
113
121
  }
114
122
  export {
@@ -48,9 +48,9 @@ function getFullImagePath(originalFilePath, env) {
48
48
  return new URL(removeLeadingForwardSlash(originalFilePath), env.serverRoot);
49
49
  }
50
50
  async function generateImagesForPath(originalFilePath, transformsAndPath, env, queue) {
51
- const originalImageData = await loadImage(originalFilePath, env);
51
+ let originalImage;
52
52
  for (const [_, transform] of transformsAndPath.transforms) {
53
- await queue.add(async () => generateImage(originalImageData, transform.finalPath, transform.transform)).catch((e) => {
53
+ await queue.add(async () => generateImage(transform.finalPath, transform.transform)).catch((e) => {
54
54
  throw e;
55
55
  });
56
56
  }
@@ -66,9 +66,9 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env, q
66
66
  } catch {
67
67
  }
68
68
  }
69
- async function generateImage(originalImage, filepath, options) {
69
+ async function generateImage(filepath, options) {
70
70
  const timeStart = performance.now();
71
- const generationData = await generateImageInternal(originalImage, filepath, options);
71
+ const generationData = await generateImageInternal(filepath, options);
72
72
  const timeEnd = performance.now();
73
73
  const timeChange = getTimeStat(timeStart, timeEnd);
74
74
  const timeIncrease = `(+${timeChange})`;
@@ -80,7 +80,7 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env, q
80
80
  );
81
81
  env.count.current++;
82
82
  }
83
- async function generateImageInternal(originalImage, filepath, options) {
83
+ async function generateImageInternal(filepath, options) {
84
84
  const isLocalImage = isESMImportedImage(options.src);
85
85
  const finalFileURL = new URL("." + filepath, env.clientRoot);
86
86
  const cacheFile = basename(filepath) + (isLocalImage ? "" : ".json");
@@ -116,6 +116,9 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env, q
116
116
  const finalFolderURL = new URL("./", finalFileURL);
117
117
  await fs.promises.mkdir(finalFolderURL, { recursive: true });
118
118
  const originalImagePath = isLocalImage ? options.src.src : options.src;
119
+ if (!originalImage) {
120
+ originalImage = await loadImage(originalFilePath, env);
121
+ }
119
122
  let resultData = {
120
123
  data: void 0,
121
124
  expires: originalImage.expires
@@ -1,4 +1,9 @@
1
+ import {
2
+ removeLeadingForwardSlash,
3
+ removeTrailingForwardSlash
4
+ } from "@astrojs/internal-helpers/path";
1
5
  import { resolveInjectedRoute } from "../../core/routing/manifest/create.js";
6
+ import { getPattern } from "../../core/routing/manifest/pattern.js";
2
7
  function injectImageEndpoint(settings, manifest, mode, cwd) {
3
8
  manifest.routes.push(getImageEndpointData(settings, mode, cwd));
4
9
  }
@@ -8,17 +13,28 @@ function ensureImageEndpointRoute(settings, manifest, mode, cwd) {
8
13
  }
9
14
  }
10
15
  function getImageEndpointData(settings, mode, cwd) {
11
- const endpointEntrypoint = settings.config.image.endpoint ?? (mode === "dev" ? "astro/assets/endpoint/node" : "astro/assets/endpoint/generic");
16
+ const endpointEntrypoint = settings.config.image.endpoint.entrypoint === void 0 ? mode === "dev" ? "astro/assets/endpoint/node" : "astro/assets/endpoint/generic" : settings.config.image.endpoint.entrypoint;
17
+ const segments = [
18
+ [
19
+ {
20
+ content: removeTrailingForwardSlash(
21
+ removeLeadingForwardSlash(settings.config.image.endpoint.route)
22
+ ),
23
+ dynamic: false,
24
+ spread: false
25
+ }
26
+ ]
27
+ ];
12
28
  return {
13
29
  type: "endpoint",
14
30
  isIndex: false,
15
- route: "/_image",
16
- pattern: /^\/_image$/,
17
- segments: [[{ content: "_image", dynamic: false, spread: false }]],
31
+ route: settings.config.image.endpoint.route,
32
+ pattern: getPattern(segments, settings.config.base, settings.config.trailingSlash),
33
+ segments,
18
34
  params: [],
19
35
  component: resolveInjectedRoute(endpointEntrypoint, settings.config.root, cwd).component,
20
36
  generate: () => "",
21
- pathname: "/_image",
37
+ pathname: settings.config.image.endpoint.route,
22
38
  prerender: false,
23
39
  fallbackRoutes: []
24
40
  };
@@ -13,7 +13,7 @@ interface SharedServiceProps<T extends Record<string, any> = Record<string, any>
13
13
  /**
14
14
  * Return the URL to the endpoint or URL your images are generated from.
15
15
  *
16
- * For a local service, your service should expose an endpoint handling the image requests, or use Astro's at `/_image`.
16
+ * For a local service, your service should expose an endpoint handling the image requests, or use Astro's which by default, is located at `/_image`.
17
17
  *
18
18
  * For external services, this should point to the URL your images are coming from, for instance, `/_vercel/image`
19
19
  *
@@ -167,7 +167,7 @@ const baseService = {
167
167
  Object.entries(params).forEach(([param, key]) => {
168
168
  options[key] && searchParams.append(param, options[key].toString());
169
169
  });
170
- const imageEndpoint = joinPaths(import.meta.env.BASE_URL, "/_image");
170
+ const imageEndpoint = joinPaths(import.meta.env.BASE_URL, imageConfig.endpoint.route);
171
171
  return `${imageEndpoint}?${searchParams}`;
172
172
  },
173
173
  parseURL(url) {
@@ -72,7 +72,7 @@ function assets({
72
72
  referencedImages: /* @__PURE__ */ new Set()
73
73
  };
74
74
  return [
75
- // Expose the components and different utilities from `astro:assets` and handle serving images from `/_image` in dev
75
+ // Expose the components and different utilities from `astro:assets`
76
76
  {
77
77
  name: "astro:assets",
78
78
  async resolveId(id) {
@@ -10,5 +10,5 @@ interface IntegrationInfo {
10
10
  type: 'integration' | 'adapter';
11
11
  }
12
12
  export declare function add(names: string[], { flags }: AddOptions): Promise<void>;
13
- export declare function setAdapter(mod: ProxifiedModule<any>, adapter: IntegrationInfo): void;
13
+ export declare function setAdapter(mod: ProxifiedModule<any>, adapter: IntegrationInfo, exportName: string): void;
14
14
  export {};
@@ -247,7 +247,7 @@ async function add(names, { flags }) {
247
247
  if (isAdapter(integration)) {
248
248
  const officialExportName = OFFICIAL_ADAPTER_TO_IMPORT_MAP[integration.id];
249
249
  if (officialExportName) {
250
- setAdapter(mod, integration);
250
+ setAdapter(mod, integration, officialExportName);
251
251
  } else {
252
252
  logger.info(
253
253
  "SKIP_FORMAT",
@@ -371,14 +371,14 @@ function addIntegration(mod, integration) {
371
371
  config.integrations.push(builders.functionCall(integrationId));
372
372
  }
373
373
  }
374
- function setAdapter(mod, adapter) {
374
+ function setAdapter(mod, adapter, exportName) {
375
375
  const config = getDefaultExportOptions(mod);
376
376
  const adapterId = toIdent(adapter.id);
377
377
  if (!mod.imports.$items.some((imp) => imp.local === adapterId)) {
378
378
  mod.imports.$append({
379
379
  imported: "default",
380
380
  local: adapterId,
381
- from: adapter.packageName
381
+ from: exportName
382
382
  });
383
383
  }
384
384
  if (!config.output) {
@@ -0,0 +1,6 @@
1
+ import { type Flags } from '../flags.js';
2
+ interface CreateKeyOptions {
3
+ flags: Flags;
4
+ }
5
+ export declare function createKey({ flags }: CreateKeyOptions): Promise<0 | 1>;
6
+ export {};
@@ -0,0 +1,27 @@
1
+ import { createNodeLogger } from "../../core/config/logging.js";
2
+ import { createKey as createCryptoKey, encodeKey } from "../../core/encryption.js";
3
+ import { flagsToAstroInlineConfig } from "../flags.js";
4
+ async function createKey({ flags }) {
5
+ try {
6
+ const inlineConfig = flagsToAstroInlineConfig(flags);
7
+ const logger = createNodeLogger(inlineConfig);
8
+ const keyPromise = createCryptoKey();
9
+ const key = await keyPromise;
10
+ const encoded = await encodeKey(key);
11
+ logger.info(
12
+ "crypto",
13
+ `Generated a key to encrypt props passed to Server islands. To reuse the same key across builds, set this value as ASTRO_KEY in an environment variable on your build server.
14
+
15
+ ASTRO_KEY=${encoded}`
16
+ );
17
+ } catch (err) {
18
+ if (err != null) {
19
+ console.error(err.toString());
20
+ }
21
+ return 1;
22
+ }
23
+ return 0;
24
+ }
25
+ export {
26
+ createKey
27
+ };
package/dist/cli/index.js CHANGED
@@ -12,6 +12,7 @@ async function printAstroHelp() {
12
12
  ["add", "Add an integration."],
13
13
  ["build", "Build your project and write it to disk."],
14
14
  ["check", "Check your project for errors."],
15
+ ["create-key", "Create a cryptography key"],
15
16
  ["db", "Manage your Astro database."],
16
17
  ["dev", "Start the development server."],
17
18
  ["docs", "Open documentation in your web browser."],
@@ -55,6 +56,7 @@ function resolveCommand(flags) {
55
56
  "build",
56
57
  "preview",
57
58
  "check",
59
+ "create-key",
58
60
  "docs",
59
61
  "db",
60
62
  "info",
@@ -81,6 +83,11 @@ async function runCommand(cmd, flags) {
81
83
  await printInfo({ flags });
82
84
  return;
83
85
  }
86
+ case "create-key": {
87
+ const { createKey } = await import("./create-key/index.js");
88
+ const exitCode = await createKey({ flags });
89
+ return process.exit(exitCode);
90
+ }
84
91
  case "docs": {
85
92
  const { docs } = await import("./docs/index.js");
86
93
  await docs({ flags });
@@ -283,7 +283,6 @@ async function generatePath(pathname, pipeline, gopts, route) {
283
283
  route.type
284
284
  );
285
285
  const request = createRequest({
286
- base: config.base,
287
286
  url,
288
287
  headers: new Headers(),
289
288
  logger,
@@ -329,7 +328,11 @@ async function generatePath(pathname, pipeline, gopts, route) {
329
328
  }
330
329
  const outFolder = getOutFolder(pipeline.settings, pathname, route);
331
330
  const outFile = getOutFile(config, outFolder, pathname, route);
332
- route.distURL = outFile;
331
+ if (route.distURL) {
332
+ route.distURL.push(outFile);
333
+ } else {
334
+ route.distURL = [outFile];
335
+ }
333
336
  await fs.promises.mkdir(outFolder, { recursive: true });
334
337
  await fs.promises.writeFile(outFile, body);
335
338
  }
@@ -15,7 +15,7 @@ import { resolveConfig } from "../config/config.js";
15
15
  import { createNodeLogger } from "../config/logging.js";
16
16
  import { createSettings } from "../config/settings.js";
17
17
  import { createVite } from "../create-vite.js";
18
- import { createKey } from "../encryption.js";
18
+ import { createKey, getEnvironmentKey, hasEnvironmentKey } from "../encryption.js";
19
19
  import { AstroError, AstroErrorData } from "../errors/index.js";
20
20
  import { levels, timerMessage } from "../logger/core.js";
21
21
  import { apply as applyPolyfill } from "../polyfill.js";
@@ -137,6 +137,8 @@ class AstroBuilder {
137
137
  "build",
138
138
  green(`\u2713 Completed in ${getTimeStat(this.timer.init, performance.now())}.`)
139
139
  );
140
+ const hasKey = hasEnvironmentKey();
141
+ const keyPromise = hasKey ? getEnvironmentKey() : createKey();
140
142
  const opts = {
141
143
  allPages,
142
144
  settings: this.settings,
@@ -147,9 +149,13 @@ class AstroBuilder {
147
149
  pageNames,
148
150
  teardownCompiler: this.teardownCompiler,
149
151
  viteConfig,
150
- key: createKey()
152
+ key: keyPromise
151
153
  };
152
154
  const { internals, ssrOutputChunkNames, contentFileNames } = await viteBuild(opts);
155
+ const hasServerIslands = this.settings.serverIslandNameMap.size > 0;
156
+ if (hasServerIslands && this.settings.buildOutput !== "server") {
157
+ throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands);
158
+ }
153
159
  await staticBuild(opts, internals, ssrOutputChunkNames, contentFileNames);
154
160
  this.timer.assetsStart = performance.now();
155
161
  Object.keys(assets).map((k) => {
@@ -163,9 +169,7 @@ class AstroBuilder {
163
169
  await runHookBuildDone({
164
170
  settings: this.settings,
165
171
  pages: pageNames,
166
- routes: Object.values(allPages).flat().map((pageData) => pageData.route).concat(
167
- this.settings.config.experimental.serverIslands ? [getServerIslandRouteData(this.settings.config)] : []
168
- ),
172
+ routes: Object.values(allPages).flat().map((pageData) => pageData.route).concat(hasServerIslands ? getServerIslandRouteData(this.settings.config) : []),
169
173
  logging: this.logger,
170
174
  cacheManifest: internals.cacheManifestUsed
171
175
  });
@@ -3,6 +3,7 @@ import glob from "fast-glob";
3
3
  import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
4
4
  import { normalizeTheLocale } from "../../../i18n/index.js";
5
5
  import { toFallbackType, toRoutingStrategy } from "../../../i18n/utils.js";
6
+ import { unwrapSupportKind } from "../../../integrations/features-validation.js";
6
7
  import { runHookBuildSsr } from "../../../integrations/hooks.js";
7
8
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../../vite-plugin-scripts/index.js";
8
9
  import { encodeKey } from "../../encryption.js";
@@ -208,7 +209,7 @@ function buildManifest(opts, internals, staticFiles, encodedKey) {
208
209
  checkOrigin: settings.config.security?.checkOrigin ?? false,
209
210
  serverIslandNameMap: Array.from(settings.serverIslandNameMap),
210
211
  key: encodedKey,
211
- envGetSecretEnabled: (settings.adapter?.supportedAstroFeatures.envGetSecret ?? "unsupported") !== "unsupported"
212
+ envGetSecretEnabled: (unwrapSupportKind(settings.adapter?.supportedAstroFeatures.envGetSecret) ?? "unsupported") !== "unsupported"
212
213
  };
213
214
  }
214
215
  export {
@@ -141,10 +141,9 @@ function generateSSRCode(settings, adapter, middlewareId) {
141
141
  `import * as serverEntrypointModule from '${ADAPTER_VIRTUAL_MODULE_ID}';`,
142
142
  `import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
143
143
  edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`,
144
- settings.config.experimental.serverIslands ? `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';` : ""
144
+ `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';`
145
145
  ];
146
146
  const contents = [
147
- settings.config.experimental.serverIslands ? "" : `const serverIslandMap = new Map()`,
148
147
  edgeMiddleware ? `const middleware = (_, next) => next()` : "",
149
148
  `const _manifest = Object.assign(defaultManifest, {`,
150
149
  ` pageMap,`,