astro 1.2.8 → 1.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 (50) hide show
  1. package/dist/@types/astro.d.ts +3 -0
  2. package/dist/cli/check/index.js +7 -2
  3. package/dist/cli/check/print.js +1 -2
  4. package/dist/cli/index.js +1 -1
  5. package/dist/core/build/generate.js +6 -0
  6. package/dist/core/build/index.js +9 -0
  7. package/dist/core/build/static-build.js +31 -11
  8. package/dist/core/config/schema.d.ts +12 -12
  9. package/dist/core/dev/index.js +7 -8
  10. package/dist/core/endpoint/index.js +1 -1
  11. package/dist/core/messages.d.ts +10 -6
  12. package/dist/core/messages.js +57 -32
  13. package/dist/core/path.d.ts +1 -0
  14. package/dist/core/path.js +4 -0
  15. package/dist/core/preview/index.js +8 -5
  16. package/dist/core/render/route-cache.js +1 -4
  17. package/dist/core/routing/params.js +1 -1
  18. package/dist/core/util.d.ts +1 -1
  19. package/dist/core/util.js +2 -2
  20. package/dist/integrations/index.d.ts +5 -0
  21. package/dist/integrations/index.js +18 -0
  22. package/dist/runtime/server/astro-global.js +1 -1
  23. package/dist/runtime/server/astro-island.js +4 -1
  24. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  25. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  26. package/dist/runtime/server/endpoint.d.ts +1 -1
  27. package/dist/runtime/server/endpoint.js +5 -1
  28. package/dist/runtime/server/escape.d.ts +8 -1
  29. package/dist/runtime/server/escape.js +47 -4
  30. package/dist/runtime/server/hydration.js +3 -1
  31. package/dist/runtime/server/index.d.ts +1 -1
  32. package/dist/runtime/server/index.js +2 -1
  33. package/dist/runtime/server/jsx.js +4 -5
  34. package/dist/runtime/server/render/any.js +3 -1
  35. package/dist/runtime/server/render/astro.d.ts +3 -2
  36. package/dist/runtime/server/render/astro.js +4 -4
  37. package/dist/runtime/server/render/common.d.ts +12 -0
  38. package/dist/runtime/server/render/common.js +55 -0
  39. package/dist/runtime/server/render/component.d.ts +2 -1
  40. package/dist/runtime/server/render/page.js +22 -17
  41. package/dist/runtime/server/render/util.js +2 -2
  42. package/dist/runtime/server/response.js +1 -1
  43. package/dist/runtime/server/serialize.js +13 -1
  44. package/dist/runtime/server/util.d.ts +1 -0
  45. package/dist/runtime/server/util.js +4 -6
  46. package/dist/vite-plugin-astro/hmr.js +3 -2
  47. package/dist/vite-plugin-jsx/tag.js +52 -20
  48. package/dist/vite-plugin-markdown/index.js +6 -1
  49. package/dist/vite-plugin-utils/index.js +4 -1
  50. package/package.json +5 -4
@@ -198,6 +198,23 @@ async function runHookBuildSsr({
198
198
  }
199
199
  }
200
200
  }
201
+ async function runHookBuildGenerated({
202
+ config,
203
+ buildConfig,
204
+ logging
205
+ }) {
206
+ var _a;
207
+ const dir = config.output === "server" ? buildConfig.client : config.outDir;
208
+ for (const integration of config.integrations) {
209
+ if ((_a = integration == null ? void 0 : integration.hooks) == null ? void 0 : _a["astro:build:generated"]) {
210
+ await withTakingALongTimeMsg({
211
+ name: integration.name,
212
+ hookResult: integration.hooks["astro:build:generated"]({ dir }),
213
+ logging
214
+ });
215
+ }
216
+ }
217
+ }
201
218
  async function runHookBuildDone({
202
219
  config,
203
220
  buildConfig,
@@ -223,6 +240,7 @@ async function runHookBuildDone({
223
240
  }
224
241
  export {
225
242
  runHookBuildDone,
243
+ runHookBuildGenerated,
226
244
  runHookBuildSetup,
227
245
  runHookBuildSsr,
228
246
  runHookBuildStart,
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "1.2.8";
1
+ const ASTRO_VERSION = "1.3.1";
2
2
  function createDeprecatedFetchContentFn() {
3
3
  return () => {
4
4
  throw new Error("Deprecated: Astro.fetchContent() has been replaced with Astro.glob().");
@@ -8,7 +8,10 @@ var _a;
8
8
  4: (value) => new Map(JSON.parse(value, reviver)),
9
9
  5: (value) => new Set(JSON.parse(value, reviver)),
10
10
  6: (value) => BigInt(value),
11
- 7: (value) => new URL(value)
11
+ 7: (value) => new URL(value),
12
+ 8: (value) => new Uint8Array(JSON.parse(value)),
13
+ 9: (value) => new Uint16Array(JSON.parse(value)),
14
+ 10: (value) => new Uint32Array(JSON.parse(value))
12
15
  };
13
16
  const reviver = (propKey, raw) => {
14
17
  if (propKey === "" || !Array.isArray(raw))
@@ -3,5 +3,5 @@
3
3
  * Do not edit this directly, but instead edit that file and rerun the prebuild
4
4
  * to generate this file.
5
5
  */
6
- declare const _default: "var l;{const c={0:t=>t,1:t=>JSON.parse(t,o),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,o)),5:t=>new Set(JSON.parse(t,o)),6:t=>BigInt(t),7:t=>new URL(t)},o=(t,s)=>{if(t===\"\"||!Array.isArray(s))return s;const[e,n]=s;return e in c?c[e](n):void 0};customElements.get(\"astro-island\")||customElements.define(\"astro-island\",(l=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement&&this.parentElement.closest(\"astro-island[ssr]\"))return;const s=this.querySelectorAll(\"astro-slot\"),e={},n=this.querySelectorAll(\"template[data-astro-template]\");for(const r of n){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute(\"data-astro-template\")||\"default\"]=r.innerHTML,r.remove())}for(const r of s){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute(\"name\")||\"default\"]=r.innerHTML)}const a=this.hasAttribute(\"props\")?JSON.parse(this.getAttribute(\"props\"),o):{};this.hydrator(this)(this.Component,a,e,{client:this.getAttribute(\"client\")}),this.removeAttribute(\"ssr\"),window.removeEventListener(\"astro:hydrate\",this.hydrate),window.dispatchEvent(new CustomEvent(\"astro:hydrate\"))}}connectedCallback(){!this.hasAttribute(\"await-children\")||this.firstChild?this.childrenConnectedCallback():new MutationObserver((s,e)=>{e.disconnect(),this.childrenConnectedCallback()}).observe(this,{childList:!0})}async childrenConnectedCallback(){window.addEventListener(\"astro:hydrate\",this.hydrate);let s=this.getAttribute(\"before-hydration-url\");s&&await import(s),this.start()}start(){const s=JSON.parse(this.getAttribute(\"opts\")),e=this.getAttribute(\"client\");if(Astro[e]===void 0){window.addEventListener(`astro:${e}`,()=>this.start(),{once:!0});return}Astro[e](async()=>{const n=this.getAttribute(\"renderer-url\"),[a,{default:r}]=await Promise.all([import(this.getAttribute(\"component-url\")),n?import(n):()=>()=>{}]),i=this.getAttribute(\"component-export\")||\"default\";if(!i.includes(\".\"))this.Component=a[i];else{this.Component=a;for(const d of i.split(\".\"))this.Component=this.Component[d]}return this.hydrator=r,this.hydrate},s,this)}attributeChangedCallback(){this.hydrator&&this.hydrate()}},l.observedAttributes=[\"props\"],l))}";
6
+ declare const _default: "var l;{const c={0:t=>t,1:t=>JSON.parse(t,o),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,o)),5:t=>new Set(JSON.parse(t,o)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(JSON.parse(t)),9:t=>new Uint16Array(JSON.parse(t)),10:t=>new Uint32Array(JSON.parse(t))},o=(t,s)=>{if(t===\"\"||!Array.isArray(s))return s;const[e,n]=s;return e in c?c[e](n):void 0};customElements.get(\"astro-island\")||customElements.define(\"astro-island\",(l=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement&&this.parentElement.closest(\"astro-island[ssr]\"))return;const s=this.querySelectorAll(\"astro-slot\"),e={},n=this.querySelectorAll(\"template[data-astro-template]\");for(const r of n){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute(\"data-astro-template\")||\"default\"]=r.innerHTML,r.remove())}for(const r of s){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute(\"name\")||\"default\"]=r.innerHTML)}const a=this.hasAttribute(\"props\")?JSON.parse(this.getAttribute(\"props\"),o):{};this.hydrator(this)(this.Component,a,e,{client:this.getAttribute(\"client\")}),this.removeAttribute(\"ssr\"),window.removeEventListener(\"astro:hydrate\",this.hydrate),window.dispatchEvent(new CustomEvent(\"astro:hydrate\"))}}connectedCallback(){!this.hasAttribute(\"await-children\")||this.firstChild?this.childrenConnectedCallback():new MutationObserver((s,e)=>{e.disconnect(),this.childrenConnectedCallback()}).observe(this,{childList:!0})}async childrenConnectedCallback(){window.addEventListener(\"astro:hydrate\",this.hydrate);let s=this.getAttribute(\"before-hydration-url\");s&&await import(s),this.start()}start(){const s=JSON.parse(this.getAttribute(\"opts\")),e=this.getAttribute(\"client\");if(Astro[e]===void 0){window.addEventListener(`astro:${e}`,()=>this.start(),{once:!0});return}Astro[e](async()=>{const n=this.getAttribute(\"renderer-url\"),[a,{default:r}]=await Promise.all([import(this.getAttribute(\"component-url\")),n?import(n):()=>()=>{}]),i=this.getAttribute(\"component-export\")||\"default\";if(!i.includes(\".\"))this.Component=a[i];else{this.Component=a;for(const d of i.split(\".\"))this.Component=this.Component[d]}return this.hydrator=r,this.hydrate},s,this)}attributeChangedCallback(){this.hydrator&&this.hydrate()}},l.observedAttributes=[\"props\"],l))}";
7
7
  export default _default;
@@ -1,4 +1,4 @@
1
- var astro_island_prebuilt_default = `var l;{const c={0:t=>t,1:t=>JSON.parse(t,o),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,o)),5:t=>new Set(JSON.parse(t,o)),6:t=>BigInt(t),7:t=>new URL(t)},o=(t,s)=>{if(t===""||!Array.isArray(s))return s;const[e,n]=s;return e in c?c[e](n):void 0};customElements.get("astro-island")||customElements.define("astro-island",(l=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement&&this.parentElement.closest("astro-island[ssr]"))return;const s=this.querySelectorAll("astro-slot"),e={},n=this.querySelectorAll("template[data-astro-template]");for(const r of n){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute("data-astro-template")||"default"]=r.innerHTML,r.remove())}for(const r of s){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute("name")||"default"]=r.innerHTML)}const a=this.hasAttribute("props")?JSON.parse(this.getAttribute("props"),o):{};this.hydrator(this)(this.Component,a,e,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),window.removeEventListener("astro:hydrate",this.hydrate),window.dispatchEvent(new CustomEvent("astro:hydrate"))}}connectedCallback(){!this.hasAttribute("await-children")||this.firstChild?this.childrenConnectedCallback():new MutationObserver((s,e)=>{e.disconnect(),this.childrenConnectedCallback()}).observe(this,{childList:!0})}async childrenConnectedCallback(){window.addEventListener("astro:hydrate",this.hydrate);let s=this.getAttribute("before-hydration-url");s&&await import(s),this.start()}start(){const s=JSON.parse(this.getAttribute("opts")),e=this.getAttribute("client");if(Astro[e]===void 0){window.addEventListener(\`astro:\${e}\`,()=>this.start(),{once:!0});return}Astro[e](async()=>{const n=this.getAttribute("renderer-url"),[a,{default:r}]=await Promise.all([import(this.getAttribute("component-url")),n?import(n):()=>()=>{}]),i=this.getAttribute("component-export")||"default";if(!i.includes("."))this.Component=a[i];else{this.Component=a;for(const d of i.split("."))this.Component=this.Component[d]}return this.hydrator=r,this.hydrate},s,this)}attributeChangedCallback(){this.hydrator&&this.hydrate()}},l.observedAttributes=["props"],l))}`;
1
+ var astro_island_prebuilt_default = `var l;{const c={0:t=>t,1:t=>JSON.parse(t,o),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,o)),5:t=>new Set(JSON.parse(t,o)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(JSON.parse(t)),9:t=>new Uint16Array(JSON.parse(t)),10:t=>new Uint32Array(JSON.parse(t))},o=(t,s)=>{if(t===""||!Array.isArray(s))return s;const[e,n]=s;return e in c?c[e](n):void 0};customElements.get("astro-island")||customElements.define("astro-island",(l=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement&&this.parentElement.closest("astro-island[ssr]"))return;const s=this.querySelectorAll("astro-slot"),e={},n=this.querySelectorAll("template[data-astro-template]");for(const r of n){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute("data-astro-template")||"default"]=r.innerHTML,r.remove())}for(const r of s){const i=r.closest(this.tagName);!i||!i.isSameNode(this)||(e[r.getAttribute("name")||"default"]=r.innerHTML)}const a=this.hasAttribute("props")?JSON.parse(this.getAttribute("props"),o):{};this.hydrator(this)(this.Component,a,e,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),window.removeEventListener("astro:hydrate",this.hydrate),window.dispatchEvent(new CustomEvent("astro:hydrate"))}}connectedCallback(){!this.hasAttribute("await-children")||this.firstChild?this.childrenConnectedCallback():new MutationObserver((s,e)=>{e.disconnect(),this.childrenConnectedCallback()}).observe(this,{childList:!0})}async childrenConnectedCallback(){window.addEventListener("astro:hydrate",this.hydrate);let s=this.getAttribute("before-hydration-url");s&&await import(s),this.start()}start(){const s=JSON.parse(this.getAttribute("opts")),e=this.getAttribute("client");if(Astro[e]===void 0){window.addEventListener(\`astro:\${e}\`,()=>this.start(),{once:!0});return}Astro[e](async()=>{const n=this.getAttribute("renderer-url"),[a,{default:r}]=await Promise.all([import(this.getAttribute("component-url")),n?import(n):()=>()=>{}]),i=this.getAttribute("component-export")||"default";if(!i.includes("."))this.Component=a[i];else{this.Component=a;for(const d of i.split("."))this.Component=this.Component[d]}return this.hydrator=r,this.hydrate},s,this)}attributeChangedCallback(){this.hydrator&&this.hydrate()}},l.observedAttributes=["props"],l))}`;
2
2
  export {
3
3
  astro_island_prebuilt_default as default
4
4
  };
@@ -1,3 +1,3 @@
1
1
  import type { EndpointHandler, Params } from '../../@types/astro';
2
2
  /** Renders an endpoint request to completion, returning the body. */
3
- export declare function renderEndpoint(mod: EndpointHandler, request: Request, params: Params): Promise<Response | import("../../@types/astro").EndpointOutput>;
3
+ export declare function renderEndpoint(mod: EndpointHandler, request: Request, params: Params, ssr?: boolean): Promise<Response | import("../../@types/astro").EndpointOutput>;
@@ -10,10 +10,14 @@ function getHandlerFromModule(mod, method) {
10
10
  }
11
11
  return void 0;
12
12
  }
13
- async function renderEndpoint(mod, request, params) {
13
+ async function renderEndpoint(mod, request, params, ssr) {
14
14
  var _a;
15
15
  const chosenMethod = (_a = request.method) == null ? void 0 : _a.toLowerCase();
16
16
  const handler = getHandlerFromModule(mod, chosenMethod);
17
+ if (!ssr && ssr === false && chosenMethod && chosenMethod !== "get") {
18
+ console.warn(`
19
+ ${chosenMethod} requests are not available when building a static site. Update your config to output: 'server' to handle ${chosenMethod} requests.`);
20
+ }
17
21
  if (!handler || typeof handler !== "function") {
18
22
  let response = new Response(null, {
19
23
  status: 404,
@@ -1,15 +1,22 @@
1
1
  import { escape } from 'html-escaper';
2
2
  export declare const escapeHTML: typeof escape;
3
+ export declare class HTMLBytes extends Uint8Array {
4
+ }
3
5
  /**
4
6
  * A "blessed" extension of String that tells Astro that the string
5
7
  * has already been escaped. This helps prevent double-escaping of HTML.
6
8
  */
7
9
  export declare class HTMLString extends String {
10
+ get [Symbol.toStringTag](): string;
8
11
  }
12
+ declare type BlessedType = string | HTMLBytes;
9
13
  /**
10
14
  * markHTMLString marks a string as raw or "already escaped" by returning
11
15
  * a `HTMLString` instance. This is meant for internal use, and should not
12
16
  * be returned through any public JS API.
13
17
  */
14
18
  export declare const markHTMLString: (value: any) => any;
15
- export declare function unescapeHTML(str: any): any;
19
+ export declare function isHTMLString(value: any): value is HTMLString;
20
+ export declare function isHTMLBytes(value: any): value is HTMLBytes;
21
+ export declare function unescapeHTML(str: any): BlessedType | Promise<BlessedType | AsyncGenerator<BlessedType, void, unknown>> | AsyncGenerator<BlessedType, void, unknown>;
22
+ export {};
@@ -1,6 +1,16 @@
1
1
  import { escape } from "html-escaper";
2
2
  const escapeHTML = escape;
3
+ class HTMLBytes extends Uint8Array {
4
+ }
5
+ Object.defineProperty(HTMLBytes.prototype, Symbol.toStringTag, {
6
+ get() {
7
+ return "HTMLBytes";
8
+ }
9
+ });
3
10
  class HTMLString extends String {
11
+ get [Symbol.toStringTag]() {
12
+ return "HTMLString";
13
+ }
4
14
  }
5
15
  const markHTMLString = (value) => {
6
16
  if (value instanceof HTMLString) {
@@ -11,17 +21,50 @@ const markHTMLString = (value) => {
11
21
  }
12
22
  return value;
13
23
  };
24
+ function isHTMLString(value) {
25
+ return Object.prototype.toString.call(value) === "[object HTMLString]";
26
+ }
27
+ function markHTMLBytes(bytes) {
28
+ return new HTMLBytes(bytes);
29
+ }
30
+ function isHTMLBytes(value) {
31
+ return Object.prototype.toString.call(value) === "[object HTMLBytes]";
32
+ }
33
+ async function* unescapeChunksAsync(iterable) {
34
+ for await (const chunk of iterable) {
35
+ yield unescapeHTML(chunk);
36
+ }
37
+ }
38
+ function* unescapeChunks(iterable) {
39
+ for (const chunk of iterable) {
40
+ yield unescapeHTML(chunk);
41
+ }
42
+ }
14
43
  function unescapeHTML(str) {
15
- if (!!str && typeof str === "object" && typeof str.then === "function") {
16
- return Promise.resolve(str).then((value) => {
17
- return markHTMLString(value);
18
- });
44
+ if (!!str && typeof str === "object") {
45
+ if (str instanceof Uint8Array) {
46
+ return markHTMLBytes(str);
47
+ } else if (str instanceof Response && str.body) {
48
+ const body = str.body;
49
+ return unescapeChunksAsync(body);
50
+ } else if (typeof str.then === "function") {
51
+ return Promise.resolve(str).then((value) => {
52
+ return unescapeHTML(value);
53
+ });
54
+ } else if (Symbol.iterator in str) {
55
+ return unescapeChunks(str);
56
+ } else if (Symbol.asyncIterator in str) {
57
+ return unescapeChunksAsync(str);
58
+ }
19
59
  }
20
60
  return markHTMLString(str);
21
61
  }
22
62
  export {
63
+ HTMLBytes,
23
64
  HTMLString,
24
65
  escapeHTML,
66
+ isHTMLBytes,
67
+ isHTMLString,
25
68
  markHTMLString,
26
69
  unescapeHTML
27
70
  };
@@ -59,7 +59,9 @@ function extractDirectives(inputProps) {
59
59
  }
60
60
  }
61
61
  } else if (key === "class:list") {
62
- extracted.props[key.slice(0, -5)] = serializeListValue(value);
62
+ if (value) {
63
+ extracted.props[key.slice(0, -5)] = serializeListValue(value);
64
+ }
63
65
  } else {
64
66
  extracted.props[key] = value;
65
67
  }
@@ -1,6 +1,6 @@
1
1
  export { createAstro } from './astro-global.js';
2
2
  export { renderEndpoint } from './endpoint.js';
3
- export { escapeHTML, HTMLString, markHTMLString, unescapeHTML } from './escape.js';
3
+ export { escapeHTML, HTMLBytes, HTMLString, markHTMLString, unescapeHTML } from './escape.js';
4
4
  export type { Metadata } from './metadata';
5
5
  export { createMetadata } from './metadata.js';
6
6
  export { addAttribute, defineScriptVars, Fragment, maybeRenderHead, renderAstroComponent, renderComponent, Renderer as Renderer, renderHead, renderHTMLElement, renderPage, renderSlot, renderTemplate as render, renderTemplate, renderToString, stringifyChunk, voidElementNames, } from './render/index.js';
@@ -1,6 +1,6 @@
1
1
  import { createAstro } from "./astro-global.js";
2
2
  import { renderEndpoint } from "./endpoint.js";
3
- import { escapeHTML, HTMLString, markHTMLString, unescapeHTML } from "./escape.js";
3
+ import { escapeHTML, HTMLBytes, HTMLString, markHTMLString, unescapeHTML } from "./escape.js";
4
4
  import { createMetadata } from "./metadata.js";
5
5
  import {
6
6
  addAttribute,
@@ -81,6 +81,7 @@ function defineStyleVars(defs) {
81
81
  }
82
82
  export {
83
83
  Fragment,
84
+ HTMLBytes,
84
85
  HTMLString,
85
86
  Renderer,
86
87
  __astro_tag_component__,
@@ -6,9 +6,9 @@ import {
6
6
  renderComponent,
7
7
  renderToString,
8
8
  spreadAttributes,
9
- stringifyChunk,
10
9
  voidElementNames
11
10
  } from "./index.js";
11
+ import { HTMLParts } from "./render/common.js";
12
12
  const ClientOnlyPlaceholder = "astro-client-only";
13
13
  const skipAstroJSXCheck = /* @__PURE__ */ new WeakSet();
14
14
  let originalConsoleError;
@@ -131,12 +131,11 @@ async function renderJSX(result, vnode) {
131
131
  );
132
132
  }
133
133
  if (typeof output !== "string" && Symbol.asyncIterator in output) {
134
- let body = "";
134
+ let parts = new HTMLParts();
135
135
  for await (const chunk of output) {
136
- let html = stringifyChunk(result, chunk);
137
- body += html;
136
+ parts.append(chunk, result);
138
137
  }
139
- return markHTMLString(body);
138
+ return markHTMLString(parts.toString());
140
139
  } else {
141
140
  return markHTMLString(output);
142
141
  }
@@ -16,7 +16,9 @@ async function* renderChild(child) {
16
16
  } else if (!child && child !== 0) {
17
17
  } else if (child instanceof AstroComponent || Object.prototype.toString.call(child) === "[object AstroComponent]") {
18
18
  yield* renderAstroComponent(child);
19
- } else if (typeof child === "object" && Symbol.asyncIterator in child) {
19
+ } else if (ArrayBuffer.isView(child)) {
20
+ yield child;
21
+ } else if (typeof child === "object" && (Symbol.asyncIterator in child || Symbol.iterator in child)) {
20
22
  yield* child;
21
23
  } else {
22
24
  yield child;
@@ -1,6 +1,7 @@
1
1
  import type { SSRResult } from '../../../@types/astro';
2
2
  import type { AstroComponentFactory } from './index';
3
3
  import type { RenderInstruction } from './types';
4
+ import { HTMLBytes } from '../escape.js';
4
5
  export declare class AstroComponent {
5
6
  private htmlParts;
6
7
  private expressions;
@@ -10,7 +11,7 @@ export declare class AstroComponent {
10
11
  }
11
12
  export declare function isAstroComponent(obj: any): obj is AstroComponent;
12
13
  export declare function isAstroComponentFactory(obj: any): obj is AstroComponentFactory;
13
- export declare function renderAstroComponent(component: InstanceType<typeof AstroComponent>): AsyncIterable<string | RenderInstruction>;
14
+ export declare function renderAstroComponent(component: InstanceType<typeof AstroComponent>): AsyncIterable<string | HTMLBytes | RenderInstruction>;
14
15
  export declare function renderToString(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any): Promise<string>;
15
- export declare function renderToIterable(result: SSRResult, componentFactory: AstroComponentFactory, displayName: string, props: any, children: any): Promise<AsyncIterable<string | RenderInstruction>>;
16
+ export declare function renderToIterable(result: SSRResult, componentFactory: AstroComponentFactory, displayName: string, props: any, children: any): Promise<AsyncIterable<string | HTMLBytes | RenderInstruction>>;
16
17
  export declare function renderTemplate(htmlParts: TemplateStringsArray, ...expressions: any[]): Promise<AstroComponent>;
@@ -1,7 +1,7 @@
1
1
  import { markHTMLString } from "../escape.js";
2
2
  import { HydrationDirectiveProps } from "../hydration.js";
3
3
  import { renderChild } from "./any.js";
4
- import { stringifyChunk } from "./common.js";
4
+ import { HTMLParts } from "./common.js";
5
5
  function validateComponentProps(props, displayName) {
6
6
  var _a;
7
7
  if (((_a = import.meta.env) == null ? void 0 : _a.DEV) && props != null) {
@@ -62,11 +62,11 @@ async function renderToString(result, componentFactory, props, children) {
62
62
  const response = Component;
63
63
  throw response;
64
64
  }
65
- let html = "";
65
+ let parts = new HTMLParts();
66
66
  for await (const chunk of renderAstroComponent(Component)) {
67
- html += stringifyChunk(result, chunk);
67
+ parts.append(chunk, result);
68
68
  }
69
- return html;
69
+ return parts.toString();
70
70
  }
71
71
  async function renderToIterable(result, componentFactory, displayName, props, children) {
72
72
  validateComponentProps(props, displayName);
@@ -1,5 +1,17 @@
1
1
  import type { SSRResult } from '../../../@types/astro';
2
2
  import type { RenderInstruction } from './types.js';
3
+ import { HTMLBytes } from '../escape.js';
3
4
  export declare const Fragment: unique symbol;
4
5
  export declare const Renderer: unique symbol;
6
+ export declare const encoder: TextEncoder;
7
+ export declare const decoder: TextDecoder;
5
8
  export declare function stringifyChunk(result: SSRResult, chunk: string | RenderInstruction): any;
9
+ export declare class HTMLParts {
10
+ parts: Array<HTMLBytes | string>;
11
+ constructor();
12
+ append(part: string | HTMLBytes | RenderInstruction, result: SSRResult): void;
13
+ toString(): string;
14
+ toArrayBuffer(): Uint8Array;
15
+ }
16
+ export declare function chunkToByteArray(result: SSRResult, chunk: string | HTMLBytes | RenderInstruction): Uint8Array;
17
+ export declare function concatUint8Arrays(arrays: Array<Uint8Array>): Uint8Array;
@@ -6,6 +6,8 @@ import {
6
6
  } from "../scripts.js";
7
7
  const Fragment = Symbol.for("astro:fragment");
8
8
  const Renderer = Symbol.for("astro:renderer");
9
+ const encoder = new TextEncoder();
10
+ const decoder = new TextDecoder();
9
11
  function stringifyChunk(result, chunk) {
10
12
  switch (chunk.type) {
11
13
  case "directive": {
@@ -25,8 +27,61 @@ function stringifyChunk(result, chunk) {
25
27
  }
26
28
  }
27
29
  }
30
+ class HTMLParts {
31
+ constructor() {
32
+ this.parts = [];
33
+ }
34
+ append(part, result) {
35
+ if (ArrayBuffer.isView(part)) {
36
+ this.parts.push(part);
37
+ } else {
38
+ this.parts.push(stringifyChunk(result, part));
39
+ }
40
+ }
41
+ toString() {
42
+ let html = "";
43
+ for (const part of this.parts) {
44
+ if (ArrayBuffer.isView(part)) {
45
+ html += decoder.decode(part);
46
+ } else {
47
+ html += part;
48
+ }
49
+ }
50
+ return html;
51
+ }
52
+ toArrayBuffer() {
53
+ this.parts.forEach((part, i) => {
54
+ if (typeof part === "string") {
55
+ this.parts[i] = encoder.encode(String(part));
56
+ }
57
+ });
58
+ return concatUint8Arrays(this.parts);
59
+ }
60
+ }
61
+ function chunkToByteArray(result, chunk) {
62
+ if (chunk instanceof Uint8Array) {
63
+ return chunk;
64
+ }
65
+ return encoder.encode(stringifyChunk(result, chunk));
66
+ }
67
+ function concatUint8Arrays(arrays) {
68
+ let len = 0;
69
+ arrays.forEach((arr) => len += arr.length);
70
+ let merged = new Uint8Array(len);
71
+ let offset = 0;
72
+ arrays.forEach((arr) => {
73
+ merged.set(arr, offset);
74
+ offset += arr.length;
75
+ });
76
+ return merged;
77
+ }
28
78
  export {
29
79
  Fragment,
80
+ HTMLParts,
30
81
  Renderer,
82
+ chunkToByteArray,
83
+ concatUint8Arrays,
84
+ decoder,
85
+ encoder,
31
86
  stringifyChunk
32
87
  };
@@ -1,3 +1,4 @@
1
1
  import type { SSRResult } from '../../../@types/astro';
2
2
  import type { RenderInstruction } from './types.js';
3
- export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, _props: Record<string | number, any>, slots?: any): Promise<string | AsyncIterable<string | RenderInstruction>>;
3
+ import { HTMLBytes } from '../escape.js';
4
+ export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, _props: Record<string | number, any>, slots?: any): Promise<string | AsyncIterable<string | HTMLBytes | RenderInstruction>>;
@@ -1,9 +1,9 @@
1
+ import { isHTMLString } from "../escape.js";
1
2
  import { createResponse } from "../response.js";
2
3
  import { isAstroComponent, isAstroComponentFactory, renderAstroComponent } from "./astro.js";
3
- import { stringifyChunk } from "./common.js";
4
+ import { chunkToByteArray, encoder, HTMLParts } from "./common.js";
4
5
  import { renderComponent } from "./component.js";
5
6
  import { maybeRenderHead } from "./head.js";
6
- const encoder = new TextEncoder();
7
7
  const needsHeadRenderingSymbol = Symbol.for("astro.needsHeadRendering");
8
8
  function nonAstroPageNeedsHeadInjection(pageComponent) {
9
9
  return needsHeadRenderingSymbol in pageComponent && !!pageComponent[needsHeadRenderingSymbol];
@@ -50,13 +50,15 @@ async function renderPage(result, componentFactory, props, children, streaming)
50
50
  let i = 0;
51
51
  try {
52
52
  for await (const chunk of iterable) {
53
- let html = stringifyChunk(result, chunk);
54
- if (i === 0) {
55
- if (!/<!doctype html/i.test(html)) {
56
- controller.enqueue(encoder.encode("<!DOCTYPE html>\n"));
53
+ if (isHTMLString(chunk)) {
54
+ if (i === 0) {
55
+ if (!/<!doctype html/i.test(String(chunk))) {
56
+ controller.enqueue(encoder.encode("<!DOCTYPE html>\n"));
57
+ }
57
58
  }
58
59
  }
59
- controller.enqueue(encoder.encode(String(html)));
60
+ let bytes = chunkToByteArray(result, chunk);
61
+ controller.enqueue(bytes);
60
62
  i++;
61
63
  }
62
64
  controller.close();
@@ -68,26 +70,29 @@ async function renderPage(result, componentFactory, props, children, streaming)
68
70
  }
69
71
  });
70
72
  } else {
71
- body = "";
73
+ let parts = new HTMLParts();
72
74
  let i = 0;
73
75
  for await (const chunk of iterable) {
74
- let html = stringifyChunk(result, chunk);
75
- if (i === 0) {
76
- if (!/<!doctype html/i.test(html)) {
77
- body += "<!DOCTYPE html>\n";
76
+ if (isHTMLString(chunk)) {
77
+ if (i === 0) {
78
+ if (!/<!doctype html/i.test(String(chunk))) {
79
+ parts.append("<!DOCTYPE html>\n", result);
80
+ }
78
81
  }
79
82
  }
80
- body += html;
83
+ parts.append(chunk, result);
81
84
  i++;
82
85
  }
83
- const bytes = encoder.encode(body);
84
- headers.set("Content-Length", bytes.byteLength.toString());
86
+ body = parts.toArrayBuffer();
87
+ headers.set("Content-Length", body.byteLength.toString());
85
88
  }
86
89
  let response = createResponse(body, { ...init, headers });
87
90
  return response;
88
- } else {
89
- return factoryReturnValue;
90
91
  }
92
+ if (!(factoryReturnValue instanceof Response)) {
93
+ throw new Error("Only instance of Response can be returned from an Astro file");
94
+ }
95
+ return factoryReturnValue;
91
96
  }
92
97
  export {
93
98
  renderPage
@@ -5,7 +5,7 @@ const htmlBooleanAttributes = /^(allowfullscreen|async|autofocus|autoplay|contro
5
5
  const htmlEnumAttributes = /^(contenteditable|draggable|spellcheck|value)$/i;
6
6
  const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i;
7
7
  const STATIC_DIRECTIVES = /* @__PURE__ */ new Set(["set:html", "set:text"]);
8
- const toIdent = (k) => k.trim().replace(/(?:(?<!^)\b\w|\s+|[^\w]+)/g, (match, index) => {
8
+ const toIdent = (k) => k.trim().replace(/(?:(?!^)\b\w|\s+|[^\w]+)/g, (match, index) => {
9
9
  if (/[^\w]|\s/.test(match))
10
10
  return "";
11
11
  return index === 0 ? match : match.toUpperCase();
@@ -16,7 +16,7 @@ const toStyleString = (obj) => Object.entries(obj).map(([k, v]) => `${kebab(k)}:
16
16
  function defineScriptVars(vars) {
17
17
  let output = "";
18
18
  for (const [key, value] of Object.entries(vars)) {
19
- output += `let ${toIdent(key)} = ${JSON.stringify(value)};
19
+ output += `const ${toIdent(key)} = ${JSON.stringify(value)};
20
20
  `;
21
21
  }
22
22
  return markHTMLString(output);
@@ -67,7 +67,7 @@ function createResponseClass() {
67
67
  return StreamingCompatibleResponse;
68
68
  }
69
69
  const createResponse = isNodeJS ? (body, init) => {
70
- if (typeof body === "string") {
70
+ if (typeof body === "string" || ArrayBuffer.isView(body)) {
71
71
  return new Response(body, init);
72
72
  }
73
73
  if (typeof StreamingCompatibleResponse === "undefined") {
@@ -6,7 +6,10 @@ const PROP_TYPE = {
6
6
  Map: 4,
7
7
  Set: 5,
8
8
  BigInt: 6,
9
- URL: 7
9
+ URL: 7,
10
+ Uint8Array: 8,
11
+ Uint16Array: 9,
12
+ Uint32Array: 10
10
13
  };
11
14
  function serializeArray(value, metadata = {}, parents = /* @__PURE__ */ new WeakSet()) {
12
15
  if (parents.has(value)) {
@@ -66,6 +69,15 @@ function convertToSerializedForm(value, metadata = {}, parents = /* @__PURE__ */
66
69
  case "[object Array]": {
67
70
  return [PROP_TYPE.JSON, JSON.stringify(serializeArray(value, metadata, parents))];
68
71
  }
72
+ case "[object Uint8Array]": {
73
+ return [PROP_TYPE.Uint8Array, JSON.stringify(Array.from(value))];
74
+ }
75
+ case "[object Uint16Array]": {
76
+ return [PROP_TYPE.Uint16Array, JSON.stringify(Array.from(value))];
77
+ }
78
+ case "[object Uint32Array]": {
79
+ return [PROP_TYPE.Uint32Array, JSON.stringify(Array.from(value))];
80
+ }
69
81
  default: {
70
82
  if (value !== null && typeof value === "object") {
71
83
  return [PROP_TYPE.Value, serializeObject(value, metadata, parents)];
@@ -1 +1,2 @@
1
1
  export declare function serializeListValue(value: any): string;
2
+ export declare function isPromise<T = any>(value: any): value is Promise<T>;
@@ -1,9 +1,3 @@
1
- function formatList(values) {
2
- if (values.length === 1) {
3
- return values[0];
4
- }
5
- return `${values.slice(0, -1).join(", ")} or ${values[values.length - 1]}`;
6
- }
7
1
  function serializeListValue(value) {
8
2
  const hash = {};
9
3
  push(value);
@@ -26,6 +20,10 @@ function serializeListValue(value) {
26
20
  }
27
21
  }
28
22
  }
23
+ function isPromise(value) {
24
+ return !!value && typeof value === "object" && typeof value.then === "function";
25
+ }
29
26
  export {
27
+ isPromise,
30
28
  serializeListValue
31
29
  };
@@ -3,9 +3,10 @@ import { invalidateCompilation, isCached } from "../core/compile/index.js";
3
3
  import { info } from "../core/logger/core.js";
4
4
  import * as msg from "../core/messages.js";
5
5
  import { isAstroScript } from "./query.js";
6
- const PKG_PREFIX = new URL("../../", import.meta.url);
6
+ const PKG_PREFIX = fileURLToPath(new URL("../../", import.meta.url));
7
+ const E2E_PREFIX = fileURLToPath(new URL("../../e2e", import.meta.url));
7
8
  const isPkgFile = (id) => {
8
- return (id == null ? void 0 : id.startsWith(fileURLToPath(PKG_PREFIX))) || (id == null ? void 0 : id.startsWith(PKG_PREFIX.pathname));
9
+ return id && id.startsWith(PKG_PREFIX) && !id.startsWith(E2E_PREFIX);
9
10
  };
10
11
  async function handleHotUpdate(ctx, { config, logging, compile }) {
11
12
  let isStyleOnlyChange = false;