astro 2.6.1 → 2.6.3

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.
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import * as colors from "kleur/colors";
3
3
  import yargs from "yargs-parser";
4
- import { z } from "zod";
4
+ import { ZodError } from "zod";
5
5
  import {
6
6
  createSettings,
7
7
  openConfig,
@@ -69,15 +69,19 @@ function resolveCommand(flags) {
69
69
  }
70
70
  return "help";
71
71
  }
72
- async function handleConfigError(e, { cwd, flags, logging }) {
72
+ async function handleConfigError(e, { cmd, cwd, flags, logging }) {
73
73
  const path = await resolveConfigPath({ cwd, flags, fs });
74
- if (e instanceof Error) {
75
- if (path) {
76
- error(logging, "astro", `Unable to load ${colors.bold(path)}
74
+ error(logging, "astro", `Unable to load ${path ? colors.bold(path) : "your Astro config"}
77
75
  `);
78
- }
76
+ if (e instanceof ZodError) {
77
+ console.error(formatConfigErrorMessage(e) + "\n");
78
+ } else if (e instanceof Error) {
79
79
  console.error(formatErrorMessage(collectErrorMetadata(e)) + "\n");
80
80
  }
81
+ const telemetryPromise = telemetry.record(eventConfigError({ cmd, err: e, isFatal: true }));
82
+ await telemetryPromise.catch(
83
+ (err2) => debug("telemetry", `record() error: ${err2.message}`)
84
+ );
81
85
  }
82
86
  async function runCommand(cmd, flags) {
83
87
  var _a;
@@ -136,7 +140,7 @@ async function runCommand(cmd, flags) {
136
140
  cmd,
137
141
  logging
138
142
  }).catch(async (e) => {
139
- await handleConfigError(e, { cwd: root, flags, logging });
143
+ await handleConfigError(e, { cmd, cwd: root, flags, logging });
140
144
  return {};
141
145
  });
142
146
  if (!initialAstroConfig)
@@ -155,7 +159,7 @@ async function runCommand(cmd, flags) {
155
159
  logging,
156
160
  telemetry,
157
161
  handleConfigError(e) {
158
- handleConfigError(e, { cwd: root, flags, logging });
162
+ handleConfigError(e, { cmd, cwd: root, flags, logging });
159
163
  info(logging, "astro", "Continuing with previous valid configuration\n");
160
164
  }
161
165
  });
@@ -218,14 +222,9 @@ async function throwAndExit(cmd, err) {
218
222
  console.error(errorMessage);
219
223
  process.exit(1);
220
224
  }
221
- if (err instanceof z.ZodError) {
222
- telemetryPromise = telemetry.record(eventConfigError({ cmd, err, isFatal: true }));
223
- errorMessage = formatConfigErrorMessage(err);
224
- } else {
225
- const errorWithMetadata = collectErrorMetadata(createSafeError(err));
226
- telemetryPromise = telemetry.record(eventError({ cmd, err: errorWithMetadata, isFatal: true }));
227
- errorMessage = formatErrorMessage(errorWithMetadata);
228
- }
225
+ const errorWithMetadata = collectErrorMetadata(createSafeError(err));
226
+ telemetryPromise = telemetry.record(eventError({ cmd, err: errorWithMetadata, isFatal: true }));
227
+ errorMessage = formatErrorMessage(errorWithMetadata);
229
228
  setTimeout(exitWithErrorMessage, 400);
230
229
  await telemetryPromise.catch((err2) => debug("telemetry", `record() error: ${err2.message}`)).then(exitWithErrorMessage);
231
230
  }
@@ -60,7 +60,7 @@ function astroContentImportPlugin({
60
60
  const code = escapeViteEnvReferences(`
61
61
  export const id = ${JSON.stringify(id)};
62
62
  export const collection = ${JSON.stringify(collection)};
63
- export const data = ${devalue.uneval(data)};
63
+ export const data = ${stringifyEntryData(data)};
64
64
  export const _internal = {
65
65
  type: 'data',
66
66
  filePath: ${JSON.stringify(_internal.filePath)},
@@ -83,7 +83,7 @@ export const _internal = {
83
83
  export const collection = ${JSON.stringify(collection)};
84
84
  export const slug = ${JSON.stringify(slug)};
85
85
  export const body = ${JSON.stringify(body)};
86
- export const data = ${devalue.uneval(data)};
86
+ export const data = ${stringifyEntryData(data)};
87
87
  export const _internal = {
88
88
  type: 'content',
89
89
  filePath: ${JSON.stringify(_internal.filePath)},
@@ -261,6 +261,28 @@ async function getContentConfigFromGlobal() {
261
261
  }
262
262
  return contentConfig;
263
263
  }
264
+ function stringifyEntryData(data) {
265
+ try {
266
+ return devalue.uneval(data, (value) => {
267
+ if (value instanceof URL) {
268
+ return `new URL(${JSON.stringify(value.href)})`;
269
+ }
270
+ });
271
+ } catch (e) {
272
+ if (e instanceof Error) {
273
+ throw new AstroError({
274
+ ...AstroErrorData.UnsupportedConfigTransformError,
275
+ message: AstroErrorData.UnsupportedConfigTransformError.message(e.message),
276
+ stack: e.stack
277
+ });
278
+ } else {
279
+ throw new AstroError({
280
+ code: 99999,
281
+ message: "Unexpected error processing content collection data."
282
+ });
283
+ }
284
+ }
285
+ }
264
286
  export {
265
287
  astroContentImportPlugin
266
288
  };
@@ -98,7 +98,7 @@ async function getStringifiedLookupMap({
98
98
  for (const filePath of contentGlob) {
99
99
  promises.push(
100
100
  limit(async () => {
101
- var _a, _b, _c;
101
+ var _a, _b, _c, _d, _e;
102
102
  const entryType = getEntryType(filePath, contentPaths, contentEntryExts, dataEntryExts);
103
103
  if (entryType !== "content" && entryType !== "data")
104
104
  return;
@@ -128,10 +128,17 @@ async function getStringifiedLookupMap({
128
128
  fileUrl: pathToFileURL(filePath),
129
129
  contentEntryType
130
130
  });
131
+ if ((_c = (_b = lookupMap[collection]) == null ? void 0 : _b.entries) == null ? void 0 : _c[slug]) {
132
+ throw new AstroError({
133
+ ...AstroErrorData.DuplicateContentEntrySlugError,
134
+ message: AstroErrorData.DuplicateContentEntrySlugError.message(collection, slug),
135
+ hint: slug !== generatedSlug ? `Check the \`slug\` frontmatter property in **${id}**.` : void 0
136
+ });
137
+ }
131
138
  lookupMap[collection] = {
132
139
  type: "content",
133
140
  entries: {
134
- ...(_b = lookupMap[collection]) == null ? void 0 : _b.entries,
141
+ ...(_d = lookupMap[collection]) == null ? void 0 : _d.entries,
135
142
  [slug]: rootRelativePath(root, filePath)
136
143
  }
137
144
  };
@@ -140,7 +147,7 @@ async function getStringifiedLookupMap({
140
147
  lookupMap[collection] = {
141
148
  type: "data",
142
149
  entries: {
143
- ...(_c = lookupMap[collection]) == null ? void 0 : _c.entries,
150
+ ...(_e = lookupMap[collection]) == null ? void 0 : _e.entries,
144
151
  [id]: rootRelativePath(root, filePath)
145
152
  }
146
153
  };
@@ -55,6 +55,12 @@ const OFFICIAL_ADAPTER_TO_IMPORT_MAP = {
55
55
  node: "@astrojs/node",
56
56
  deno: "@astrojs/deno"
57
57
  };
58
+ async function getRegistry() {
59
+ var _a;
60
+ const packageManager = ((_a = await preferredPM(process.cwd())) == null ? void 0 : _a.name) || "npm";
61
+ const { stdout } = await execa(packageManager, ["config", "get", "registry"]);
62
+ return stdout || "https://registry.npmjs.org";
63
+ }
58
64
  async function add(names, { cwd, flags, logging, telemetry }) {
59
65
  var _a;
60
66
  applyPolyfill();
@@ -561,7 +567,8 @@ ${message}`
561
567
  }
562
568
  async function fetchPackageJson(scope, name, tag) {
563
569
  const packageName = `${scope ? `${scope}/` : ""}${name}`;
564
- const res = await fetch(`https://registry.npmjs.org/${packageName}/${tag}`);
570
+ const registry = await getRegistry();
571
+ const res = await fetch(`${registry}/${packageName}/${tag}`);
565
572
  if (res.status === 404) {
566
573
  return new Error();
567
574
  } else {
@@ -20,7 +20,7 @@ import { runHookBuildGenerated } from "../../integrations/index.js";
20
20
  import { isServerLikeOutput } from "../../prerender/utils.js";
21
21
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
22
22
  import { callEndpoint, createAPIContext, throwIfRedirectNotAllowed } from "../endpoint/index.js";
23
- import { AstroError } from "../errors/index.js";
23
+ import { AstroError, AstroErrorData } from "../errors/index.js";
24
24
  import { debug, info } from "../logger/core.js";
25
25
  import { callMiddleware } from "../middleware/callMiddleware.js";
26
26
  import {
@@ -221,7 +221,16 @@ async function getPathsForRoute(pageData, mod, opts, builtPaths) {
221
221
  throw err;
222
222
  });
223
223
  opts.routeCache.set(route, result);
224
- paths = result.staticPaths.map((staticPath) => staticPath.params && route.generate(staticPath.params)).filter((staticPath) => {
224
+ paths = result.staticPaths.map((staticPath) => {
225
+ try {
226
+ return route.generate(staticPath.params);
227
+ } catch (e) {
228
+ if (e instanceof TypeError) {
229
+ throw getInvalidRouteSegmentError(e, route, staticPath);
230
+ }
231
+ throw e;
232
+ }
233
+ }).filter((staticPath) => {
225
234
  if (!builtPaths.has(removeTrailingForwardSlash(staticPath))) {
226
235
  return true;
227
236
  }
@@ -234,6 +243,33 @@ async function getPathsForRoute(pageData, mod, opts, builtPaths) {
234
243
  }
235
244
  return paths;
236
245
  }
246
+ function getInvalidRouteSegmentError(e, route, staticPath) {
247
+ var _a, _b;
248
+ const invalidParam = (_a = e.message.match(/^Expected "([^"]+)"/)) == null ? void 0 : _a[1];
249
+ const received = invalidParam ? staticPath.params[invalidParam] : void 0;
250
+ let hint = "Learn about dynamic routes at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes";
251
+ if (invalidParam && typeof received === "string") {
252
+ const matchingSegment = (_b = route.segments.find(
253
+ (segment) => {
254
+ var _a2;
255
+ return ((_a2 = segment[0]) == null ? void 0 : _a2.content) === invalidParam;
256
+ }
257
+ )) == null ? void 0 : _b[0];
258
+ const mightBeMissingSpread = (matchingSegment == null ? void 0 : matchingSegment.dynamic) && !(matchingSegment == null ? void 0 : matchingSegment.spread);
259
+ if (mightBeMissingSpread) {
260
+ hint = `If the param contains slashes, try using a rest parameter: **[...${invalidParam}]**. Learn more at https://docs.astro.build/en/core-concepts/routing/#dynamic-routes`;
261
+ }
262
+ }
263
+ return new AstroError({
264
+ ...AstroErrorData.InvalidDynamicRoute,
265
+ message: invalidParam ? AstroErrorData.InvalidDynamicRoute.message(
266
+ route.route,
267
+ JSON.stringify(invalidParam),
268
+ JSON.stringify(received)
269
+ ) : `Generated path for ${route.route} is invalid.`,
270
+ hint
271
+ });
272
+ }
237
273
  function shouldAppendForwardSlash(trailingSlash, buildFormat) {
238
274
  switch (trailingSlash) {
239
275
  case "always":
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "2.6.1";
1
+ const ASTRO_VERSION = "2.6.3";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -53,7 +53,7 @@ async function dev(settings, options) {
53
53
  isRestart: options.isRestart
54
54
  })
55
55
  );
56
- const currentVersion = "2.6.1";
56
+ const currentVersion = "2.6.3";
57
57
  if (currentVersion.includes("-")) {
58
58
  warn(options.logging, null, msg.prerelease({ currentVersion }));
59
59
  }
@@ -115,7 +115,7 @@ function isRedirect(statusCode) {
115
115
  return statusCode >= 300 && statusCode < 400;
116
116
  }
117
117
  function throwIfRedirectNotAllowed(response, config) {
118
- if (!isServerLikeOutput(config) && isRedirect(response.status)) {
118
+ if (!isServerLikeOutput(config) && isRedirect(response.status) && !config.experimental.redirects) {
119
119
  throw new AstroError(AstroErrorData.StaticRedirectNotAvailable);
120
120
  }
121
121
  }
@@ -655,6 +655,18 @@ export declare const AstroErrorData: {
655
655
  readonly title: "A redirect must be given a location with the `Location` header.";
656
656
  readonly code: 3037;
657
657
  };
658
+ /**
659
+ * @docs
660
+ * @see
661
+ * - [Dynamic routes](https://docs.astro.build/en/core-concepts/routing/#dynamic-routes)
662
+ * @description
663
+ * A dynamic route param is invalid. This is often caused by an `undefined` parameter or a missing [rest parameter](https://docs.astro.build/en/core-concepts/routing/#rest-parameters).
664
+ */
665
+ readonly InvalidDynamicRoute: {
666
+ readonly title: "Invalid dynamic route.";
667
+ readonly code: 3038;
668
+ readonly message: (route: string, invalidParam: string, received: string) => string;
669
+ };
658
670
  /**
659
671
  * @docs
660
672
  * @see
@@ -962,6 +974,29 @@ export declare const AstroErrorData: {
962
974
  readonly message: (entryId: string, errorMessage: string) => string;
963
975
  readonly hint: "Ensure your data entry is an object with valid JSON (for `.json` entries) or YAML (for `.yaml` entries).";
964
976
  };
977
+ /**
978
+ * @docs
979
+ * @description
980
+ * Content collection entries must have unique slugs. Duplicates are often caused by the `slug` frontmatter property.
981
+ */
982
+ readonly DuplicateContentEntrySlugError: {
983
+ readonly title: "Duplicate content entry slug.";
984
+ readonly code: 9008;
985
+ readonly message: (collection: string, slug: string) => string;
986
+ };
987
+ /**
988
+ * @docs
989
+ * @see
990
+ * - [devalue library](https://github.com/rich-harris/devalue)
991
+ * @description
992
+ * `transform()` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).
993
+ */
994
+ readonly UnsupportedConfigTransformError: {
995
+ readonly title: "Unsupported transform in content config.";
996
+ readonly code: 9008;
997
+ readonly message: (parseError: string) => string;
998
+ readonly hint: "See the devalue library for all supported types: https://github.com/rich-harris/devalue";
999
+ };
965
1000
  readonly UnknownError: {
966
1001
  readonly title: "Unknown Error.";
967
1002
  readonly code: 99999;
@@ -689,6 +689,18 @@ Expected \`${defaultExpectedValue}\` value but got \`${suffix}\`.`;
689
689
  title: "A redirect must be given a location with the `Location` header.",
690
690
  code: 3037
691
691
  },
692
+ /**
693
+ * @docs
694
+ * @see
695
+ * - [Dynamic routes](https://docs.astro.build/en/core-concepts/routing/#dynamic-routes)
696
+ * @description
697
+ * A dynamic route param is invalid. This is often caused by an `undefined` parameter or a missing [rest parameter](https://docs.astro.build/en/core-concepts/routing/#rest-parameters).
698
+ */
699
+ InvalidDynamicRoute: {
700
+ title: "Invalid dynamic route.",
701
+ code: 3038,
702
+ message: (route, invalidParam, received) => `The ${invalidParam} param for route ${route} is invalid. Received **${received}**.`
703
+ },
692
704
  // No headings here, that way Vite errors are merged with Astro ones in the docs, which makes more sense to users.
693
705
  // Vite Errors - 4xxx
694
706
  /**
@@ -1020,6 +1032,32 @@ Expected \`${defaultExpectedValue}\` value but got \`${suffix}\`.`;
1020
1032
  },
1021
1033
  hint: "Ensure your data entry is an object with valid JSON (for `.json` entries) or YAML (for `.yaml` entries)."
1022
1034
  },
1035
+ /**
1036
+ * @docs
1037
+ * @description
1038
+ * Content collection entries must have unique slugs. Duplicates are often caused by the `slug` frontmatter property.
1039
+ */
1040
+ DuplicateContentEntrySlugError: {
1041
+ title: "Duplicate content entry slug.",
1042
+ code: 9008,
1043
+ message: (collection, slug) => {
1044
+ return `**${collection}** contains multiple entries with the same slug: \`${slug}\`. Slugs must be unique.`;
1045
+ }
1046
+ },
1047
+ /**
1048
+ * @docs
1049
+ * @see
1050
+ * - [devalue library](https://github.com/rich-harris/devalue)
1051
+ * @description
1052
+ * `transform()` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).
1053
+ */
1054
+ UnsupportedConfigTransformError: {
1055
+ title: "Unsupported transform in content config.",
1056
+ code: 9008,
1057
+ message: (parseError) => `\`transform()\` functions in your content config must return valid JSON, or data types compatible with the devalue library (including Dates, Maps, and Sets).
1058
+ Full error: ${parseError}`,
1059
+ hint: "See the devalue library for all supported types: https://github.com/rich-harris/devalue"
1060
+ },
1023
1061
  // Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip
1024
1062
  UnknownError: {
1025
1063
  title: "Unknown Error.",
@@ -47,7 +47,7 @@ function serverStart({
47
47
  base,
48
48
  isRestart = false
49
49
  }) {
50
- const version = "2.6.1";
50
+ const version = "2.6.3";
51
51
  const localPrefix = `${dim("\u2503")} Local `;
52
52
  const networkPrefix = `${dim("\u2503")} Network `;
53
53
  const emptyPrefix = " ".repeat(11);
@@ -233,7 +233,7 @@ function printHelp({
233
233
  message.push(
234
234
  linebreak(),
235
235
  ` ${bgGreen(black(` ${commandName} `))} ${green(
236
- `v${"2.6.1"}`
236
+ `v${"2.6.3"}`
237
237
  )} ${headline}`
238
238
  );
239
239
  }
@@ -13,6 +13,16 @@ async function check(Component, props, { default: children = null, ...slotted }
13
13
  const result = await Component({ ...props, ...slots, children });
14
14
  return result[AstroJSX];
15
15
  } catch (e) {
16
+ const error = e;
17
+ if (Component[Symbol.for("mdx-component")]) {
18
+ throw createFormattedError({
19
+ message: error.message,
20
+ title: error.name,
21
+ hint: `This issue often occurs when your MDX component encounters runtime errors.`,
22
+ name: error.name,
23
+ stack: error.stack
24
+ });
25
+ }
16
26
  }
17
27
  return false;
18
28
  }
@@ -26,6 +36,13 @@ async function renderToStaticMarkup(Component, props = {}, { default: children =
26
36
  const html = await renderJSX(result, jsx(Component, { ...props, ...slots, children }));
27
37
  return { html };
28
38
  }
39
+ function createFormattedError({ message, name, stack, hint }) {
40
+ const error = new Error(message);
41
+ error.name = name;
42
+ error.stack = stack;
43
+ error.hint = hint;
44
+ return error;
45
+ }
29
46
  var server_default = {
30
47
  check,
31
48
  renderToStaticMarkup
@@ -1,13 +1,14 @@
1
1
  import type { AstroSettings, RouteData } from '../@types/astro';
2
- import { type DevelopmentEnvironment } from '../core/render/dev/index.js';
2
+ import { type ComponentPreload, type DevelopmentEnvironment } from '../core/render/dev/index.js';
3
3
  type GetSortedPreloadedMatchesParams = {
4
4
  env: DevelopmentEnvironment;
5
5
  matches: RouteData[];
6
6
  settings: AstroSettings;
7
7
  };
8
- export declare function getSortedPreloadedMatches({ env, matches, settings, }: GetSortedPreloadedMatchesParams): Promise<{
9
- readonly preloadedComponent: import("../core/render/dev/index.js").ComponentPreload;
10
- readonly route: RouteData;
11
- readonly filePath: URL;
12
- }[]>;
8
+ export declare function getSortedPreloadedMatches({ env, matches, settings, }: GetSortedPreloadedMatchesParams): Promise<PreloadAndSetPrerenderStatusResult[]>;
9
+ type PreloadAndSetPrerenderStatusResult = {
10
+ filePath: URL;
11
+ route: RouteData;
12
+ preloadedComponent: ComponentPreload;
13
+ };
13
14
  export {};
@@ -1,4 +1,7 @@
1
- import { preload } from "../core/render/dev/index.js";
1
+ import { RedirectComponentInstance, routeIsRedirect } from "../core/redirects/index.js";
2
+ import {
3
+ preload
4
+ } from "../core/render/dev/index.js";
2
5
  import { getPrerenderStatus } from "./metadata.js";
3
6
  async function getSortedPreloadedMatches({
4
7
  env,
@@ -19,6 +22,14 @@ async function preloadAndSetPrerenderStatus({
19
22
  const preloaded = await Promise.all(
20
23
  matches.map(async (route) => {
21
24
  const filePath = new URL(`./${route.component}`, settings.config.root);
25
+ if (routeIsRedirect(route)) {
26
+ const preloadedComponent2 = [[], RedirectComponentInstance];
27
+ return {
28
+ preloadedComponent: preloadedComponent2,
29
+ route,
30
+ filePath
31
+ };
32
+ }
22
33
  const preloadedComponent = await preload({ env, filePath });
23
34
  const prerenderStatus = getPrerenderStatus({
24
35
  filePath,
@@ -8,7 +8,7 @@ export type { AstroComponentFactory, AstroComponentInstance, ComponentSlots, Ren
8
8
  export declare function mergeSlots(...slotted: unknown[]): Record<string, () => any>;
9
9
  /** @internal Associate JSX components with a specific renderer (see /src/vite-plugin-jsx/tag.ts) */
10
10
  export declare function __astro_tag_component__(Component: unknown, rendererName: string): void;
11
- export declare function spreadAttributes(values: Record<any, any>, _name?: string, { class: scopedClassName }?: {
11
+ export declare function spreadAttributes(values?: Record<any, any>, _name?: string, { class: scopedClassName }?: {
12
12
  class?: string;
13
13
  }): any;
14
14
  export declare function defineStyleVars(defs: Record<any, any> | Record<any, any>[]): any;
@@ -59,7 +59,7 @@ function __astro_tag_component__(Component, rendererName) {
59
59
  writable: false
60
60
  });
61
61
  }
62
- function spreadAttributes(values, _name, { class: scopedClassName } = {}) {
62
+ function spreadAttributes(values = {}, _name, { class: scopedClassName } = {}) {
63
63
  let output = "";
64
64
  if (scopedClassName) {
65
65
  if (typeof values.class !== "undefined") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "2.6.1",
3
+ "version": "2.6.3",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -121,7 +121,7 @@
121
121
  "cookie": "^0.5.0",
122
122
  "debug": "^4.3.4",
123
123
  "deepmerge-ts": "^4.2.2",
124
- "devalue": "^4.2.0",
124
+ "devalue": "^4.3.2",
125
125
  "diff": "^5.1.0",
126
126
  "es-module-lexer": "^1.1.0",
127
127
  "esbuild": "^0.17.18",