astro 2.8.5 → 2.9.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 (81) hide show
  1. package/client-base.d.ts +9 -0
  2. package/components/ViewTransitions.astro +157 -0
  3. package/components/index.ts +1 -0
  4. package/components/viewtransitions.css +44 -0
  5. package/dist/@types/astro.d.ts +28 -10
  6. package/dist/assets/services/vendor/squoosh/impl.js +1 -1
  7. package/dist/content/runtime.js +1 -1
  8. package/dist/content/vite-plugin-content-assets.js +2 -2
  9. package/dist/core/app/index.js +115 -95
  10. package/dist/core/build/generate.js +18 -33
  11. package/dist/core/build/graph.js +1 -1
  12. package/dist/core/build/plugins/plugin-analyzer.js +101 -3
  13. package/dist/core/build/plugins/plugin-css.js +1 -1
  14. package/dist/core/build/types.d.ts +1 -1
  15. package/dist/core/compile/compile.js +2 -0
  16. package/dist/core/config/config.js +3 -5
  17. package/dist/core/config/schema.d.ts +85 -48
  18. package/dist/core/config/schema.js +36 -10
  19. package/dist/core/constants.js +1 -1
  20. package/dist/core/create-vite.js +4 -2
  21. package/dist/core/dev/dev.js +1 -1
  22. package/dist/core/endpoint/dev/index.d.ts +2 -11
  23. package/dist/core/endpoint/index.d.ts +2 -3
  24. package/dist/core/endpoint/index.js +1 -11
  25. package/dist/core/errors/index.d.ts +1 -1
  26. package/dist/core/errors/index.js +3 -3
  27. package/dist/core/messages.js +2 -2
  28. package/dist/core/middleware/index.d.ts +1 -1
  29. package/dist/core/render/core.d.ts +9 -3
  30. package/dist/core/render/core.js +42 -18
  31. package/dist/core/render/environment.d.ts +7 -2
  32. package/dist/core/render/index.d.ts +22 -1
  33. package/dist/core/render/index.js +2 -2
  34. package/dist/core/render/route-cache.js +1 -1
  35. package/dist/core/routing/validation.d.ts +2 -3
  36. package/dist/core/routing/validation.js +0 -9
  37. package/dist/jsx-runtime/index.d.ts +1 -1
  38. package/dist/prerender/routing.d.ts +1 -1
  39. package/dist/prerender/routing.js +1 -1
  40. package/dist/runtime/server/astro-component.d.ts +1 -1
  41. package/dist/runtime/server/astro-component.js +5 -5
  42. package/dist/runtime/server/index.d.ts +2 -1
  43. package/dist/runtime/server/index.js +3 -1
  44. package/dist/runtime/server/jsx.js +1 -1
  45. package/dist/runtime/server/render/component.js +1 -1
  46. package/dist/runtime/server/render/page.js +1 -1
  47. package/dist/runtime/server/transition.d.ts +2 -0
  48. package/dist/runtime/server/transition.js +133 -0
  49. package/dist/transitions/index.d.ts +7 -0
  50. package/dist/transitions/index.js +67 -0
  51. package/dist/transitions/vite-plugin-transitions.d.ts +5 -0
  52. package/dist/transitions/vite-plugin-transitions.js +36 -0
  53. package/dist/{core/render/dev → vite-plugin-astro-server}/css.d.ts +2 -2
  54. package/dist/{core/render/dev → vite-plugin-astro-server}/css.js +1 -1
  55. package/dist/vite-plugin-astro-server/environment.d.ts +5 -0
  56. package/dist/{core/render/dev → vite-plugin-astro-server}/environment.js +3 -3
  57. package/dist/vite-plugin-astro-server/index.d.ts +6 -0
  58. package/dist/vite-plugin-astro-server/index.js +21 -0
  59. package/dist/{core/render/dev → vite-plugin-astro-server}/metadata.d.ts +2 -2
  60. package/dist/{core/render/dev → vite-plugin-astro-server}/metadata.js +2 -2
  61. package/dist/vite-plugin-astro-server/plugin.js +1 -1
  62. package/dist/vite-plugin-astro-server/request.d.ts +1 -1
  63. package/dist/{core/render/dev → vite-plugin-astro-server}/resolve.d.ts +1 -1
  64. package/dist/{core/render/dev → vite-plugin-astro-server}/resolve.js +1 -1
  65. package/dist/vite-plugin-astro-server/route.d.ts +1 -1
  66. package/dist/vite-plugin-astro-server/route.js +93 -20
  67. package/dist/vite-plugin-astro-server/scripts.d.ts +3 -0
  68. package/dist/{core/render/dev → vite-plugin-astro-server}/scripts.js +2 -2
  69. package/dist/{core/render/dev → vite-plugin-astro-server}/vite.d.ts +1 -1
  70. package/dist/{core/render/dev → vite-plugin-astro-server}/vite.js +2 -2
  71. package/dist/vite-plugin-scanner/index.d.ts +6 -3
  72. package/dist/vite-plugin-scanner/index.js +21 -4
  73. package/dist/vite-plugin-scanner/scan.d.ts +2 -1
  74. package/dist/vite-plugin-scanner/scan.js +6 -2
  75. package/package.json +6 -3
  76. package/dist/core/render/dev/environment.d.ts +0 -9
  77. package/dist/core/render/dev/index.d.ts +0 -27
  78. package/dist/core/render/dev/index.js +0 -112
  79. package/dist/core/render/dev/scripts.d.ts +0 -3
  80. /package/dist/{core/render/dev → vite-plugin-astro-server}/util.d.ts +0 -0
  81. /package/dist/{core/render/dev → vite-plugin-astro-server}/util.js +0 -0
package/client-base.d.ts CHANGED
@@ -70,6 +70,15 @@ declare module 'astro:assets' {
70
70
  export const { getImage, getConfiguredImageService, Image }: AstroAssets;
71
71
  }
72
72
 
73
+ declare module 'astro:transitions' {
74
+ type TransitionModule = typeof import('./dist/transitions/index.js');
75
+ export const slide: TransitionModule['slide'];
76
+ export const fade: TransitionModule['fade'];
77
+
78
+ type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
79
+ export const ViewTransitions: ViewTransitionsModule['default'];
80
+ }
81
+
73
82
  type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
74
83
  interface ExportedMarkdownModuleEntities {
75
84
  frontmatter: MD['frontmatter'];
@@ -0,0 +1,157 @@
1
+ ---
2
+ type Fallback = 'none' | 'animate' | 'swap';
3
+
4
+ export interface Props {
5
+ fallback?: Fallback;
6
+ }
7
+
8
+ const { fallback = 'animate' } = Astro.props as Props;
9
+ ---
10
+
11
+ <meta name="astro-view-transitions-enabled" content="true" />
12
+ <meta name="astro-view-transitions-fallback" content={fallback} />
13
+ <script>
14
+ type Fallback = 'none' | 'animate' | 'swap';
15
+ type Direction = 'forward' | 'back';
16
+
17
+ // The History API does not tell you if navigation is forward or back, so
18
+ // you can figure it using an index. On pushState the index is incremented so you
19
+ // can use that to determine popstate if going forward or back.
20
+ let currentHistoryIndex = history.state?.index || 0;
21
+ if (!history.state) {
22
+ history.replaceState({ index: currentHistoryIndex }, document.title);
23
+ }
24
+
25
+ const supportsViewTransitions = !!document.startViewTransition;
26
+ const transitionEnabledOnThisPage = () =>
27
+ !!document.querySelector('[name="astro-view-transitions-enabled"]');
28
+
29
+ async function getHTML(href: string) {
30
+ const res = await fetch(href);
31
+ const html = await res.text();
32
+ return { ok: res.ok, html };
33
+ }
34
+
35
+ function getFallback(): Fallback {
36
+ const el = document.querySelector('[name="astro-view-transitions-fallback"]');
37
+ if (el) {
38
+ return el.getAttribute('content') as Fallback;
39
+ }
40
+ return 'animate';
41
+ }
42
+
43
+ const parser = new DOMParser();
44
+
45
+ async function updateDOM(dir: Direction, html: string, fallback?: Fallback) {
46
+ const doc = parser.parseFromString(html, 'text/html');
47
+ doc.documentElement.dataset.astroTransition = dir;
48
+ const swap = () => document.documentElement.replaceWith(doc.documentElement);
49
+
50
+ if (fallback === 'animate') {
51
+ let isAnimating = false;
52
+ addEventListener('animationstart', () => (isAnimating = true), { once: true });
53
+
54
+ // Trigger the animations
55
+ document.documentElement.dataset.astroTransitionFallback = 'old';
56
+ doc.documentElement.dataset.astroTransitionFallback = 'new';
57
+ // If there are any animations, want for the animationend event.
58
+ addEventListener('animationend', swap, { once: true });
59
+ // If there are no animations, go ahead and swap on next tick
60
+ // This is necessary because we do not know if there are animations.
61
+ // The setTimeout is a fallback in case there are none.
62
+ setTimeout(() => !isAnimating && swap());
63
+ } else {
64
+ swap();
65
+ }
66
+ }
67
+
68
+ async function navigate(dir: Direction, href: string) {
69
+ let finished: Promise<void>;
70
+ const { html, ok } = await getHTML(href);
71
+ // If there is a problem fetching the new page, just do an MPA navigation to it.
72
+ if (!ok) {
73
+ location.href = href;
74
+ return;
75
+ }
76
+ if (supportsViewTransitions) {
77
+ finished = document.startViewTransition(() => updateDOM(dir, html)).finished;
78
+ } else {
79
+ finished = updateDOM(dir, html, getFallback());
80
+ }
81
+ try {
82
+ await finished;
83
+ } finally {
84
+ document.documentElement.removeAttribute('data-astro-transition');
85
+ }
86
+ }
87
+
88
+ // Prefetching
89
+ function maybePrefetch(pathname: string) {
90
+ if (document.querySelector(`link[rel=prefetch][href="${pathname}"]`)) return;
91
+ if (navigator.connection) {
92
+ let conn = navigator.connection;
93
+ if (conn.saveData || /(2|3)g/.test(conn.effectiveType || '')) return;
94
+ }
95
+ let link = document.createElement('link');
96
+ link.setAttribute('rel', 'prefetch');
97
+ link.setAttribute('href', pathname);
98
+ document.head.append(link);
99
+ }
100
+
101
+ if (supportsViewTransitions || getFallback() !== 'none') {
102
+ document.addEventListener('click', (ev) => {
103
+ let link = ev.target;
104
+ if (link instanceof Element && link.tagName !== 'A') {
105
+ link = link.closest('a');
106
+ }
107
+ // This check verifies that the click is happening on an anchor
108
+ // that is going to another page within the same origin. Basically it determines
109
+ // same-origin navigation, but omits special key combos for new tabs, etc.
110
+ if (
111
+ link &&
112
+ link instanceof HTMLAnchorElement &&
113
+ link.href &&
114
+ (!link.target || link.target === '_self') &&
115
+ link.origin === location.origin &&
116
+ ev.button === 0 && // left clicks only
117
+ !ev.metaKey && // new tab (mac)
118
+ !ev.ctrlKey && // new tab (windows)
119
+ !ev.altKey && // download
120
+ !ev.shiftKey &&
121
+ !ev.defaultPrevented &&
122
+ transitionEnabledOnThisPage()
123
+ ) {
124
+ ev.preventDefault();
125
+ navigate('forward', link.href);
126
+ currentHistoryIndex++;
127
+ history.pushState({ index: currentHistoryIndex }, '', link.href);
128
+ }
129
+ });
130
+ window.addEventListener('popstate', () => {
131
+ if (!transitionEnabledOnThisPage()) return;
132
+ const nextIndex = history.state?.index ?? currentHistoryIndex + 1;
133
+ const direction: Direction = nextIndex > currentHistoryIndex ? 'forward' : 'back';
134
+ navigate(direction, location.href);
135
+ currentHistoryIndex = nextIndex;
136
+ });
137
+
138
+ ['mouseenter', 'touchstart', 'focus'].forEach((evName) => {
139
+ document.addEventListener(
140
+ evName,
141
+ (ev) => {
142
+ if (ev.target instanceof HTMLAnchorElement) {
143
+ let el = ev.target;
144
+ if (
145
+ el.origin === location.origin &&
146
+ el.pathname !== location.pathname &&
147
+ transitionEnabledOnThisPage()
148
+ ) {
149
+ maybePrefetch(el.pathname);
150
+ }
151
+ }
152
+ },
153
+ { passive: true, capture: true }
154
+ );
155
+ });
156
+ }
157
+ </script>
@@ -1,2 +1,3 @@
1
1
  export { default as Code } from './Code.astro';
2
2
  export { default as Debug } from './Debug.astro';
3
+ export { default as ViewTransitions } from './ViewTransitions.astro';
@@ -0,0 +1,44 @@
1
+ @keyframes astroFadeInOut {
2
+ from {
3
+ opacity: 1;
4
+ }
5
+ to {
6
+ opacity: 0;
7
+ }
8
+ }
9
+
10
+ @keyframes astroFadeIn {
11
+ from {
12
+ opacity: 0;
13
+ }
14
+ }
15
+
16
+ @keyframes astroFadeOut {
17
+ to {
18
+ opacity: 0;
19
+ }
20
+ }
21
+
22
+ @keyframes astroSlideFromRight {
23
+ from {
24
+ transform: translateX(100%);
25
+ }
26
+ }
27
+
28
+ @keyframes astroSlideFromLeft {
29
+ from {
30
+ transform: translateX(-100%);
31
+ }
32
+ }
33
+
34
+ @keyframes astroSlideToRight {
35
+ to {
36
+ transform: translateX(100%);
37
+ }
38
+ }
39
+
40
+ @keyframes astroSlideToLeft {
41
+ to {
42
+ transform: translateX(-100%);
43
+ }
44
+ }
@@ -29,6 +29,23 @@ export interface AstroBuiltinProps {
29
29
  'client:visible'?: boolean;
30
30
  'client:only'?: boolean | string;
31
31
  }
32
+ export interface TransitionAnimation {
33
+ name: string;
34
+ delay?: number | string;
35
+ duration?: number | string;
36
+ easing?: string;
37
+ fillMode?: string;
38
+ direction?: string;
39
+ }
40
+ export interface TransitionAnimationPair {
41
+ old: TransitionAnimation | TransitionAnimation[];
42
+ new: TransitionAnimation | TransitionAnimation[];
43
+ }
44
+ export interface TransitionDirectionalAnimations {
45
+ forwards: TransitionAnimationPair;
46
+ backwards: TransitionAnimationPair;
47
+ }
48
+ export type TransitionAnimationValue = 'morph' | 'slide' | 'fade' | TransitionDirectionalAnimations;
32
49
  export interface AstroClientDirectives {
33
50
  }
34
51
  export interface AstroBuiltinAttributes {
@@ -36,6 +53,8 @@ export interface AstroBuiltinAttributes {
36
53
  'set:html'?: any;
37
54
  'set:text'?: any;
38
55
  'is:raw'?: boolean;
56
+ 'transition:animate'?: 'morph' | 'slide' | 'fade' | TransitionDirectionalAnimations;
57
+ 'transition:name'?: string;
39
58
  }
40
59
  export interface AstroDefineVarsAttribute {
41
60
  'define:vars'?: any;
@@ -73,7 +92,6 @@ export interface CLIFlags {
73
92
  drafts?: boolean;
74
93
  open?: boolean;
75
94
  experimentalAssets?: boolean;
76
- experimentalRedirects?: boolean;
77
95
  }
78
96
  /**
79
97
  * Astro global available in all contexts in .astro files
@@ -399,10 +417,10 @@ export interface AstroUserConfig {
399
417
  cacheDir?: string;
400
418
  /**
401
419
  * @docs
402
- * @name redirects (Experimental)
420
+ * @name redirects
403
421
  * @type {Record<string, RedirectConfig>}
404
422
  * @default `{}`
405
- * @version 2.6.0
423
+ * @version 2.9.0
406
424
  * @description Specify a mapping of redirects where the key is the route to match
407
425
  * and the value is the path to redirect to.
408
426
  *
@@ -1149,24 +1167,24 @@ export interface AstroUserConfig {
1149
1167
  assets?: boolean;
1150
1168
  /**
1151
1169
  * @docs
1152
- * @name experimental.redirects
1170
+ * @name experimental.viewTransitions
1153
1171
  * @type {boolean}
1154
1172
  * @default `false`
1155
- * @version 2.6.0
1173
+ * @version 2.9.0
1156
1174
  * @description
1157
- * Enable experimental support for redirect configuration. With this enabled
1158
- * you can set redirects via the top-level `redirects` property. To enable
1159
- * this feature, set `experimental.redirects` to `true`.
1175
+ * Enable experimental support for the `<ViewTransitions / >` component. With this enabled
1176
+ * you can opt-in to [client-side routing](https://docs.astro.build/en/guides/client-side-routing/) on a per-page basis using this component
1177
+ * and enable animations with the `transition:animate` directive.
1160
1178
  *
1161
1179
  * ```js
1162
1180
  * {
1163
1181
  * experimental: {
1164
- * redirects: true,
1182
+ * viewTransitions: true,
1165
1183
  * },
1166
1184
  * }
1167
1185
  * ```
1168
1186
  */
1169
- redirects?: boolean;
1187
+ viewTransitions?: boolean;
1170
1188
  };
1171
1189
  /** @deprecated - Use "integrations" instead. Run Astro to learn more about migrating. */
1172
1190
  renderers?: never;
@@ -1,4 +1,4 @@
1
- import { codecs as supportedFormats, preprocessors } from "./codecs.js";
1
+ import { preprocessors, codecs as supportedFormats } from "./codecs.js";
2
2
  import ImageData from "./image_data.js";
3
3
  const DELAY_MS = 1e3;
4
4
  let _promise;
@@ -1,4 +1,4 @@
1
- import { string as zodString, ZodIssueCode } from "zod";
1
+ import { ZodIssueCode, string as zodString } from "zod";
2
2
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
3
3
  import { prependForwardSlash } from "../core/path.js";
4
4
  import {
@@ -4,8 +4,8 @@ import { moduleIsTopLevelPage, walkParentInfos } from "../core/build/graph.js";
4
4
  import { getPageDataByViteID } from "../core/build/internal.js";
5
5
  import { createViteLoader } from "../core/module-loader/vite.js";
6
6
  import { joinPaths, prependForwardSlash } from "../core/path.js";
7
- import { getStylesForURL } from "../core/render/dev/css.js";
8
- import { getScriptsForURL } from "../core/render/dev/scripts.js";
7
+ import { getStylesForURL } from "../vite-plugin-astro-server/css.js";
8
+ import { getScriptsForURL } from "../vite-plugin-astro-server/scripts.js";
9
9
  import {
10
10
  CONTENT_RENDER_FLAG,
11
11
  LINKS_PLACEHOLDER,
@@ -1,14 +1,14 @@
1
1
  import mime from "mime";
2
2
  import { attachToResponse, getSetCookiesFromResponse } from "../cookies/index.js";
3
- import { callEndpoint } from "../endpoint/index.js";
4
3
  import { consoleLogDestination } from "../logger/console.js";
5
4
  import { error } from "../logger/core.js";
6
5
  import { prependForwardSlash, removeTrailingForwardSlash } from "../path.js";
7
6
  import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
7
+ import { isResponse } from "../render/core";
8
8
  import {
9
9
  createEnvironment,
10
10
  createRenderContext,
11
- tryRenderPage
11
+ tryRenderRoute
12
12
  } from "../render/index.js";
13
13
  import { RouteCache } from "../render/route-cache.js";
14
14
  import {
@@ -131,34 +131,140 @@ class App {
131
131
  defaultStatus = 404;
132
132
  }
133
133
  let mod = await this.#getModuleForRoute(routeData);
134
- if (routeData.type === "page" || routeData.type === "redirect") {
135
- let response = await this.#renderPage(request, routeData, mod, defaultStatus);
134
+ const pageModule = await mod.page();
135
+ const url = new URL(request.url);
136
+ const renderContext = await this.#createRenderContext(
137
+ url,
138
+ request,
139
+ routeData,
140
+ mod,
141
+ defaultStatus
142
+ );
143
+ let response;
144
+ try {
145
+ response = await tryRenderRoute(
146
+ routeData.type,
147
+ renderContext,
148
+ this.#env,
149
+ pageModule,
150
+ mod.onRequest
151
+ );
152
+ } catch (err) {
153
+ error(this.#logging, "ssr", err.stack || err.message || String(err));
154
+ response = new Response(null, {
155
+ status: 500,
156
+ statusText: "Internal server error"
157
+ });
158
+ }
159
+ if (isResponse(response, routeData.type)) {
136
160
  if (response.status === 500 || response.status === 404) {
137
161
  const errorRouteData = matchRoute("/" + response.status, this.#manifestData);
138
162
  if (errorRouteData && errorRouteData.route !== routeData.route) {
139
163
  mod = await this.#getModuleForRoute(errorRouteData);
140
164
  try {
141
- let errorResponse = await this.#renderPage(
165
+ const newRenderContext = await this.#createRenderContext(
166
+ url,
142
167
  request,
143
- errorRouteData,
168
+ routeData,
144
169
  mod,
145
170
  response.status
146
171
  );
172
+ const page = await mod.page();
173
+ const errorResponse = await tryRenderRoute(
174
+ routeData.type,
175
+ newRenderContext,
176
+ this.#env,
177
+ page
178
+ );
147
179
  return errorResponse;
148
180
  } catch {
149
181
  }
150
182
  }
151
183
  }
184
+ Reflect.set(response, responseSentSymbol, true);
152
185
  return response;
153
- } else if (routeData.type === "endpoint") {
154
- return this.#callEndpoint(request, routeData, mod, defaultStatus);
155
186
  } else {
156
- throw new Error(`Unsupported route type [${routeData.type}].`);
187
+ if (response.type === "response") {
188
+ if (response.response.headers.get("X-Astro-Response") === "Not-Found") {
189
+ const fourOhFourRequest = new Request(new URL("/404", request.url));
190
+ const fourOhFourRouteData = this.match(fourOhFourRequest);
191
+ if (fourOhFourRouteData) {
192
+ return this.render(fourOhFourRequest, fourOhFourRouteData);
193
+ }
194
+ }
195
+ return response.response;
196
+ } else {
197
+ const body = response.body;
198
+ const headers = new Headers();
199
+ const mimeType = mime.getType(url.pathname);
200
+ if (mimeType) {
201
+ headers.set("Content-Type", `${mimeType};charset=utf-8`);
202
+ } else {
203
+ headers.set("Content-Type", "text/plain;charset=utf-8");
204
+ }
205
+ const bytes = this.#encoder.encode(body);
206
+ headers.set("Content-Length", bytes.byteLength.toString());
207
+ const newResponse = new Response(bytes, {
208
+ status: 200,
209
+ headers
210
+ });
211
+ attachToResponse(newResponse, response.cookies);
212
+ return newResponse;
213
+ }
157
214
  }
158
215
  }
159
216
  setCookieHeaders(response) {
160
217
  return getSetCookiesFromResponse(response);
161
218
  }
219
+ /**
220
+ * Creates the render context of the current route
221
+ */
222
+ async #createRenderContext(url, request, routeData, page, status = 200) {
223
+ if (routeData.type === "endpoint") {
224
+ const pathname = "/" + this.removeBase(url.pathname);
225
+ const mod = await page.page();
226
+ const handler = mod;
227
+ return await createRenderContext({
228
+ request,
229
+ pathname,
230
+ route: routeData,
231
+ status,
232
+ env: this.#env,
233
+ mod: handler
234
+ });
235
+ } else {
236
+ const pathname = prependForwardSlash(this.removeBase(url.pathname));
237
+ const info = this.#routeDataToRouteInfo.get(routeData);
238
+ const links = /* @__PURE__ */ new Set();
239
+ const styles = createStylesheetElementSet(info.styles);
240
+ let scripts = /* @__PURE__ */ new Set();
241
+ for (const script of info.scripts) {
242
+ if ("stage" in script) {
243
+ if (script.stage === "head-inline") {
244
+ scripts.add({
245
+ props: {},
246
+ children: script.children
247
+ });
248
+ }
249
+ } else {
250
+ scripts.add(createModuleScriptElement(script));
251
+ }
252
+ }
253
+ const mod = await page.page();
254
+ return await createRenderContext({
255
+ request,
256
+ pathname,
257
+ componentMetadata: this.#manifest.componentMetadata,
258
+ scripts,
259
+ styles,
260
+ links,
261
+ route: routeData,
262
+ status,
263
+ mod,
264
+ env: this.#env
265
+ });
266
+ }
267
+ }
162
268
  async #getModuleForRoute(route) {
163
269
  if (route.type === "redirect") {
164
270
  return RedirectSinglePageBuiltModule;
@@ -182,92 +288,6 @@ class App {
182
288
  }
183
289
  }
184
290
  }
185
- async #renderPage(request, routeData, page, status = 200) {
186
- const url = new URL(request.url);
187
- const pathname = prependForwardSlash(this.removeBase(url.pathname));
188
- const info = this.#routeDataToRouteInfo.get(routeData);
189
- const links = /* @__PURE__ */ new Set();
190
- const styles = createStylesheetElementSet(info.styles);
191
- let scripts = /* @__PURE__ */ new Set();
192
- for (const script of info.scripts) {
193
- if ("stage" in script) {
194
- if (script.stage === "head-inline") {
195
- scripts.add({
196
- props: {},
197
- children: script.children
198
- });
199
- }
200
- } else {
201
- scripts.add(createModuleScriptElement(script));
202
- }
203
- }
204
- try {
205
- const mod = await page.page();
206
- const renderContext = await createRenderContext({
207
- request,
208
- pathname,
209
- componentMetadata: this.#manifest.componentMetadata,
210
- scripts,
211
- styles,
212
- links,
213
- route: routeData,
214
- status,
215
- mod,
216
- env: this.#env
217
- });
218
- const response = await tryRenderPage(renderContext, this.#env, mod, page.onRequest);
219
- Reflect.set(request, responseSentSymbol, true);
220
- return response;
221
- } catch (err) {
222
- error(this.#logging, "ssr", err.stack || err.message || String(err));
223
- return new Response(null, {
224
- status: 500,
225
- statusText: "Internal server error"
226
- });
227
- }
228
- }
229
- async #callEndpoint(request, routeData, page, status = 200) {
230
- const url = new URL(request.url);
231
- const pathname = "/" + this.removeBase(url.pathname);
232
- const mod = await page.page();
233
- const handler = mod;
234
- const ctx = await createRenderContext({
235
- request,
236
- pathname,
237
- route: routeData,
238
- status,
239
- env: this.#env,
240
- mod: handler
241
- });
242
- const result = await callEndpoint(handler, this.#env, ctx, page.onRequest);
243
- if (result.type === "response") {
244
- if (result.response.headers.get("X-Astro-Response") === "Not-Found") {
245
- const fourOhFourRequest = new Request(new URL("/404", request.url));
246
- const fourOhFourRouteData = this.match(fourOhFourRequest);
247
- if (fourOhFourRouteData) {
248
- return this.render(fourOhFourRequest, fourOhFourRouteData);
249
- }
250
- }
251
- return result.response;
252
- } else {
253
- const body = result.body;
254
- const headers = new Headers();
255
- const mimeType = mime.getType(url.pathname);
256
- if (mimeType) {
257
- headers.set("Content-Type", `${mimeType};charset=utf-8`);
258
- } else {
259
- headers.set("Content-Type", "text/plain;charset=utf-8");
260
- }
261
- const bytes = this.#encoder.encode(body);
262
- headers.set("Content-Length", bytes.byteLength.toString());
263
- const response = new Response(bytes, {
264
- status: 200,
265
- headers
266
- });
267
- attachToResponse(response, result.cookies);
268
- return response;
269
- }
270
- }
271
291
  }
272
292
  export {
273
293
  App,
@@ -20,15 +20,11 @@ import {
20
20
  import { runHookBuildGenerated } from "../../integrations/index.js";
21
21
  import { isServerLikeOutput } from "../../prerender/utils.js";
22
22
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
23
- import { callEndpoint, throwIfRedirectNotAllowed } from "../endpoint/index.js";
24
23
  import { AstroError, AstroErrorData } from "../errors/index.js";
25
24
  import { debug, info } from "../logger/core.js";
26
- import {
27
- getRedirectLocationOrThrow,
28
- RedirectSinglePageBuiltModule,
29
- routeIsRedirect
30
- } from "../redirects/index.js";
31
- import { createEnvironment, createRenderContext, tryRenderPage } from "../render/index.js";
25
+ import { RedirectSinglePageBuiltModule, getRedirectLocationOrThrow } from "../redirects/index.js";
26
+ import { isEndpointResult } from "../render/core.js";
27
+ import { createEnvironment, createRenderContext, tryRenderRoute } from "../render/index.js";
32
28
  import { callGetStaticPaths } from "../render/route-cache.js";
33
29
  import {
34
30
  createAssetLink,
@@ -165,9 +161,6 @@ async function generateImage(opts, transform, path) {
165
161
  info(opts.logging, null, ` ${green("\u25B6")} ${path} ${dim(statsText)} ${dim(timeIncrease)}`);
166
162
  }
167
163
  async function generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest) {
168
- if (routeIsRedirect(pageData.route) && !opts.settings.config.experimental.redirects) {
169
- throw new Error(`To use redirects first set experimental.redirects to \`true\``);
170
- }
171
164
  let timeStart = performance.now();
172
165
  const pageInfo = getPageDataByComponent(internals, pageData.route.component);
173
166
  const linkIds = [];
@@ -399,34 +392,26 @@ async function generatePath(pathname, opts, gopts, manifest, onRequest) {
399
392
  });
400
393
  let body;
401
394
  let encoding;
402
- if (pageData.route.type === "endpoint") {
403
- const endpointHandler = mod;
404
- const result = await callEndpoint(
405
- endpointHandler,
406
- env,
407
- renderContext,
408
- onRequest
409
- );
410
- if (result.type === "response") {
411
- throwIfRedirectNotAllowed(result.response, opts.settings.config);
412
- if (!result.response.body)
395
+ let response;
396
+ try {
397
+ response = await tryRenderRoute(pageData.route.type, renderContext, env, mod, onRequest);
398
+ } catch (err) {
399
+ if (!AstroError.is(err) && !err.id && typeof err === "object") {
400
+ err.id = pageData.component;
401
+ }
402
+ throw err;
403
+ }
404
+ if (isEndpointResult(response, pageData.route.type)) {
405
+ if (response.type === "response") {
406
+ if (!response.response.body)
413
407
  return;
414
- const ab = await result.response.arrayBuffer();
408
+ const ab = await response.response.arrayBuffer();
415
409
  body = new Uint8Array(ab);
416
410
  } else {
417
- body = result.body;
418
- encoding = result.encoding;
411
+ body = response.body;
412
+ encoding = response.encoding;
419
413
  }
420
414
  } else {
421
- let response;
422
- try {
423
- response = await tryRenderPage(renderContext, env, mod, onRequest);
424
- } catch (err) {
425
- if (!AstroError.is(err) && !err.id && typeof err === "object") {
426
- err.id = pageData.component;
427
- }
428
- throw err;
429
- }
430
415
  if (response.status >= 300 && response.status < 400) {
431
416
  if (!opts.settings.config.build.redirects) {
432
417
  return;
@@ -21,7 +21,7 @@ function* walkParentInfos(id, ctx, until, depth = 0, order = 0, seen = /* @__PUR
21
21
  if (seen.has(imp)) {
22
22
  continue;
23
23
  }
24
- yield* walkParentInfos(imp, ctx, until, ++depth, order, seen, id);
24
+ yield* walkParentInfos(imp, ctx, until, depth + 1, order, seen, id);
25
25
  }
26
26
  }
27
27
  function moduleIsTopLevelPage(info) {