astro 2.10.7 → 2.10.8

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/client-base.d.ts CHANGED
@@ -48,7 +48,9 @@ declare module 'astro:assets' {
48
48
  * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
49
49
  */
50
50
  getImage: (
51
- options: import('./dist/assets/types.js').ImageTransform
51
+ options:
52
+ | import('./dist/assets/types.js').ImageTransform
53
+ | import('./dist/assets/types.js').UnresolvedImageTransform
52
54
  ) => Promise<import('./dist/assets/types.js').GetImageResult>;
53
55
  getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
54
56
  Image: typeof import('./components/Image.astro').default;
@@ -74,9 +74,9 @@ const html = renderToHtml(tokens, {
74
74
  // Handle code wrapping
75
75
  // if wrap=null, do nothing.
76
76
  if (wrap === false) {
77
- style += '; overflow-x: auto;"';
77
+ style += '; overflow-x: auto;';
78
78
  } else if (wrap === true) {
79
- style += '; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"';
79
+ style += '; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;';
80
80
  }
81
81
  return `<${tag} class="${className}" style="${style}" tabindex="0">${children}</${tag}>`;
82
82
  },
@@ -8,10 +8,9 @@ import type { AddressInfo } from 'node:net';
8
8
  import type * as rollup from 'rollup';
9
9
  import type { TsConfigJson } from 'tsconfig-resolver';
10
10
  import type * as vite from 'vite';
11
- import type { z } from 'zod';
12
11
  import type { SerializedSSRManifest } from '../core/app/types';
13
12
  import type { PageBuildData } from '../core/build/types';
14
- import type { AstroConfigSchema } from '../core/config';
13
+ import type { AstroConfigType } from '../core/config';
15
14
  import type { AstroTimer } from '../core/config/timer';
16
15
  import type { AstroCookies } from '../core/cookies';
17
16
  import type { LogOptions, LoggerLevel } from '../core/logger/core';
@@ -99,7 +98,7 @@ export interface CLIFlags {
99
98
  *
100
99
  * [Astro reference](https://docs.astro.build/reference/api-reference/#astro-global)
101
100
  */
102
- export interface AstroGlobal<Props extends Record<string, any> = Record<string, any>> extends AstroGlobalPartial, AstroSharedContext<Props> {
101
+ export interface AstroGlobal<Props extends Record<string, any> = Record<string, any>, Self = AstroComponentFactory> extends AstroGlobalPartial, AstroSharedContext<Props> {
103
102
  /**
104
103
  * A full URL object of the request URL.
105
104
  * Equivalent to: `new URL(Astro.request.url)`
@@ -175,7 +174,7 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
175
174
  *
176
175
  * [Astro reference](https://docs.astro.build/en/guides/api-reference/#astroself)
177
176
  */
178
- self: AstroComponentFactory;
177
+ self: Self;
179
178
  /** Utility functions for modifying an Astro component’s slotted children
180
179
  *
181
180
  * [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroslots)
@@ -630,6 +629,10 @@ export interface AstroUserConfig {
630
629
  * - `file` - The `Astro.url.pathname` will include `.html`; ie `/foo.html`.
631
630
  *
632
631
  * This means that when you create relative URLs using `new URL('./relative', Astro.url)`, you will get consistent behavior between dev and build.
632
+ *
633
+ * To prevent inconsistencies with trailing slash behaviour in dev, you can restrict the [`trailingSlash` option](#trailingslash) to `'always'` or `'never'` depending on your build format:
634
+ * - `directory` - Set `trailingSlash: 'always'`
635
+ * - `file` - Set `trailingSlash: 'never'`
633
636
  */
634
637
  format?: 'file' | 'directory';
635
638
  /**
@@ -1249,7 +1252,7 @@ export interface ResolvedInjectedRoute extends InjectedRoute {
1249
1252
  * Resolved Astro Config
1250
1253
  * Config with user settings along with all defaults filled in.
1251
1254
  */
1252
- export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
1255
+ export interface AstroConfig extends AstroConfigType {
1253
1256
  integrations: AstroIntegration[];
1254
1257
  }
1255
1258
  export interface AstroInlineConfig extends AstroUserConfig, AstroInlineOnlyConfig {
@@ -1,7 +1,7 @@
1
1
  import type { AstroSettings } from '../@types/astro.js';
2
2
  import { type ImageService } from './services/service.js';
3
- import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js';
3
+ import type { GetImageResult, ImageMetadata, ImageTransform, UnresolvedImageTransform } from './types.js';
4
4
  export declare function injectImageEndpoint(settings: AstroSettings): AstroSettings;
5
5
  export declare function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata;
6
6
  export declare function getConfiguredImageService(): Promise<ImageService>;
7
- export declare function getImage(options: ImageTransform, serviceConfig: Record<string, any>): Promise<GetImageResult>;
7
+ export declare function getImage(options: ImageTransform | UnresolvedImageTransform, serviceConfig: Record<string, any>): Promise<GetImageResult>;
@@ -37,13 +37,17 @@ async function getImage(options, serviceConfig) {
37
37
  });
38
38
  }
39
39
  const service = await getConfiguredImageService();
40
- const validatedOptions = service.validateOptions ? await service.validateOptions(options, serviceConfig) : options;
40
+ const resolvedOptions = {
41
+ ...options,
42
+ src: typeof options.src === "object" && "then" in options.src ? (await options.src).default : options.src
43
+ };
44
+ const validatedOptions = service.validateOptions ? await service.validateOptions(resolvedOptions, serviceConfig) : resolvedOptions;
41
45
  let imageURL = await service.getURL(validatedOptions, serviceConfig);
42
46
  if (isLocalService(service) && globalThis.astroAsset.addStaticImage) {
43
47
  imageURL = globalThis.astroAsset.addStaticImage(validatedOptions);
44
48
  }
45
49
  return {
46
- rawOptions: options,
50
+ rawOptions: resolvedOptions,
47
51
  options: validatedOptions,
48
52
  src: imageURL,
49
53
  attributes: service.getHTMLAttributes !== void 0 ? service.getHTMLAttributes(validatedOptions, serviceConfig) : {}
@@ -24,6 +24,11 @@ export interface ImageMetadata {
24
24
  format: ImageInputFormat;
25
25
  orientation?: number;
26
26
  }
27
+ export type UnresolvedImageTransform = Omit<ImageTransform, 'src'> & {
28
+ src: Promise<{
29
+ default: ImageMetadata;
30
+ }>;
31
+ };
27
32
  /**
28
33
  * Options accepted by the image transformation service.
29
34
  */
@@ -89,7 +94,9 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
89
94
  * <Image src={myImage} alt="..."></Image>
90
95
  * ```
91
96
  */
92
- src: ImageMetadata;
97
+ src: ImageMetadata | Promise<{
98
+ default: ImageMetadata;
99
+ }>;
93
100
  /**
94
101
  * Desired output format for the image. Defaults to `webp`.
95
102
  *
@@ -528,6 +528,15 @@ async function getInstallIntegrationsCommand({
528
528
  return null;
529
529
  }
530
530
  }
531
+ const INHERITED_FLAGS = /* @__PURE__ */ new Set([
532
+ "P",
533
+ "save-prod",
534
+ "D",
535
+ "save-dev",
536
+ "E",
537
+ "save-exact",
538
+ "no-save"
539
+ ]);
531
540
  async function tryToInstallIntegrations({
532
541
  integrations,
533
542
  cwd,
@@ -535,12 +544,22 @@ async function tryToInstallIntegrations({
535
544
  logging
536
545
  }) {
537
546
  const installCommand = await getInstallIntegrationsCommand({ integrations, cwd });
547
+ const inheritedFlags = Object.entries(flags).map(([flag]) => {
548
+ if (flag == "_")
549
+ return;
550
+ if (INHERITED_FLAGS.has(flag)) {
551
+ if (flag.length === 1)
552
+ return `-${flag}`;
553
+ return `--${flag}`;
554
+ }
555
+ }).filter(Boolean).flat();
538
556
  if (installCommand === null) {
539
557
  return 0 /* none */;
540
558
  } else {
541
559
  const coloredOutput = `${bold(installCommand.pm)} ${installCommand.command}${[
542
560
  "",
543
- ...installCommand.flags
561
+ ...installCommand.flags,
562
+ ...inheritedFlags
544
563
  ].join(" ")} ${cyan(installCommand.dependencies.join(" "))}`;
545
564
  const message = `
546
565
  ${boxen(coloredOutput, {
@@ -564,14 +583,20 @@ ${message}`
564
583
  try {
565
584
  await execa(
566
585
  installCommand.pm,
567
- [installCommand.command, ...installCommand.flags, ...installCommand.dependencies],
586
+ [
587
+ installCommand.command,
588
+ ...installCommand.flags,
589
+ ...inheritedFlags,
590
+ ...installCommand.dependencies
591
+ ],
568
592
  { cwd }
569
593
  );
570
594
  spinner.succeed();
571
595
  return 1 /* updated */;
572
596
  } catch (err) {
573
- debug("add", "Error installing dependencies", err);
574
597
  spinner.fail();
598
+ debug("add", "Error installing dependencies", err);
599
+ console.error("\n", err.stdout, "\n");
575
600
  return 3 /* failure */;
576
601
  }
577
602
  } else {
@@ -5,7 +5,8 @@ import { IncomingMessage } from 'node:http';
5
5
  import { App, type MatchOptions } from './index.js';
6
6
  declare class NodeIncomingMessage extends IncomingMessage {
7
7
  /**
8
- * The read-only body property of the Request interface contains a ReadableStream with the body contents that have been added to the request.
8
+ * Allow the request body to be explicitly overridden. For example, this
9
+ * is used by the Express JSON middleware.
9
10
  */
10
11
  body?: unknown;
11
12
  }
@@ -4,71 +4,87 @@ import { TLSSocket } from "node:tls";
4
4
  import { deserializeManifest } from "./common.js";
5
5
  import { App } from "./index.js";
6
6
  const clientAddressSymbol = Symbol.for("astro.clientAddress");
7
- function createRequestFromNodeRequest(req, body) {
7
+ function createRequestFromNodeRequest(req, options) {
8
8
  var _a;
9
9
  const protocol = req.socket instanceof TLSSocket || req.headers["x-forwarded-proto"] === "https" ? "https" : "http";
10
10
  const hostname = req.headers.host || req.headers[":authority"];
11
11
  const url = `${protocol}://${hostname}${req.url}`;
12
- const rawHeaders = req.headers;
13
- const entries = Object.entries(rawHeaders);
12
+ const headers = makeRequestHeaders(req);
14
13
  const method = req.method || "GET";
14
+ let bodyProps = {};
15
+ const bodyAllowed = method !== "HEAD" && method !== "GET" && !(options == null ? void 0 : options.emptyBody);
16
+ if (bodyAllowed) {
17
+ bodyProps = makeRequestBody(req);
18
+ }
15
19
  const request = new Request(url, {
16
20
  method,
17
- headers: new Headers(entries),
18
- body: ["HEAD", "GET"].includes(method) ? null : body
21
+ headers,
22
+ ...bodyProps
19
23
  });
20
24
  if ((_a = req.socket) == null ? void 0 : _a.remoteAddress) {
21
25
  Reflect.set(request, clientAddressSymbol, req.socket.remoteAddress);
22
26
  }
23
27
  return request;
24
28
  }
25
- class NodeIncomingMessage extends IncomingMessage {
26
- }
27
- class NodeApp extends App {
28
- match(req, opts = {}) {
29
- return super.match(req instanceof Request ? req : createRequestFromNodeRequest(req), opts);
29
+ function makeRequestHeaders(req) {
30
+ const headers = new Headers();
31
+ for (const [name, value] of Object.entries(req.headers)) {
32
+ if (value === void 0) {
33
+ continue;
34
+ }
35
+ if (Array.isArray(value)) {
36
+ for (const item of value) {
37
+ headers.append(name, item);
38
+ }
39
+ } else {
40
+ headers.append(name, value);
41
+ }
30
42
  }
31
- render(req, routeData, locals) {
43
+ return headers;
44
+ }
45
+ function makeRequestBody(req) {
46
+ if (req.body !== void 0) {
32
47
  if (typeof req.body === "string" && req.body.length > 0) {
33
- return super.render(
34
- req instanceof Request ? req : createRequestFromNodeRequest(req, Buffer.from(req.body)),
35
- routeData,
36
- locals
37
- );
48
+ return { body: Buffer.from(req.body) };
38
49
  }
39
50
  if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
40
- return super.render(
41
- req instanceof Request ? req : createRequestFromNodeRequest(req, Buffer.from(JSON.stringify(req.body))),
42
- routeData,
43
- locals
44
- );
51
+ return { body: Buffer.from(JSON.stringify(req.body)) };
45
52
  }
46
- if ("on" in req) {
47
- let body = Buffer.from([]);
48
- let reqBodyComplete = new Promise((resolve, reject) => {
49
- req.on("data", (d) => {
50
- body = Buffer.concat([body, d]);
51
- });
52
- req.on("end", () => {
53
- resolve(body);
54
- });
55
- req.on("error", (err) => {
56
- reject(err);
57
- });
58
- });
59
- return reqBodyComplete.then(() => {
60
- return super.render(
61
- req instanceof Request ? req : createRequestFromNodeRequest(req, body),
62
- routeData,
63
- locals
64
- );
53
+ if (typeof req.body === "object" && req.body !== null && typeof req.body[Symbol.asyncIterator] !== "undefined") {
54
+ return asyncIterableToBodyProps(req.body);
55
+ }
56
+ }
57
+ return asyncIterableToBodyProps(req);
58
+ }
59
+ function asyncIterableToBodyProps(iterable) {
60
+ return {
61
+ // Node uses undici for the Request implementation. Undici accepts
62
+ // a non-standard async iterable for the body.
63
+ // @ts-expect-error
64
+ body: iterable,
65
+ // The duplex property is required when using a ReadableStream or async
66
+ // iterable for the body. The type definitions do not include the duplex
67
+ // property because they are not up-to-date.
68
+ // @ts-expect-error
69
+ duplex: "half"
70
+ };
71
+ }
72
+ class NodeIncomingMessage extends IncomingMessage {
73
+ }
74
+ class NodeApp extends App {
75
+ match(req, opts = {}) {
76
+ if (!(req instanceof Request)) {
77
+ req = createRequestFromNodeRequest(req, {
78
+ emptyBody: true
65
79
  });
66
80
  }
67
- return super.render(
68
- req instanceof Request ? req : createRequestFromNodeRequest(req),
69
- routeData,
70
- locals
71
- );
81
+ return super.match(req, opts);
82
+ }
83
+ render(req, routeData, locals) {
84
+ if (!(req instanceof Request)) {
85
+ req = createRequestFromNodeRequest(req);
86
+ }
87
+ return super.render(req, routeData, locals);
72
88
  }
73
89
  }
74
90
  async function loadManifest(rootFolder) {
@@ -1,6 +1,6 @@
1
1
  export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js';
2
2
  export { createNodeLogging } from './logging.js';
3
3
  export { mergeConfig } from './merge.js';
4
- export type { AstroConfigSchema } from './schema';
4
+ export type { AstroConfigType } from './schema';
5
5
  export { createSettings } from './settings.js';
6
6
  export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js';
@@ -329,6 +329,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
329
329
  } | undefined;
330
330
  legacy?: {} | undefined;
331
331
  }>;
332
+ export type AstroConfigType = z.infer<typeof AstroConfigSchema>;
332
333
  export declare function createRelativeSchema(cmd: string, fileProtocolRoot: string): z.ZodEffects<z.ZodObject<{
333
334
  output: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"server">, z.ZodLiteral<"hybrid">]>>>;
334
335
  redirects: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodObject<{
@@ -1,4 +1,3 @@
1
- import { deepmerge } from "deepmerge-ts";
2
1
  import { existsSync } from "node:fs";
3
2
  import { join } from "node:path";
4
3
  import * as tsr from "tsconfig-resolver";
@@ -72,7 +71,23 @@ function updateTSConfigForFramework(target, framework) {
72
71
  if (!presets.has(framework)) {
73
72
  return target;
74
73
  }
75
- return deepmerge(target, presets.get(framework));
74
+ return deepMergeObjects(target, presets.get(framework));
75
+ }
76
+ function deepMergeObjects(a, b) {
77
+ const merged = { ...a };
78
+ for (const key in b) {
79
+ const value = b[key];
80
+ if (a[key] == null) {
81
+ merged[key] = value;
82
+ continue;
83
+ }
84
+ if (typeof a[key] === "object" && typeof value === "object") {
85
+ merged[key] = deepMergeObjects(a[key], value);
86
+ continue;
87
+ }
88
+ merged[key] = value;
89
+ }
90
+ return merged;
76
91
  }
77
92
  export {
78
93
  defaultTSConfig,
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "2.10.7";
1
+ const ASTRO_VERSION = "2.10.8";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -23,7 +23,7 @@ async function dev(inlineConfig) {
23
23
  base: restart.container.settings.config.base
24
24
  })
25
25
  );
26
- const currentVersion = "2.10.7";
26
+ const currentVersion = "2.10.8";
27
27
  if (currentVersion.includes("-")) {
28
28
  warn(logging, null, msg.prerelease({ currentVersion }));
29
29
  }
@@ -47,7 +47,7 @@ function serverStart({
47
47
  base,
48
48
  isRestart = false
49
49
  }) {
50
- const version = "2.10.7";
50
+ const version = "2.10.8";
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.10.7"}`
236
+ `v${"2.10.8"}`
237
237
  )} ${headline}`
238
238
  );
239
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "2.10.7",
3
+ "version": "2.10.8",
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",
@@ -124,7 +124,6 @@
124
124
  "common-ancestor-path": "^1.0.1",
125
125
  "cookie": "^0.5.0",
126
126
  "debug": "^4.3.4",
127
- "deepmerge-ts": "^4.3.0",
128
127
  "devalue": "^4.3.2",
129
128
  "diff": "^5.1.0",
130
129
  "es-module-lexer": "^1.3.0",