astro 5.2.6 → 5.3.1

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 (43) hide show
  1. package/dist/container/index.js +1 -0
  2. package/dist/content/content-layer.js +3 -3
  3. package/dist/content/loaders/glob.js +6 -5
  4. package/dist/content/runtime-assets.d.ts +1 -1
  5. package/dist/content/types-generator.js +6 -11
  6. package/dist/content/vite-plugin-content-virtual-mod.js +2 -2
  7. package/dist/core/app/middlewares.js +5 -4
  8. package/dist/core/app/types.d.ts +7 -0
  9. package/dist/core/build/generate.js +1 -0
  10. package/dist/core/build/plugins/plugin-manifest.js +4 -5
  11. package/dist/core/build/static-build.d.ts +0 -1
  12. package/dist/core/build/static-build.js +4 -23
  13. package/dist/core/config/schema.d.ts +278 -312
  14. package/dist/core/config/schema.js +22 -22
  15. package/dist/core/constants.js +1 -1
  16. package/dist/core/create-vite.js +2 -2
  17. package/dist/core/dev/dev.js +1 -1
  18. package/dist/core/errors/errors-data.d.ts +74 -28
  19. package/dist/core/errors/errors-data.js +33 -12
  20. package/dist/core/messages.js +2 -2
  21. package/dist/core/render-context.js +1 -0
  22. package/dist/core/routing/rewrite.js +15 -2
  23. package/dist/core/session.d.ts +3 -1
  24. package/dist/core/session.js +37 -8
  25. package/dist/integrations/hooks.js +2 -0
  26. package/dist/runtime/server/endpoint.js +8 -2
  27. package/dist/runtime/server/render/any.d.ts +1 -1
  28. package/dist/runtime/server/render/any.js +79 -30
  29. package/dist/runtime/server/render/astro/instance.d.ts +4 -3
  30. package/dist/runtime/server/render/astro/instance.js +14 -6
  31. package/dist/runtime/server/render/astro/render-template.d.ts +1 -1
  32. package/dist/runtime/server/render/astro/render-template.js +21 -11
  33. package/dist/runtime/server/render/astro/render.js +12 -5
  34. package/dist/runtime/server/render/component.d.ts +1 -1
  35. package/dist/runtime/server/render/component.js +9 -7
  36. package/dist/runtime/server/render/head.js +3 -0
  37. package/dist/runtime/server/render/script.js +3 -1
  38. package/dist/runtime/server/render/util.d.ts +13 -7
  39. package/dist/runtime/server/render/util.js +23 -12
  40. package/dist/types/public/config.d.ts +33 -21
  41. package/dist/types/public/internal.d.ts +1 -0
  42. package/dist/vite-plugin-astro-server/plugin.js +2 -1
  43. package/package.json +4 -4
@@ -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) {
@@ -1,4 +1,5 @@
1
1
  import { AstroError, AstroErrorData } from "../../../../core/errors/index.js";
2
+ import { isPromise } from "../../util.js";
2
3
  import { chunkToByteArray, chunkToString, encoder } from "../common.js";
3
4
  import { promiseWithResolvers } from "../util.js";
4
5
  import { isHeadAndContent } from "./head-and-content.js";
@@ -206,12 +207,10 @@ async function renderToAsyncIterable(result, componentFactory, props, children,
206
207
  }
207
208
  }
208
209
  };
209
- const renderPromise = templateResult.render(destination);
210
- renderPromise.then(() => {
211
- renderingComplete = true;
212
- next?.resolve();
213
- }).catch((err) => {
210
+ const renderResult = toPromise(() => templateResult.render(destination));
211
+ renderResult.catch((err) => {
214
212
  error = err;
213
+ }).finally(() => {
215
214
  renderingComplete = true;
216
215
  next?.resolve();
217
216
  });
@@ -221,6 +220,14 @@ async function renderToAsyncIterable(result, componentFactory, props, children,
221
220
  }
222
221
  };
223
222
  }
223
+ function toPromise(fn) {
224
+ try {
225
+ const result = fn();
226
+ return isPromise(result) ? result : Promise.resolve(result);
227
+ } catch (err) {
228
+ return Promise.reject(err);
229
+ }
230
+ }
224
231
  export {
225
232
  renderToAsyncIterable,
226
233
  renderToReadableStream,
@@ -2,7 +2,7 @@ import type { RouteData, SSRResult } from '../../../types/public/internal.js';
2
2
  import { type RenderInstance } from './common.js';
3
3
  import { type ComponentSlots } from './slot.js';
4
4
  declare const needsHeadRenderingSymbol: unique symbol;
5
- export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: ComponentSlots): Promise<RenderInstance>;
5
+ export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: ComponentSlots): RenderInstance | Promise<RenderInstance>;
6
6
  export declare function renderComponentToString(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: any, isPage?: boolean, route?: RouteData): Promise<string>;
7
7
  export type NonAstroPageComponent = {
8
8
  name: string;
@@ -346,26 +346,28 @@ function renderAstroComponent(result, displayName, Component, props, slots = {})
346
346
  }
347
347
  const instance = createAstroComponentInstance(result, displayName, Component, props, slots);
348
348
  return {
349
- async render(destination) {
350
- await instance.render(destination);
349
+ render(destination) {
350
+ return instance.render(destination);
351
351
  }
352
352
  };
353
353
  }
354
- async function renderComponent(result, displayName, Component, props, slots = {}) {
354
+ function renderComponent(result, displayName, Component, props, slots = {}) {
355
355
  if (isPromise(Component)) {
356
- Component = await Component.catch(handleCancellation);
356
+ return Component.catch(handleCancellation).then((x) => {
357
+ return renderComponent(result, displayName, x, props, slots);
358
+ });
357
359
  }
358
360
  if (isFragmentComponent(Component)) {
359
- return await renderFragmentComponent(result, slots).catch(handleCancellation);
361
+ return renderFragmentComponent(result, slots).catch(handleCancellation);
360
362
  }
361
363
  props = normalizeProps(props);
362
364
  if (isHTMLComponent(Component)) {
363
- return await renderHTMLComponent(result, Component, props, slots).catch(handleCancellation);
365
+ return renderHTMLComponent(result, Component, props, slots).catch(handleCancellation);
364
366
  }
365
367
  if (isAstroComponentFactory(Component)) {
366
368
  return renderAstroComponent(result, displayName, Component, props, slots);
367
369
  }
368
- return await renderFrameworkComponent(result, displayName, Component, props, slots).catch(
370
+ return renderFrameworkComponent(result, displayName, Component, props, slots).catch(
369
371
  handleCancellation
370
372
  );
371
373
  function handleCancellation(e) {
@@ -13,6 +13,9 @@ function renderAllHeadContent(result) {
13
13
  );
14
14
  result.styles.clear();
15
15
  const scripts = Array.from(result.scripts).filter(uniqueElements).map((script) => {
16
+ if (result.userAssetsBase) {
17
+ script.props.src = (result.base === "/" ? "" : result.base) + result.userAssetsBase + script.props.src;
18
+ }
16
19
  return renderElement("script", script, false);
17
20
  });
18
21
  const links = Array.from(result.links).filter(uniqueElements).map((link) => renderElement("link", link, false));
@@ -11,7 +11,9 @@ async function renderScript(result, id) {
11
11
  }
12
12
  }
13
13
  const resolved = await result.resolve(id);
14
- return markHTMLString(`<script type="module" src="${resolved}"></script>`);
14
+ return markHTMLString(
15
+ `<script type="module" src="${result.userAssetsBase ? (result.base === "/" ? "" : result.base) + result.userAssetsBase : ""}${resolved}"></script>`
16
+ );
15
17
  }
16
18
  export {
17
19
  renderScript
@@ -1,4 +1,4 @@
1
- import type { RenderFunction } from './common.js';
1
+ import type { RenderDestination, RenderFunction } from './common.js';
2
2
  import type { SSRElement } from '../../../types/public/internal.js';
3
3
  export declare const voidElementNames: RegExp;
4
4
  export declare const toAttributeString: (value: any, shouldEscape?: boolean) => any;
@@ -10,26 +10,32 @@ export declare function internalSpreadAttributes(values: Record<any, any>, shoul
10
10
  export declare function renderElement(name: string, { props: _props, children }: SSRElement, shouldEscape?: boolean): string;
11
11
  /**
12
12
  * Executes the `bufferRenderFunction` to prerender it into a buffer destination, and return a promise
13
- * with an object containing the `renderToFinalDestination` function to flush the buffer to the final
13
+ * with an object containing the `flush` function to flush the buffer to the final
14
14
  * destination.
15
15
  *
16
16
  * @example
17
17
  * ```ts
18
18
  * // Render components in parallel ahead of time
19
19
  * const finalRenders = [ComponentA, ComponentB].map((comp) => {
20
- * return renderToBufferDestination(async (bufferDestination) => {
20
+ * return createBufferedRenderer(finalDestination, async (bufferDestination) => {
21
21
  * await renderComponentToDestination(bufferDestination);
22
22
  * });
23
23
  * });
24
24
  * // Render array of components serially
25
25
  * for (const finalRender of finalRenders) {
26
- * await finalRender.renderToFinalDestination(finalDestination);
26
+ * await finalRender.flush();
27
27
  * }
28
28
  * ```
29
29
  */
30
- export declare function renderToBufferDestination(bufferRenderFunction: RenderFunction): {
31
- renderToFinalDestination: RenderFunction;
32
- };
30
+ export declare function createBufferedRenderer(destination: RenderDestination, renderFunction: RenderFunction): RendererFlusher;
31
+ export interface RendererFlusher {
32
+ /**
33
+ * Flushes the current renderer to the underlying renderer.
34
+ *
35
+ * See example of `createBufferedRenderer` for usage.
36
+ */
37
+ flush(): void | Promise<void>;
38
+ }
33
39
  export declare const isNode: boolean;
34
40
  export declare const isDeno: boolean;
35
41
  export type PromiseWithResolvers<T> = {
@@ -1,5 +1,6 @@
1
1
  import { clsx } from "clsx";
2
2
  import { HTMLString, markHTMLString } from "../escape.js";
3
+ import { isPromise } from "../util.js";
3
4
  const voidElementNames = /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i;
4
5
  const htmlBooleanAttributes = /^(?:allowfullscreen|async|autofocus|autoplay|checked|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|hidden|inert|loop|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|selected|itemscope)$/i;
5
6
  const AMPERSAND_REGEX = /&/g;
@@ -103,28 +104,38 @@ class BufferedRenderer {
103
104
  chunks = [];
104
105
  renderPromise;
105
106
  destination;
106
- constructor(bufferRenderFunction) {
107
- this.renderPromise = bufferRenderFunction(this);
108
- Promise.resolve(this.renderPromise).catch(noop);
107
+ /**
108
+ * Determines whether buffer has been flushed
109
+ * to the final destination.
110
+ */
111
+ flushed = false;
112
+ constructor(destination, renderFunction) {
113
+ this.destination = destination;
114
+ this.renderPromise = renderFunction(this);
115
+ if (isPromise(this.renderPromise)) {
116
+ Promise.resolve(this.renderPromise).catch(noop);
117
+ }
109
118
  }
110
119
  write(chunk) {
111
- if (this.destination) {
120
+ if (this.flushed) {
112
121
  this.destination.write(chunk);
113
122
  } else {
114
123
  this.chunks.push(chunk);
115
124
  }
116
125
  }
117
- async renderToFinalDestination(destination) {
126
+ flush() {
127
+ if (this.flushed) {
128
+ throw new Error("The render buffer has already been flushed.");
129
+ }
130
+ this.flushed = true;
118
131
  for (const chunk of this.chunks) {
119
- destination.write(chunk);
132
+ this.destination.write(chunk);
120
133
  }
121
- this.destination = destination;
122
- await this.renderPromise;
134
+ return this.renderPromise;
123
135
  }
124
136
  }
125
- function renderToBufferDestination(bufferRenderFunction) {
126
- const renderer = new BufferedRenderer(bufferRenderFunction);
127
- return renderer;
137
+ function createBufferedRenderer(destination, renderFunction) {
138
+ return new BufferedRenderer(destination, renderFunction);
128
139
  }
129
140
  const isNode = typeof process !== "undefined" && Object.prototype.toString.call(process) === "[object process]";
130
141
  const isDeno = typeof Deno !== "undefined";
@@ -151,6 +162,7 @@ function isHttpUrl(url) {
151
162
  }
152
163
  export {
153
164
  addAttribute,
165
+ createBufferedRenderer,
154
166
  defineScriptVars,
155
167
  formatList,
156
168
  internalSpreadAttributes,
@@ -158,7 +170,6 @@ export {
158
170
  isNode,
159
171
  promiseWithResolvers,
160
172
  renderElement,
161
- renderToBufferDestination,
162
173
  toAttributeString,
163
174
  toStyleString,
164
175
  voidElementNames
@@ -495,6 +495,35 @@ export interface ViteUserConfig extends OriginalViteUserConfig {
495
495
  */
496
496
  checkOrigin?: boolean;
497
497
  };
498
+ /**
499
+ * @docs
500
+ * @name session
501
+ * @type {SessionConfig}
502
+ * @version 5.3.0
503
+ * @description
504
+ *
505
+ * Configures experimental session support by specifying a storage `driver` as well as any associated `options`.
506
+ * You must enable the `experimental.session` flag to use this feature.
507
+ * Some adapters may provide a default session driver, but you can override it with your own configuration.
508
+ *
509
+ * You can specify [any driver from Unstorage](https://unstorage.unjs.io/drivers) or provide a custom config which will override your adapter's default.
510
+ *
511
+ * See [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information.
512
+ *
513
+ * ```js title="astro.config.mjs"
514
+ * {
515
+ * session: {
516
+ * // Required: the name of the Unstorage driver
517
+ * driver: 'redis',
518
+ * // The required options depend on the driver
519
+ * options: {
520
+ * url: process.env.REDIS_URL,
521
+ * },
522
+ * }
523
+ * }
524
+ * ```
525
+ */
526
+ session?: SessionConfig<TSession>;
498
527
  /**
499
528
  * @docs
500
529
  * @name vite
@@ -1864,7 +1893,8 @@ export interface ViteUserConfig extends OriginalViteUserConfig {
1864
1893
  /**
1865
1894
  *
1866
1895
  * @name experimental.session
1867
- * @type {SessionConfig}
1896
+ * @type {boolean}
1897
+ * @default `false`
1868
1898
  * @version 5.0.0
1869
1899
  * @description
1870
1900
  *
@@ -1881,29 +1911,11 @@ export interface ViteUserConfig extends OriginalViteUserConfig {
1881
1911
  * <a href="/checkout">🛒 {cart?.length ?? 0} items</a>
1882
1912
  *
1883
1913
  * ```
1884
- * The object configures session management for your Astro site by specifying a `driver` as well as any `options` for your data storage.
1885
- *
1886
- * You can specify [any driver from Unstorage](https://unstorage.unjs.io/drivers) or provide a custom config which will override your adapter's default.
1887
- *
1888
- * ```js title="astro.config.mjs"
1889
- * {
1890
- * experimental: {
1891
- * session: {
1892
- * // Required: the name of the Unstorage driver
1893
- * driver: "redis",
1894
- * // The required options depend on the driver
1895
- * options: {
1896
- * url: process.env.REDIS_URL,
1897
- * }
1898
- * }
1899
- * },
1900
- * }
1901
- * ```
1902
1914
  *
1903
- * For more details, see [the Sessions RFC](https://github.com/withastro/roadmap/blob/sessions/proposals/0054-sessions.md).
1915
+ * For more details, see [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/).
1904
1916
  *
1905
1917
  */
1906
- session?: SessionConfig<TSession>;
1918
+ session?: boolean;
1907
1919
  /**
1908
1920
  *
1909
1921
  * @name experimental.svg
@@ -195,6 +195,7 @@ export interface SSRResult {
195
195
  */
196
196
  cancelled: boolean;
197
197
  base: string;
198
+ userAssetsBase: string | undefined;
198
199
  styles: Set<SSRElement>;
199
200
  scripts: Set<SSRElement>;
200
201
  links: Set<SSRElement>;
@@ -150,6 +150,7 @@ function createDevelopmentManifest(settings) {
150
150
  clientDirectives: settings.clientDirectives,
151
151
  renderers: [],
152
152
  base: settings.config.base,
153
+ userAssetsBase: settings.config?.vite?.base,
153
154
  assetsPrefix: settings.config.build.assetsPrefix,
154
155
  site: settings.config.site,
155
156
  componentMetadata: /* @__PURE__ */ new Map(),
@@ -162,7 +163,7 @@ function createDevelopmentManifest(settings) {
162
163
  onRequest: NOOP_MIDDLEWARE_FN
163
164
  };
164
165
  },
165
- sessionConfig: settings.config.experimental.session
166
+ sessionConfig: settings.config.experimental.session ? settings.config.session : void 0
166
167
  };
167
168
  }
168
169
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "5.2.6",
3
+ "version": "5.3.1",
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",
@@ -125,7 +125,6 @@
125
125
  "es-module-lexer": "^1.6.0",
126
126
  "esbuild": "^0.24.2",
127
127
  "estree-walker": "^3.0.3",
128
- "fast-glob": "^3.3.3",
129
128
  "flattie": "^1.1.1",
130
129
  "github-slugger": "^2.0.0",
131
130
  "html-escaper": "3.0.3",
@@ -134,17 +133,18 @@
134
133
  "kleur": "^4.1.5",
135
134
  "magic-string": "^0.30.17",
136
135
  "magicast": "^0.3.5",
137
- "micromatch": "^4.0.8",
138
136
  "mrmime": "^2.0.0",
139
137
  "neotraverse": "^0.6.18",
140
138
  "p-limit": "^6.2.0",
141
139
  "p-queue": "^8.1.0",
140
+ "picomatch": "^4.0.2",
142
141
  "preferred-pm": "^4.1.1",
143
142
  "prompts": "^2.4.2",
144
143
  "rehype": "^13.0.2",
145
144
  "semver": "^7.7.1",
146
145
  "shiki": "^1.29.2",
147
146
  "tinyexec": "^0.3.2",
147
+ "tinyglobby": "^0.2.12",
148
148
  "tsconfck": "^3.1.4",
149
149
  "ultrahtml": "^1.5.3",
150
150
  "unist-util-visit": "^5.0.0",
@@ -179,7 +179,7 @@
179
179
  "@types/html-escaper": "3.0.4",
180
180
  "@types/http-cache-semantics": "^4.0.4",
181
181
  "@types/js-yaml": "^4.0.9",
182
- "@types/micromatch": "^4.0.9",
182
+ "@types/picomatch": "^3.0.2",
183
183
  "@types/prompts": "^2.4.9",
184
184
  "@types/semver": "^7.5.8",
185
185
  "@types/yargs-parser": "^21.0.3",