astro 5.2.6 → 5.3.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.
@@ -50,12 +50,14 @@ const ASTRO_CONFIG_DEFAULTS = {
50
50
  schema: {},
51
51
  validateSecrets: false
52
52
  },
53
+ session: void 0,
53
54
  experimental: {
54
55
  clientPrerender: false,
55
56
  contentIntellisense: false,
56
57
  responsiveImages: false,
57
58
  svg: false,
58
- serializeConfig: false
59
+ serializeConfig: false,
60
+ session: false
59
61
  }
60
62
  };
61
63
  const AstroConfigSchema = z.object({
@@ -331,31 +333,29 @@ const AstroConfigSchema = z.object({
331
333
  schema: EnvSchema.optional().default(ASTRO_CONFIG_DEFAULTS.env.schema),
332
334
  validateSecrets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.env.validateSecrets)
333
335
  }).strict().optional().default(ASTRO_CONFIG_DEFAULTS.env),
336
+ session: z.object({
337
+ driver: z.string(),
338
+ options: z.record(z.any()).optional(),
339
+ cookie: z.object({
340
+ name: z.string().optional(),
341
+ domain: z.string().optional(),
342
+ path: z.string().optional(),
343
+ maxAge: z.number().optional(),
344
+ sameSite: z.union([z.enum(["strict", "lax", "none"]), z.boolean()]).optional(),
345
+ secure: z.boolean().optional()
346
+ }).or(z.string()).transform((val) => {
347
+ if (typeof val === "string") {
348
+ return { name: val };
349
+ }
350
+ return val;
351
+ }).optional(),
352
+ ttl: z.number().optional()
353
+ }).optional(),
334
354
  experimental: z.object({
335
355
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
336
356
  contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
337
357
  responsiveImages: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.responsiveImages),
338
- session: z.object({
339
- driver: z.string(),
340
- options: z.record(z.any()).optional(),
341
- cookie: z.union([
342
- z.object({
343
- name: z.string().optional(),
344
- domain: z.string().optional(),
345
- path: z.string().optional(),
346
- maxAge: z.number().optional(),
347
- sameSite: z.union([z.enum(["strict", "lax", "none"]), z.boolean()]).optional(),
348
- secure: z.boolean().optional()
349
- }),
350
- z.string()
351
- ]).transform((val) => {
352
- if (typeof val === "string") {
353
- return { name: val };
354
- }
355
- return val;
356
- }).optional(),
357
- ttl: z.number().optional()
358
- }).optional(),
358
+ session: z.boolean().optional(),
359
359
  svg: z.union([
360
360
  z.boolean(),
361
361
  z.object({
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.2.6";
1
+ const ASTRO_VERSION = "5.3.0";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -22,7 +22,7 @@ async function dev(inlineConfig) {
22
22
  await telemetry.record([]);
23
23
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
24
24
  const logger = restart.container.logger;
25
- const currentVersion = "5.2.6";
25
+ const currentVersion = "5.3.0";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -784,34 +784,6 @@ export declare const AstroResponseHeadersReassigned: {
784
784
  message: string;
785
785
  hint: string;
786
786
  };
787
- /**
788
- * @docs
789
- * @message Error when initializing session storage with driver `DRIVER`. `ERROR`
790
- * @see
791
- * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
792
- * @description
793
- * Thrown when the session storage could not be initialized.
794
- */
795
- export declare const SessionStorageInitError: {
796
- name: string;
797
- title: string;
798
- message: (error: string, driver?: string) => string;
799
- hint: string;
800
- };
801
- /**
802
- * @docs
803
- * @message Error when saving session data with driver `DRIVER`. `ERROR`
804
- * @see
805
- * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
806
- * @description
807
- * Thrown when the session data could not be saved.
808
- */
809
- export declare const SessionStorageSaveError: {
810
- name: string;
811
- title: string;
812
- message: (error: string, driver?: string) => string;
813
- hint: string;
814
- };
815
787
  /**
816
788
  * @docs
817
789
  * @description
@@ -1621,3 +1593,77 @@ export declare const UnknownError: {
1621
1593
  name: string;
1622
1594
  title: string;
1623
1595
  };
1596
+ /**
1597
+ * @docs
1598
+ * @kind heading
1599
+ * @name Session Errors
1600
+ */
1601
+ /**
1602
+ * @docs
1603
+ * @see
1604
+ * - [Server output adapter feature](https://docs.astro.build/en/reference/adapter-reference/#building-an-adapter)
1605
+ * @description
1606
+ * Your adapter must support server output to use sessions.
1607
+ */
1608
+ export declare const SessionWithoutSupportedAdapterOutputError: {
1609
+ name: string;
1610
+ title: string;
1611
+ message: string;
1612
+ hint: string;
1613
+ };
1614
+ /**
1615
+ * @docs
1616
+ * @message Error when initializing session storage with driver `DRIVER`. `ERROR`
1617
+ * @see
1618
+ * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
1619
+ * @description
1620
+ * Thrown when the session storage could not be initialized.
1621
+ */
1622
+ export declare const SessionStorageInitError: {
1623
+ name: string;
1624
+ title: string;
1625
+ message: (error: string, driver?: string) => string;
1626
+ hint: string;
1627
+ };
1628
+ /**
1629
+ * @docs
1630
+ * @message Error when saving session data with driver `DRIVER`. `ERROR`
1631
+ * @see
1632
+ * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
1633
+ * @description
1634
+ * Thrown when the session data could not be saved.
1635
+ */
1636
+ export declare const SessionStorageSaveError: {
1637
+ name: string;
1638
+ title: string;
1639
+ message: (error: string, driver?: string) => string;
1640
+ hint: string;
1641
+ };
1642
+ /**
1643
+ * @docs
1644
+ * @message The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage
1645
+ * @see
1646
+ * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
1647
+ * @description
1648
+ * Thrown when session storage is enabled but not configured.
1649
+ */
1650
+ export declare const SessionConfigMissingError: {
1651
+ name: string;
1652
+ title: string;
1653
+ message: string;
1654
+ hint: string;
1655
+ };
1656
+ /**
1657
+ * @docs
1658
+ * @message Session config was provided without enabling the `experimental.session` flag
1659
+ * @see
1660
+ * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/)
1661
+ * @description
1662
+ * Thrown when session storage is configured but the `experimental.session` flag is not enabled.
1663
+ */
1664
+ export declare const SessionConfigWithoutFlagError: {
1665
+ name: string;
1666
+ title: string;
1667
+ message: string;
1668
+ hint: string;
1669
+ };
@@ -280,18 +280,6 @@ const AstroResponseHeadersReassigned = {
280
280
  message: "Individual headers can be added to and removed from `Astro.response.headers`, but it must not be replaced with another instance of `Headers` altogether.",
281
281
  hint: "Consider using `Astro.response.headers.add()`, and `Astro.response.headers.delete()`."
282
282
  };
283
- const SessionStorageInitError = {
284
- name: "SessionStorageInitError",
285
- title: "Session storage could not be initialized.",
286
- message: (error, driver) => `Error when initializing session storage${driver ? ` with driver \`${driver}\`` : ""}. \`${error ?? ""}\``,
287
- hint: "For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/"
288
- };
289
- const SessionStorageSaveError = {
290
- name: "SessionStorageSaveError",
291
- title: "Session data could not be saved.",
292
- message: (error, driver) => `Error when saving session data${driver ? ` with driver \`${driver}\`` : ""}. \`${error ?? ""}\``,
293
- hint: "For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/"
294
- };
295
283
  const MiddlewareCantBeLoaded = {
296
284
  name: "MiddlewareCantBeLoaded",
297
285
  title: "Can't load the middleware.",
@@ -645,6 +633,36 @@ const ActionCalledFromServerError = {
645
633
  hint: "See the `Astro.callAction()` reference for usage examples: https://docs.astro.build/en/reference/api-reference/#callaction"
646
634
  };
647
635
  const UnknownError = { name: "UnknownError", title: "Unknown Error." };
636
+ const SessionWithoutSupportedAdapterOutputError = {
637
+ name: "SessionWithoutSupportedAdapterOutputError",
638
+ title: "Sessions cannot be used with an adapter that doesn't support server output.",
639
+ message: 'Sessions require an adapter that supports server output. The adapter must set `"server"` in the `buildOutput` adapter feature.',
640
+ hint: 'Ensure your adapter supports `buildOutput: "server"`: https://docs.astro.build/en/reference/adapter-reference/#building-an-adapter'
641
+ };
642
+ const SessionStorageInitError = {
643
+ name: "SessionStorageInitError",
644
+ title: "Session storage could not be initialized.",
645
+ message: (error, driver) => `Error when initializing session storage${driver ? ` with driver \`${driver}\`` : ""}. \`${error ?? ""}\``,
646
+ hint: "For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/"
647
+ };
648
+ const SessionStorageSaveError = {
649
+ name: "SessionStorageSaveError",
650
+ title: "Session data could not be saved.",
651
+ message: (error, driver) => `Error when saving session data${driver ? ` with driver \`${driver}\`` : ""}. \`${error ?? ""}\``,
652
+ hint: "For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/"
653
+ };
654
+ const SessionConfigMissingError = {
655
+ name: "SessionConfigMissingError",
656
+ title: "Session storage was enabled but not configured.",
657
+ message: "The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage",
658
+ hint: "See https://docs.astro.build/en/reference/experimental-flags/sessions/"
659
+ };
660
+ const SessionConfigWithoutFlagError = {
661
+ name: "SessionConfigWithoutFlagError",
662
+ title: "Session flag not set",
663
+ message: "Session config was provided without enabling the `experimental.session` flag",
664
+ hint: "See https://docs.astro.build/en/reference/experimental-flags/sessions/"
665
+ };
648
666
  export {
649
667
  ActionCalledFromServerError,
650
668
  ActionNotFoundError,
@@ -733,8 +751,11 @@ export {
733
751
  RewriteWithBodyUsed,
734
752
  RouteNotFound,
735
753
  ServerOnlyModule,
754
+ SessionConfigMissingError,
755
+ SessionConfigWithoutFlagError,
736
756
  SessionStorageInitError,
737
757
  SessionStorageSaveError,
758
+ SessionWithoutSupportedAdapterOutputError,
738
759
  StaticClientAddressNotAvailable,
739
760
  UnhandledRejection,
740
761
  UnknownCLIError,
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "5.2.6";
41
+ const version = "5.3.0";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -281,7 +281,7 @@ function printHelp({
281
281
  message.push(
282
282
  linebreak(),
283
283
  ` ${bgGreen(black(` ${commandName} `))} ${green(
284
- `v${"5.2.6"}`
284
+ `v${"5.3.0"}`
285
285
  )} ${headline}`
286
286
  );
287
287
  }
@@ -1,3 +1,4 @@
1
+ import type { AstroSettings } from '../types/astro.js';
1
2
  import type { ResolvedSessionConfig, SessionDriverName } from '../types/public/config.js';
2
3
  import type { AstroCookies } from './cookies/cookies.js';
3
4
  export declare const PERSIST_SYMBOL: unique symbol;
@@ -45,4 +46,5 @@ export declare class AstroSession<TDriver extends SessionDriverName = any> {
45
46
  [PERSIST_SYMBOL](): Promise<void>;
46
47
  get sessionID(): string | undefined;
47
48
  }
48
- export declare function resolveSessionDriver(driver: string | undefined): Promise<string> | string | null;
49
+ export declare function resolveSessionDriver(driver: string | undefined): Promise<string | null>;
50
+ export declare function validateSessionConfig(settings: AstroSettings): void;
@@ -3,7 +3,13 @@ import {
3
3
  builtinDrivers,
4
4
  createStorage
5
5
  } from "unstorage";
6
- import { SessionStorageInitError, SessionStorageSaveError } from "./errors/errors-data.js";
6
+ import {
7
+ SessionConfigMissingError,
8
+ SessionConfigWithoutFlagError,
9
+ SessionStorageInitError,
10
+ SessionStorageSaveError,
11
+ SessionWithoutSupportedAdapterOutputError
12
+ } from "./errors/errors-data.js";
7
13
  import { AstroError } from "./errors/index.js";
8
14
  const PERSIST_SYMBOL = Symbol();
9
15
  const DEFAULT_COOKIE_NAME = "astro-session";
@@ -373,20 +379,43 @@ class AstroSession {
373
379
  }
374
380
  }
375
381
  }
376
- function resolveSessionDriver(driver) {
382
+ async function resolveSessionDriver(driver) {
377
383
  if (!driver) {
378
384
  return null;
379
385
  }
380
- if (driver === "fs") {
381
- return import.meta.resolve(builtinDrivers.fsLite);
382
- }
383
- if (driver in builtinDrivers) {
384
- return import.meta.resolve(builtinDrivers[driver]);
386
+ try {
387
+ if (driver === "fs") {
388
+ return await import.meta.resolve(builtinDrivers.fsLite);
389
+ }
390
+ if (driver in builtinDrivers) {
391
+ return await import.meta.resolve(builtinDrivers[driver]);
392
+ }
393
+ } catch {
394
+ return null;
385
395
  }
386
396
  return driver;
387
397
  }
398
+ function validateSessionConfig(settings) {
399
+ const { experimental, session } = settings.config;
400
+ const { buildOutput } = settings;
401
+ let error;
402
+ if (experimental.session) {
403
+ if (!session?.driver) {
404
+ error = new AstroError(SessionConfigMissingError);
405
+ } else if (buildOutput === "static") {
406
+ error = new AstroError(SessionWithoutSupportedAdapterOutputError);
407
+ }
408
+ } else if (session?.driver) {
409
+ error = new AstroError(SessionConfigWithoutFlagError);
410
+ }
411
+ if (error) {
412
+ error.stack = void 0;
413
+ throw error;
414
+ }
415
+ }
388
416
  export {
389
417
  AstroSession,
390
418
  PERSIST_SYMBOL,
391
- resolveSessionDriver
419
+ resolveSessionDriver,
420
+ validateSessionConfig
392
421
  };
@@ -9,6 +9,7 @@ import { globalContentConfigObserver } from "../content/utils.js";
9
9
  import { buildClientDirectiveEntrypoint } from "../core/client-directive/index.js";
10
10
  import { mergeConfig } from "../core/config/index.js";
11
11
  import { validateSetAdapter } from "../core/dev/adapter-validation.js";
12
+ import { validateSessionConfig } from "../core/session.js";
12
13
  import { validateSupportedFeatures } from "./features-validation.js";
13
14
  async function withTakingALongTimeMsg({
14
15
  name,
@@ -272,6 +273,7 @@ async function runHookConfigDone({
272
273
  });
273
274
  }
274
275
  }
276
+ validateSessionConfig(settings);
275
277
  }
276
278
  async function runHookServerSetup({
277
279
  config,
@@ -5,8 +5,11 @@ import { AstroError } from "../../core/errors/errors.js";
5
5
  async function renderEndpoint(mod, context, isPrerendered, logger) {
6
6
  const { request, url } = context;
7
7
  const method = request.method.toUpperCase();
8
- const handler = mod[method] ?? mod["ALL"];
9
- if (isPrerendered && method !== "GET") {
8
+ let handler = mod[method] ?? mod["ALL"];
9
+ if (!handler && method === "HEAD" && mod["GET"]) {
10
+ handler = mod["GET"];
11
+ }
12
+ if (isPrerendered && !["GET", "HEAD"].includes(method)) {
10
13
  logger.warn(
11
14
  "router",
12
15
  `${url.pathname} ${bold(
@@ -47,6 +50,9 @@ Found handlers: ${Object.keys(mod).map((exp) => JSON.stringify(exp)).join(", ")}
47
50
  }
48
51
  }
49
52
  }
53
+ if (method === "HEAD") {
54
+ return new Response(null, response);
55
+ }
50
56
  return response;
51
57
  }
52
58
  export {
@@ -1,2 +1,2 @@
1
1
  import { type RenderDestination } from './common.js';
2
- export declare function renderChild(destination: RenderDestination, child: any): Promise<void>;
2
+ export declare function renderChild(destination: RenderDestination, child: any): void | Promise<void>;
@@ -3,44 +3,93 @@ import { isPromise } from "../util.js";
3
3
  import { isAstroComponentInstance, isRenderTemplateResult } from "./astro/index.js";
4
4
  import { isRenderInstance } from "./common.js";
5
5
  import { SlotString } from "./slot.js";
6
- import { renderToBufferDestination } from "./util.js";
7
- async function renderChild(destination, child) {
6
+ import { createBufferedRenderer } from "./util.js";
7
+ function renderChild(destination, child) {
8
8
  if (isPromise(child)) {
9
- child = await child;
9
+ return child.then((x) => renderChild(destination, x));
10
10
  }
11
11
  if (child instanceof SlotString) {
12
12
  destination.write(child);
13
- } else if (isHTMLString(child)) {
13
+ return;
14
+ }
15
+ if (isHTMLString(child)) {
14
16
  destination.write(child);
15
- } else if (Array.isArray(child)) {
16
- const childRenders = child.map((c) => {
17
- return renderToBufferDestination((bufferDestination) => {
18
- return renderChild(bufferDestination, c);
19
- });
20
- });
21
- for (const childRender of childRenders) {
22
- if (!childRender) continue;
23
- await childRender.renderToFinalDestination(destination);
24
- }
25
- } else if (typeof child === "function") {
26
- await renderChild(destination, child());
27
- } else if (typeof child === "string") {
17
+ return;
18
+ }
19
+ if (Array.isArray(child)) {
20
+ return renderArray(destination, child);
21
+ }
22
+ if (typeof child === "function") {
23
+ return renderChild(destination, child());
24
+ }
25
+ if (!child && child !== 0) {
26
+ return;
27
+ }
28
+ if (typeof child === "string") {
28
29
  destination.write(markHTMLString(escapeHTML(child)));
29
- } else if (!child && child !== 0) {
30
- } else if (isRenderInstance(child)) {
31
- await child.render(destination);
32
- } else if (isRenderTemplateResult(child)) {
33
- await child.render(destination);
34
- } else if (isAstroComponentInstance(child)) {
35
- await child.render(destination);
36
- } else if (ArrayBuffer.isView(child)) {
30
+ return;
31
+ }
32
+ if (isRenderInstance(child)) {
33
+ return child.render(destination);
34
+ }
35
+ if (isRenderTemplateResult(child)) {
36
+ return child.render(destination);
37
+ }
38
+ if (isAstroComponentInstance(child)) {
39
+ return child.render(destination);
40
+ }
41
+ if (ArrayBuffer.isView(child)) {
37
42
  destination.write(child);
38
- } else if (typeof child === "object" && (Symbol.asyncIterator in child || Symbol.iterator in child)) {
39
- for await (const value of child) {
40
- await renderChild(destination, value);
43
+ return;
44
+ }
45
+ if (typeof child === "object" && (Symbol.asyncIterator in child || Symbol.iterator in child)) {
46
+ if (Symbol.asyncIterator in child) {
47
+ return renderAsyncIterable(destination, child);
41
48
  }
42
- } else {
43
- destination.write(child);
49
+ return renderIterable(destination, child);
50
+ }
51
+ destination.write(child);
52
+ }
53
+ function renderArray(destination, children) {
54
+ const flushers = children.map((c) => {
55
+ return createBufferedRenderer(destination, (bufferDestination) => {
56
+ return renderChild(bufferDestination, c);
57
+ });
58
+ });
59
+ const iterator = flushers[Symbol.iterator]();
60
+ const iterate = () => {
61
+ for (; ; ) {
62
+ const { value: flusher, done } = iterator.next();
63
+ if (done) {
64
+ break;
65
+ }
66
+ const result = flusher.flush();
67
+ if (isPromise(result)) {
68
+ return result.then(iterate);
69
+ }
70
+ }
71
+ };
72
+ return iterate();
73
+ }
74
+ function renderIterable(destination, children) {
75
+ const iterator = children[Symbol.iterator]();
76
+ const iterate = () => {
77
+ for (; ; ) {
78
+ const { value, done } = iterator.next();
79
+ if (done) {
80
+ break;
81
+ }
82
+ const result = renderChild(destination, value);
83
+ if (isPromise(result)) {
84
+ return result.then(iterate);
85
+ }
86
+ }
87
+ };
88
+ return iterate();
89
+ }
90
+ async function renderAsyncIterable(destination, children) {
91
+ for await (const value of children) {
92
+ await renderChild(destination, value);
44
93
  }
45
94
  }
46
95
  export {
@@ -1,5 +1,5 @@
1
1
  import type { ComponentSlots } from '../slot.js';
2
- import type { AstroComponentFactory } from './factory.js';
2
+ import type { AstroComponentFactory, AstroFactoryReturnValue } from './factory.js';
3
3
  import type { SSRResult } from '../../../../types/public/internal.js';
4
4
  import type { RenderDestination } from '../common.js';
5
5
  type ComponentProps = Record<string | number, any>;
@@ -12,8 +12,9 @@ export declare class AstroComponentInstance {
12
12
  private readonly factory;
13
13
  private returnValue;
14
14
  constructor(result: SSRResult, props: ComponentProps, slots: ComponentSlots, factory: AstroComponentFactory);
15
- init(result: SSRResult): Promise<import("./factory.js").AstroFactoryReturnValue>;
16
- render(destination: RenderDestination): Promise<void>;
15
+ init(result: SSRResult): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
16
+ render(destination: RenderDestination): void | Promise<void>;
17
+ private renderImpl;
17
18
  }
18
19
  export declare function createAstroComponentInstance(result: SSRResult, displayName: string, factory: AstroComponentFactory, props: ComponentProps, slots?: any): AstroComponentInstance;
19
20
  export declare function isAstroComponentInstance(obj: unknown): obj is AstroComponentInstance;
@@ -27,8 +27,10 @@ class AstroComponentInstance {
27
27
  };
28
28
  }
29
29
  }
30
- async init(result) {
31
- if (this.returnValue !== void 0) return this.returnValue;
30
+ init(result) {
31
+ if (this.returnValue !== void 0) {
32
+ return this.returnValue;
33
+ }
32
34
  this.returnValue = this.factory(result, this.props, this.slotValues);
33
35
  if (isPromise(this.returnValue)) {
34
36
  this.returnValue.then((resolved) => {
@@ -38,12 +40,18 @@ class AstroComponentInstance {
38
40
  }
39
41
  return this.returnValue;
40
42
  }
41
- async render(destination) {
42
- const returnValue = await this.init(this.result);
43
+ render(destination) {
44
+ const returnValue = this.init(this.result);
45
+ if (isPromise(returnValue)) {
46
+ return returnValue.then((x) => this.renderImpl(destination, x));
47
+ }
48
+ return this.renderImpl(destination, returnValue);
49
+ }
50
+ renderImpl(destination, returnValue) {
43
51
  if (isHeadAndContent(returnValue)) {
44
- await returnValue.content.render(destination);
52
+ return returnValue.content.render(destination);
45
53
  } else {
46
- await renderChild(destination, returnValue);
54
+ return renderChild(destination, returnValue);
47
55
  }
48
56
  }
49
57
  }
@@ -6,7 +6,7 @@ export declare class RenderTemplateResult {
6
6
  expressions: any[];
7
7
  private error;
8
8
  constructor(htmlParts: TemplateStringsArray, expressions: unknown[]);
9
- render(destination: RenderDestination): Promise<void>;
9
+ render(destination: RenderDestination): void | Promise<void>;
10
10
  }
11
11
  export declare function isRenderTemplateResult(obj: unknown): obj is RenderTemplateResult;
12
12
  export declare function renderTemplate(htmlParts: TemplateStringsArray, ...expressions: any[]): RenderTemplateResult;
@@ -1,7 +1,7 @@
1
1
  import { markHTMLString } from "../../escape.js";
2
2
  import { isPromise } from "../../util.js";
3
3
  import { renderChild } from "../any.js";
4
- import { renderToBufferDestination } from "../util.js";
4
+ import { createBufferedRenderer } from "../util.js";
5
5
  const renderTemplateResultSym = Symbol.for("astro.renderTemplateResult");
6
6
  class RenderTemplateResult {
7
7
  [renderTemplateResultSym] = true;
@@ -23,22 +23,32 @@ class RenderTemplateResult {
23
23
  return expression;
24
24
  });
25
25
  }
26
- async render(destination) {
27
- const expRenders = this.expressions.map((exp) => {
28
- return renderToBufferDestination((bufferDestination) => {
26
+ render(destination) {
27
+ const flushers = this.expressions.map((exp) => {
28
+ return createBufferedRenderer(destination, (bufferDestination) => {
29
29
  if (exp || exp === 0) {
30
30
  return renderChild(bufferDestination, exp);
31
31
  }
32
32
  });
33
33
  });
34
- for (let i = 0; i < this.htmlParts.length; i++) {
35
- const html = this.htmlParts[i];
36
- const expRender = expRenders[i];
37
- destination.write(markHTMLString(html));
38
- if (expRender) {
39
- await expRender.renderToFinalDestination(destination);
34
+ let i = 0;
35
+ const iterate = () => {
36
+ while (i < this.htmlParts.length) {
37
+ const html = this.htmlParts[i];
38
+ const flusher = flushers[i];
39
+ i++;
40
+ if (html) {
41
+ destination.write(markHTMLString(html));
42
+ }
43
+ if (flusher) {
44
+ const result = flusher.flush();
45
+ if (isPromise(result)) {
46
+ return result.then(iterate);
47
+ }
48
+ }
40
49
  }
41
- }
50
+ };
51
+ return iterate();
42
52
  }
43
53
  }
44
54
  function isRenderTemplateResult(obj) {