astro 2.3.4 → 2.4.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 (69) hide show
  1. package/client-base.d.ts +6 -0
  2. package/components/Code.astro +46 -21
  3. package/components/shiki-languages.js +172 -2016
  4. package/components/shiki-themes.js +41 -31
  5. package/dist/@types/app.d.js +0 -0
  6. package/dist/@types/astro.d.ts +108 -1
  7. package/dist/assets/internal.d.ts +6 -1
  8. package/dist/assets/internal.js +37 -4
  9. package/dist/content/runtime.js +8 -3
  10. package/dist/content/vite-plugin-content-assets.js +14 -4
  11. package/dist/core/app/index.js +50 -10
  12. package/dist/core/app/types.d.ts +10 -1
  13. package/dist/core/build/generate.js +62 -23
  14. package/dist/core/build/internal.d.ts +10 -4
  15. package/dist/core/build/internal.js +29 -18
  16. package/dist/core/build/page-data.js +2 -2
  17. package/dist/core/build/plugins/plugin-css.d.ts +1 -8
  18. package/dist/core/build/plugins/plugin-css.js +185 -150
  19. package/dist/core/build/plugins/plugin-pages.d.ts +1 -1
  20. package/dist/core/build/plugins/plugin-pages.js +13 -2
  21. package/dist/core/build/plugins/plugin-ssr.d.ts +2 -2
  22. package/dist/core/build/plugins/plugin-ssr.js +14 -5
  23. package/dist/core/build/types.d.ts +15 -6
  24. package/dist/core/compile/compile.js +1 -0
  25. package/dist/core/config/config.js +5 -1
  26. package/dist/core/config/schema.d.ts +40 -0
  27. package/dist/core/config/schema.js +10 -2
  28. package/dist/core/constants.d.ts +1 -0
  29. package/dist/core/constants.js +3 -1
  30. package/dist/core/dev/dev.js +1 -1
  31. package/dist/core/endpoint/dev/index.js +7 -4
  32. package/dist/core/endpoint/index.d.ts +9 -2
  33. package/dist/core/endpoint/index.js +42 -24
  34. package/dist/core/errors/errors-data.d.ts +81 -0
  35. package/dist/core/errors/errors-data.js +84 -0
  36. package/dist/core/messages.js +2 -2
  37. package/dist/core/middleware/callMiddleware.d.ts +36 -0
  38. package/dist/core/middleware/callMiddleware.js +38 -0
  39. package/dist/core/middleware/index.d.ts +4 -0
  40. package/dist/core/middleware/index.js +8 -0
  41. package/dist/core/middleware/loadMiddleware.d.ts +8 -0
  42. package/dist/core/middleware/loadMiddleware.js +13 -0
  43. package/dist/core/middleware/sequence.d.ts +6 -0
  44. package/dist/core/middleware/sequence.js +27 -0
  45. package/dist/core/render/context.d.ts +7 -2
  46. package/dist/core/render/context.js +13 -2
  47. package/dist/core/render/core.d.ts +22 -2
  48. package/dist/core/render/core.js +68 -32
  49. package/dist/core/render/dev/index.d.ts +5 -1
  50. package/dist/core/render/dev/index.js +23 -3
  51. package/dist/core/render/index.d.ts +1 -1
  52. package/dist/core/render/index.js +7 -1
  53. package/dist/core/render/result.d.ts +1 -0
  54. package/dist/core/render/result.js +2 -1
  55. package/dist/core/render/ssr-element.d.ts +3 -2
  56. package/dist/core/render/ssr-element.js +22 -15
  57. package/dist/core/request.js +2 -0
  58. package/dist/integrations/index.js +1 -1
  59. package/dist/runtime/server/endpoint.js +1 -1
  60. package/dist/runtime/server/index.d.ts +1 -1
  61. package/dist/runtime/server/index.js +0 -2
  62. package/dist/runtime/server/render/head.js +3 -1
  63. package/dist/runtime/server/render/index.d.ts +1 -1
  64. package/dist/runtime/server/render/index.js +1 -2
  65. package/dist/runtime/server/render/tags.d.ts +2 -7
  66. package/dist/runtime/server/render/tags.js +9 -27
  67. package/dist/vite-plugin-astro-server/response.js +3 -3
  68. package/dist/vite-plugin-astro-server/route.js +7 -0
  69. package/package.json +10 -6
@@ -9,10 +9,12 @@ export declare const AstroConfigSchema: z.ZodObject<{
9
9
  srcDir: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, URL, string | undefined>;
10
10
  publicDir: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, URL, string | undefined>;
11
11
  outDir: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, URL, string | undefined>;
12
+ cacheDir: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, URL, string | undefined>;
12
13
  site: z.ZodOptional<z.ZodString>;
13
14
  base: z.ZodDefault<z.ZodOptional<z.ZodString>>;
14
15
  trailingSlash: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"always">, z.ZodLiteral<"never">, z.ZodLiteral<"ignore">]>>>;
15
16
  output: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"server">]>>>;
17
+ scopedStyleStrategy: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"where">, z.ZodLiteral<"class">]>>>;
16
18
  adapter: z.ZodOptional<z.ZodObject<{
17
19
  name: z.ZodString;
18
20
  hooks: z.ZodDefault<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
@@ -152,10 +154,16 @@ export declare const AstroConfigSchema: z.ZodObject<{
152
154
  vite: z.ZodDefault<z.ZodType<ViteUserConfig, z.ZodTypeDef, ViteUserConfig>>;
153
155
  experimental: z.ZodDefault<z.ZodOptional<z.ZodObject<{
154
156
  assets: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
157
+ inlineStylesheets: z.ZodDefault<z.ZodOptional<z.ZodEnum<["always", "auto", "never"]>>>;
158
+ middleware: z.ZodDefault<z.ZodOptional<z.ZodOptional<z.ZodBoolean>>>;
155
159
  }, "strip", z.ZodTypeAny, {
156
160
  assets: boolean;
161
+ middleware: boolean;
162
+ inlineStylesheets: "never" | "always" | "auto";
157
163
  }, {
158
164
  assets?: boolean | undefined;
165
+ middleware?: boolean | undefined;
166
+ inlineStylesheets?: "never" | "always" | "auto" | undefined;
159
167
  }>>>;
160
168
  legacy: z.ZodDefault<z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>>;
161
169
  }, "strip", z.ZodTypeAny, {
@@ -184,6 +192,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
184
192
  srcDir: URL;
185
193
  publicDir: URL;
186
194
  outDir: URL;
195
+ cacheDir: URL;
187
196
  trailingSlash: "never" | "always" | "ignore";
188
197
  server: {
189
198
  headers?: OutgoingHttpHeaders | undefined;
@@ -191,6 +200,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
191
200
  host: string | boolean;
192
201
  port: number;
193
202
  };
203
+ scopedStyleStrategy: "where" | "class";
194
204
  integrations: {
195
205
  name: string;
196
206
  hooks: {};
@@ -212,6 +222,8 @@ export declare const AstroConfigSchema: z.ZodObject<{
212
222
  vite: ViteUserConfig;
213
223
  experimental: {
214
224
  assets: boolean;
225
+ middleware: boolean;
226
+ inlineStylesheets: "never" | "always" | "auto";
215
227
  };
216
228
  legacy: {};
217
229
  }, {
@@ -236,8 +248,10 @@ export declare const AstroConfigSchema: z.ZodObject<{
236
248
  srcDir?: string | undefined;
237
249
  publicDir?: string | undefined;
238
250
  outDir?: string | undefined;
251
+ cacheDir?: string | undefined;
239
252
  trailingSlash?: "never" | "always" | "ignore" | undefined;
240
253
  server?: unknown;
254
+ scopedStyleStrategy?: "where" | "class" | undefined;
241
255
  adapter?: {
242
256
  hooks?: {} | undefined;
243
257
  name: string;
@@ -260,6 +274,8 @@ export declare const AstroConfigSchema: z.ZodObject<{
260
274
  vite?: ViteUserConfig | undefined;
261
275
  experimental?: {
262
276
  assets?: boolean | undefined;
277
+ middleware?: boolean | undefined;
278
+ inlineStylesheets?: "never" | "always" | "auto" | undefined;
263
279
  } | undefined;
264
280
  legacy?: {} | undefined;
265
281
  }>;
@@ -316,6 +332,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
316
332
  }>>;
317
333
  output: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"static">, z.ZodLiteral<"server">]>>>;
318
334
  trailingSlash: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"always">, z.ZodLiteral<"never">, z.ZodLiteral<"ignore">]>>>;
335
+ scopedStyleStrategy: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"where">, z.ZodLiteral<"class">]>>>;
319
336
  adapter: z.ZodOptional<z.ZodObject<{
320
337
  name: z.ZodString;
321
338
  hooks: z.ZodDefault<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
@@ -364,16 +381,23 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
364
381
  vite: z.ZodDefault<z.ZodType<ViteUserConfig, z.ZodTypeDef, ViteUserConfig>>;
365
382
  experimental: z.ZodDefault<z.ZodOptional<z.ZodObject<{
366
383
  assets: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
384
+ inlineStylesheets: z.ZodDefault<z.ZodOptional<z.ZodEnum<["always", "auto", "never"]>>>;
385
+ middleware: z.ZodDefault<z.ZodOptional<z.ZodOptional<z.ZodBoolean>>>;
367
386
  }, "strip", z.ZodTypeAny, {
368
387
  assets: boolean;
388
+ middleware: boolean;
389
+ inlineStylesheets: "never" | "always" | "auto";
369
390
  }, {
370
391
  assets?: boolean | undefined;
392
+ middleware?: boolean | undefined;
393
+ inlineStylesheets?: "never" | "always" | "auto" | undefined;
371
394
  }>>>;
372
395
  legacy: z.ZodDefault<z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>>;
373
396
  root: z.ZodEffects<z.ZodDefault<z.ZodString>, URL, string | undefined>;
374
397
  srcDir: z.ZodEffects<z.ZodDefault<z.ZodString>, URL, string | undefined>;
375
398
  publicDir: z.ZodEffects<z.ZodDefault<z.ZodString>, URL, string | undefined>;
376
399
  outDir: z.ZodEffects<z.ZodDefault<z.ZodString>, URL, string | undefined>;
400
+ cacheDir: z.ZodEffects<z.ZodDefault<z.ZodString>, URL, string | undefined>;
377
401
  build: z.ZodDefault<z.ZodOptional<z.ZodObject<{
378
402
  format: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"file">, z.ZodLiteral<"directory">]>>>;
379
403
  client: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, URL, string | undefined>;
@@ -447,6 +471,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
447
471
  srcDir: URL;
448
472
  publicDir: URL;
449
473
  outDir: URL;
474
+ cacheDir: URL;
450
475
  trailingSlash: "never" | "always" | "ignore";
451
476
  server: {
452
477
  headers?: OutgoingHttpHeaders | undefined;
@@ -455,6 +480,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
455
480
  port: number;
456
481
  streaming: boolean;
457
482
  };
483
+ scopedStyleStrategy: "where" | "class";
458
484
  integrations: {
459
485
  name: string;
460
486
  hooks: {};
@@ -476,6 +502,8 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
476
502
  vite: ViteUserConfig;
477
503
  experimental: {
478
504
  assets: boolean;
505
+ middleware: boolean;
506
+ inlineStylesheets: "never" | "always" | "auto";
479
507
  };
480
508
  legacy: {};
481
509
  }, {
@@ -500,8 +528,10 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
500
528
  srcDir?: string | undefined;
501
529
  publicDir?: string | undefined;
502
530
  outDir?: string | undefined;
531
+ cacheDir?: string | undefined;
503
532
  trailingSlash?: "never" | "always" | "ignore" | undefined;
504
533
  server?: unknown;
534
+ scopedStyleStrategy?: "where" | "class" | undefined;
505
535
  adapter?: {
506
536
  hooks?: {} | undefined;
507
537
  name: string;
@@ -524,6 +554,8 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
524
554
  vite?: ViteUserConfig | undefined;
525
555
  experimental?: {
526
556
  assets?: boolean | undefined;
557
+ middleware?: boolean | undefined;
558
+ inlineStylesheets?: "never" | "always" | "auto" | undefined;
527
559
  } | undefined;
528
560
  legacy?: {} | undefined;
529
561
  }>, {
@@ -552,6 +584,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
552
584
  srcDir: URL;
553
585
  publicDir: URL;
554
586
  outDir: URL;
587
+ cacheDir: URL;
555
588
  trailingSlash: "never" | "always" | "ignore";
556
589
  server: {
557
590
  headers?: OutgoingHttpHeaders | undefined;
@@ -560,6 +593,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
560
593
  port: number;
561
594
  streaming: boolean;
562
595
  };
596
+ scopedStyleStrategy: "where" | "class";
563
597
  integrations: {
564
598
  name: string;
565
599
  hooks: {};
@@ -581,6 +615,8 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
581
615
  vite: ViteUserConfig;
582
616
  experimental: {
583
617
  assets: boolean;
618
+ middleware: boolean;
619
+ inlineStylesheets: "never" | "always" | "auto";
584
620
  };
585
621
  legacy: {};
586
622
  }, {
@@ -605,8 +641,10 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
605
641
  srcDir?: string | undefined;
606
642
  publicDir?: string | undefined;
607
643
  outDir?: string | undefined;
644
+ cacheDir?: string | undefined;
608
645
  trailingSlash?: "never" | "always" | "ignore" | undefined;
609
646
  server?: unknown;
647
+ scopedStyleStrategy?: "where" | "class" | undefined;
610
648
  adapter?: {
611
649
  hooks?: {} | undefined;
612
650
  name: string;
@@ -629,6 +667,8 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: URL)
629
667
  vite?: ViteUserConfig | undefined;
630
668
  experimental?: {
631
669
  assets?: boolean | undefined;
670
+ middleware?: boolean | undefined;
671
+ inlineStylesheets?: "never" | "always" | "auto" | undefined;
632
672
  } | undefined;
633
673
  legacy?: {} | undefined;
634
674
  }>;
@@ -7,6 +7,7 @@ const ASTRO_CONFIG_DEFAULTS = {
7
7
  srcDir: "./src",
8
8
  publicDir: "./public",
9
9
  outDir: "./dist",
10
+ cacheDir: "./node_modules/.astro",
10
11
  base: "/",
11
12
  trailingSlash: "ignore",
12
13
  build: {
@@ -30,7 +31,9 @@ const ASTRO_CONFIG_DEFAULTS = {
30
31
  vite: {},
31
32
  legacy: {},
32
33
  experimental: {
33
- assets: false
34
+ assets: false,
35
+ inlineStylesheets: "never",
36
+ middleware: false
34
37
  }
35
38
  };
36
39
  const AstroConfigSchema = z.object({
@@ -38,10 +41,12 @@ const AstroConfigSchema = z.object({
38
41
  srcDir: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.srcDir).transform((val) => new URL(val)),
39
42
  publicDir: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.publicDir).transform((val) => new URL(val)),
40
43
  outDir: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.outDir).transform((val) => new URL(val)),
44
+ cacheDir: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.cacheDir).transform((val) => new URL(val)),
41
45
  site: z.string().url().optional(),
42
46
  base: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.base),
43
47
  trailingSlash: z.union([z.literal("always"), z.literal("never"), z.literal("ignore")]).optional().default(ASTRO_CONFIG_DEFAULTS.trailingSlash),
44
48
  output: z.union([z.literal("static"), z.literal("server")]).optional().default("static"),
49
+ scopedStyleStrategy: z.union([z.literal("where"), z.literal("class")]).optional().default("where"),
45
50
  adapter: z.object({ name: z.string(), hooks: z.object({}).passthrough().default({}) }).optional(),
46
51
  integrations: z.preprocess(
47
52
  // preprocess
@@ -108,7 +113,9 @@ const AstroConfigSchema = z.object({
108
113
  }).default({}),
109
114
  vite: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.vite),
110
115
  experimental: z.object({
111
- assets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.assets)
116
+ assets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.assets),
117
+ inlineStylesheets: z.enum(["always", "auto", "never"]).optional().default(ASTRO_CONFIG_DEFAULTS.experimental.inlineStylesheets),
118
+ middleware: z.oboolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.middleware)
112
119
  }).optional().default({}),
113
120
  legacy: z.object({}).optional().default({})
114
121
  });
@@ -118,6 +125,7 @@ function createRelativeSchema(cmd, fileProtocolRoot) {
118
125
  srcDir: z.string().default(ASTRO_CONFIG_DEFAULTS.srcDir).transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
119
126
  publicDir: z.string().default(ASTRO_CONFIG_DEFAULTS.publicDir).transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
120
127
  outDir: z.string().default(ASTRO_CONFIG_DEFAULTS.outDir).transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
128
+ cacheDir: z.string().default(ASTRO_CONFIG_DEFAULTS.cacheDir).transform((val) => new URL(appendForwardSlash(val), fileProtocolRoot)),
121
129
  build: z.object({
122
130
  format: z.union([z.literal("file"), z.literal("directory")]).optional().default(ASTRO_CONFIG_DEFAULTS.build.format),
123
131
  client: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.build.client).transform((val) => new URL(val, fileProtocolRoot)),
@@ -1,2 +1,3 @@
1
1
  export declare const ASTRO_VERSION: string;
2
2
  export declare const SUPPORTED_MARKDOWN_FILE_EXTENSIONS: readonly [".markdown", ".mdown", ".mkdn", ".mkd", ".mdwn", ".md"];
3
+ export declare const MIDDLEWARE_PATH_SEGMENT_NAME = "middleware";
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "2.3.4";
1
+ const ASTRO_VERSION = "2.4.0";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -7,7 +7,9 @@ const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
7
7
  ".mdwn",
8
8
  ".md"
9
9
  ];
10
+ const MIDDLEWARE_PATH_SEGMENT_NAME = "middleware";
10
11
  export {
11
12
  ASTRO_VERSION,
13
+ MIDDLEWARE_PATH_SEGMENT_NAME,
12
14
  SUPPORTED_MARKDOWN_FILE_EXTENSIONS
13
15
  };
@@ -53,7 +53,7 @@ async function dev(settings, options) {
53
53
  isRestart: options.isRestart
54
54
  })
55
55
  );
56
- const currentVersion = "2.3.4";
56
+ const currentVersion = "2.4.0";
57
57
  if (currentVersion.includes("-")) {
58
58
  warn(options.logging, null, msg.prerelease({ currentVersion }));
59
59
  }
@@ -3,16 +3,19 @@ import { call as callEndpoint } from "../index.js";
3
3
  async function call(options, logging) {
4
4
  const {
5
5
  env,
6
- preload: [, mod]
6
+ preload: [, mod],
7
+ middleware
7
8
  } = options;
8
9
  const endpointHandler = mod;
9
- const ctx = createRenderContext({
10
+ const ctx = await createRenderContext({
10
11
  request: options.request,
11
12
  origin: options.origin,
12
13
  pathname: options.pathname,
13
- route: options.route
14
+ route: options.route,
15
+ env,
16
+ mod: endpointHandler
14
17
  });
15
- return await callEndpoint(endpointHandler, env, ctx, logging);
18
+ return await callEndpoint(endpointHandler, env, ctx, logging, middleware);
16
19
  }
17
20
  export {
18
21
  call
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { AstroConfig, EndpointHandler } from '../../@types/astro';
2
+ import type { APIContext, AstroConfig, AstroMiddlewareInstance, EndpointHandler, EndpointOutput, Params } from '../../@types/astro';
3
3
  import type { Environment, RenderContext } from '../render/index';
4
4
  import { AstroCookies } from '../cookies/index.js';
5
5
  import { type LogOptions } from '../logger/core.js';
@@ -12,6 +12,13 @@ type EndpointCallResult = {
12
12
  type: 'response';
13
13
  response: Response;
14
14
  };
15
- export declare function call(mod: EndpointHandler, env: Environment, ctx: RenderContext, logging: LogOptions): Promise<EndpointCallResult>;
15
+ export declare function createAPIContext({ request, params, site, props, adapterName, }: {
16
+ request: Request;
17
+ params: Params;
18
+ site?: string;
19
+ props: Record<string, any>;
20
+ adapterName?: string;
21
+ }): APIContext;
22
+ export declare function call<MiddlewareResult = Response | EndpointOutput>(mod: EndpointHandler, env: Environment, ctx: RenderContext, logging: LogOptions, middleware?: AstroMiddlewareInstance<MiddlewareResult> | undefined): Promise<EndpointCallResult>;
16
23
  export declare function throwIfRedirectNotAllowed(response: Response, config: AstroConfig): void;
17
24
  export {};
@@ -3,8 +3,10 @@ import { ASTRO_VERSION } from "../constants.js";
3
3
  import { AstroCookies, attachToResponse } from "../cookies/index.js";
4
4
  import { AstroError, AstroErrorData } from "../errors/index.js";
5
5
  import { warn } from "../logger/core.js";
6
- import { getParamsAndProps, GetParamsAndPropsError } from "../render/core.js";
6
+ import { callMiddleware } from "../middleware/callMiddleware.js";
7
+ import { isValueSerializable } from "../render/core.js";
7
8
  const clientAddressSymbol = Symbol.for("astro.clientAddress");
9
+ const clientLocalsSymbol = Symbol.for("astro.locals");
8
10
  function createAPIContext({
9
11
  request,
10
12
  params,
@@ -12,7 +14,7 @@ function createAPIContext({
12
14
  props,
13
15
  adapterName
14
16
  }) {
15
- return {
17
+ const context = {
16
18
  cookies: new AstroCookies(request),
17
19
  request,
18
20
  params,
@@ -28,7 +30,6 @@ function createAPIContext({
28
30
  });
29
31
  },
30
32
  url: new URL(request.url),
31
- // @ts-expect-error
32
33
  get clientAddress() {
33
34
  if (!(clientAddressSymbol in request)) {
34
35
  if (adapterName) {
@@ -43,33 +44,49 @@ function createAPIContext({
43
44
  return Reflect.get(request, clientAddressSymbol);
44
45
  }
45
46
  };
46
- }
47
- async function call(mod, env, ctx, logging) {
48
- var _a, _b;
49
- const paramsAndPropsResp = await getParamsAndProps({
50
- mod,
51
- route: ctx.route,
52
- routeCache: env.routeCache,
53
- pathname: ctx.pathname,
54
- logging: env.logging,
55
- ssr: env.ssr
47
+ Object.defineProperty(context, "locals", {
48
+ get() {
49
+ return Reflect.get(request, clientLocalsSymbol);
50
+ },
51
+ set(val) {
52
+ if (typeof val !== "object") {
53
+ throw new AstroError(AstroErrorData.LocalsNotAnObject);
54
+ } else {
55
+ Reflect.set(request, clientLocalsSymbol, val);
56
+ }
57
+ }
56
58
  });
57
- if (paramsAndPropsResp === GetParamsAndPropsError.NoMatchingStaticPath) {
58
- throw new AstroError({
59
- ...AstroErrorData.NoMatchingStaticPathFound,
60
- message: AstroErrorData.NoMatchingStaticPathFound.message(ctx.pathname),
61
- hint: ((_a = ctx.route) == null ? void 0 : _a.component) ? AstroErrorData.NoMatchingStaticPathFound.hint([(_b = ctx.route) == null ? void 0 : _b.component]) : ""
62
- });
63
- }
64
- const [params, props] = paramsAndPropsResp;
59
+ return context;
60
+ }
61
+ async function call(mod, env, ctx, logging, middleware) {
65
62
  const context = createAPIContext({
66
63
  request: ctx.request,
67
- params,
68
- props,
64
+ params: ctx.params,
65
+ props: ctx.props,
69
66
  site: env.site,
70
67
  adapterName: env.adapterName
71
68
  });
72
- const response = await renderEndpoint(mod, context, env.ssr);
69
+ let response = await renderEndpoint(mod, context, env.ssr);
70
+ if (middleware && middleware.onRequest) {
71
+ if (response.body === null) {
72
+ const onRequest = middleware.onRequest;
73
+ response = await callMiddleware(onRequest, context, async () => {
74
+ if (env.mode === "development" && !isValueSerializable(context.locals)) {
75
+ throw new AstroError({
76
+ ...AstroErrorData.LocalsNotSerializable,
77
+ message: AstroErrorData.LocalsNotSerializable.message(ctx.pathname)
78
+ });
79
+ }
80
+ return response;
81
+ });
82
+ } else {
83
+ warn(
84
+ env.logging,
85
+ "middleware",
86
+ "Middleware doesn't work for endpoints that return a simple body. The middleware will be disabled for this page."
87
+ );
88
+ }
89
+ }
73
90
  if (response instanceof Response) {
74
91
  attachToResponse(response, context.cookies);
75
92
  return {
@@ -110,5 +127,6 @@ function throwIfRedirectNotAllowed(response, config) {
110
127
  }
111
128
  export {
112
129
  call,
130
+ createAPIContext,
113
131
  throwIfRedirectNotAllowed
114
132
  };
@@ -555,6 +555,87 @@ export declare const AstroErrorData: {
555
555
  readonly code: 3030;
556
556
  readonly message: "The response has already been sent to the browser and cannot be altered.";
557
557
  };
558
+ /**
559
+ * @docs
560
+ * @description
561
+ * Thrown when the middleware does not return any data or call the `next` function.
562
+ *
563
+ * For example:
564
+ * ```ts
565
+ * import {defineMiddleware} from "astro/middleware";
566
+ * export const onRequest = defineMiddleware((context, _) => {
567
+ * // doesn't return anything or call `next`
568
+ * context.locals.someData = false;
569
+ * });
570
+ * ```
571
+ */
572
+ readonly MiddlewareNoDataOrNextCalled: {
573
+ readonly title: "The middleware didn't return a response or call `next`";
574
+ readonly code: 3031;
575
+ readonly message: "The middleware needs to either return a `Response` object or call the `next` function.";
576
+ };
577
+ /**
578
+ * @docs
579
+ * @description
580
+ * Thrown in development mode when middleware returns something that is not a `Response` object.
581
+ *
582
+ * For example:
583
+ * ```ts
584
+ * import {defineMiddleware} from "astro/middleware";
585
+ * export const onRequest = defineMiddleware(() => {
586
+ * return "string"
587
+ * });
588
+ * ```
589
+ */
590
+ readonly MiddlewareNotAResponse: {
591
+ readonly title: "The middleware returned something that is not a `Response` object";
592
+ readonly code: 3032;
593
+ readonly message: "Any data returned from middleware must be a valid `Response` object.";
594
+ };
595
+ /**
596
+ * @docs
597
+ * @description
598
+ *
599
+ * Thrown in development mode when `locals` is overwritten with something that is not an object
600
+ *
601
+ * For example:
602
+ * ```ts
603
+ * import {defineMiddleware} from "astro/middleware";
604
+ * export const onRequest = defineMiddleware((context, next) => {
605
+ * context.locals = 1541;
606
+ * return next();
607
+ * });
608
+ * ```
609
+ */
610
+ readonly LocalsNotAnObject: {
611
+ readonly title: "Value assigned to `locals` is not accepted";
612
+ readonly code: 3033;
613
+ readonly message: "`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.";
614
+ readonly hint: "If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`.";
615
+ };
616
+ /**
617
+ * @docs
618
+ * @description
619
+ * Thrown in development mode when a user attempts to store something that is not serializable in `locals`.
620
+ *
621
+ * For example:
622
+ * ```ts
623
+ * import {defineMiddleware} from "astro/middleware";
624
+ * export const onRequest = defineMiddleware((context, next) => {
625
+ * context.locals = {
626
+ * foo() {
627
+ * alert("Hello world!")
628
+ * }
629
+ * };
630
+ * return next();
631
+ * });
632
+ * ```
633
+ */
634
+ readonly LocalsNotSerializable: {
635
+ readonly title: "`Astro.locals` is not serializable";
636
+ readonly code: 3034;
637
+ readonly message: (href: string) => string;
638
+ };
558
639
  /**
559
640
  * @docs
560
641
  * @see
@@ -568,6 +568,90 @@ Expected \`true\` value but got \`${suffix}\`.`;
568
568
  code: 3030,
569
569
  message: "The response has already been sent to the browser and cannot be altered."
570
570
  },
571
+ /**
572
+ * @docs
573
+ * @description
574
+ * Thrown when the middleware does not return any data or call the `next` function.
575
+ *
576
+ * For example:
577
+ * ```ts
578
+ * import {defineMiddleware} from "astro/middleware";
579
+ * export const onRequest = defineMiddleware((context, _) => {
580
+ * // doesn't return anything or call `next`
581
+ * context.locals.someData = false;
582
+ * });
583
+ * ```
584
+ */
585
+ MiddlewareNoDataOrNextCalled: {
586
+ title: "The middleware didn't return a response or call `next`",
587
+ code: 3031,
588
+ message: "The middleware needs to either return a `Response` object or call the `next` function."
589
+ },
590
+ /**
591
+ * @docs
592
+ * @description
593
+ * Thrown in development mode when middleware returns something that is not a `Response` object.
594
+ *
595
+ * For example:
596
+ * ```ts
597
+ * import {defineMiddleware} from "astro/middleware";
598
+ * export const onRequest = defineMiddleware(() => {
599
+ * return "string"
600
+ * });
601
+ * ```
602
+ */
603
+ MiddlewareNotAResponse: {
604
+ title: "The middleware returned something that is not a `Response` object",
605
+ code: 3032,
606
+ message: "Any data returned from middleware must be a valid `Response` object."
607
+ },
608
+ /**
609
+ * @docs
610
+ * @description
611
+ *
612
+ * Thrown in development mode when `locals` is overwritten with something that is not an object
613
+ *
614
+ * For example:
615
+ * ```ts
616
+ * import {defineMiddleware} from "astro/middleware";
617
+ * export const onRequest = defineMiddleware((context, next) => {
618
+ * context.locals = 1541;
619
+ * return next();
620
+ * });
621
+ * ```
622
+ */
623
+ LocalsNotAnObject: {
624
+ title: "Value assigned to `locals` is not accepted",
625
+ code: 3033,
626
+ message: "`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.",
627
+ hint: "If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`."
628
+ },
629
+ /**
630
+ * @docs
631
+ * @description
632
+ * Thrown in development mode when a user attempts to store something that is not serializable in `locals`.
633
+ *
634
+ * For example:
635
+ * ```ts
636
+ * import {defineMiddleware} from "astro/middleware";
637
+ * export const onRequest = defineMiddleware((context, next) => {
638
+ * context.locals = {
639
+ * foo() {
640
+ * alert("Hello world!")
641
+ * }
642
+ * };
643
+ * return next();
644
+ * });
645
+ * ```
646
+ */
647
+ LocalsNotSerializable: {
648
+ title: "`Astro.locals` is not serializable",
649
+ code: 3034,
650
+ message: (href) => {
651
+ return `The information stored in \`Astro.locals\` for the path "${href}" is not serializable.
652
+ Make sure you store only serializable data.`;
653
+ }
654
+ },
571
655
  // No headings here, that way Vite errors are merged with Astro ones in the docs, which makes more sense to users.
572
656
  // Vite Errors - 4xxx
573
657
  /**
@@ -47,7 +47,7 @@ function serverStart({
47
47
  base,
48
48
  isRestart = false
49
49
  }) {
50
- const version = "2.3.4";
50
+ const version = "2.4.0";
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.3.4"}`
236
+ `v${"2.4.0"}`
237
237
  )} ${headline}`
238
238
  );
239
239
  }
@@ -0,0 +1,36 @@
1
+ import type { APIContext, MiddlewareHandler } from '../../@types/astro';
2
+ /**
3
+ * Utility function that is in charge of calling the middleware.
4
+ *
5
+ * It accepts a `R` generic, which usually is the `Response` returned.
6
+ * It is a generic because endpoints can return a different payload.
7
+ *
8
+ * When calling a middleware, we provide a `next` function, this function might or
9
+ * might not be called.
10
+ *
11
+ * A middleware, to behave correctly, can:
12
+ * - return a `Response`;
13
+ * - call `next`;
14
+ *
15
+ * Failing doing so will result an error. A middleware can call `next` and do not return a
16
+ * response. A middleware can not call `next` and return a new `Response` from scratch (maybe with a redirect).
17
+ *
18
+ * ```js
19
+ * const onRequest = async (context, next) => {
20
+ * const response = await next(context);
21
+ * return response;
22
+ * }
23
+ * ```
24
+ *
25
+ * ```js
26
+ * const onRequest = async (context, next) => {
27
+ * context.locals = "foo";
28
+ * next();
29
+ * }
30
+ * ```
31
+ *
32
+ * @param onRequest The function called which accepts a `context` and a `resolve` function
33
+ * @param apiContext The API context
34
+ * @param responseFunction A callback function that should return a promise with the response
35
+ */
36
+ export declare function callMiddleware<R>(onRequest: MiddlewareHandler<R>, apiContext: APIContext, responseFunction: () => Promise<R>): Promise<Response | R>;