astro 6.2.1 → 6.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.
Files changed (137) hide show
  1. package/dist/actions/handler.d.ts +32 -0
  2. package/dist/actions/handler.js +45 -0
  3. package/dist/actions/runtime/server.js +1 -1
  4. package/dist/assets/build/generate.js +1 -1
  5. package/dist/assets/build/remote.d.ts +3 -2
  6. package/dist/assets/build/remote.js +16 -9
  7. package/dist/assets/endpoint/generic.js +4 -7
  8. package/dist/assets/endpoint/shared.js +7 -2
  9. package/dist/assets/index.d.ts +1 -0
  10. package/dist/assets/index.js +2 -0
  11. package/dist/assets/internal.js +16 -1
  12. package/dist/assets/services/sharp.js +16 -1
  13. package/dist/assets/utils/index.d.ts +1 -0
  14. package/dist/assets/utils/index.js +2 -0
  15. package/dist/assets/utils/redirectValidation.d.ts +48 -0
  16. package/dist/assets/utils/redirectValidation.js +48 -0
  17. package/dist/assets/utils/remoteProbe.js +25 -2
  18. package/dist/cli/add/index.js +7 -4
  19. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  20. package/dist/container/index.js +18 -14
  21. package/dist/content/content-layer.js +3 -4
  22. package/dist/content/loaders/types.d.ts +1 -1
  23. package/dist/content/server-listeners.js +0 -4
  24. package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
  25. package/dist/core/app/base.d.ts +33 -15
  26. package/dist/core/app/base.js +120 -324
  27. package/dist/core/app/dev/app.d.ts +3 -2
  28. package/dist/core/app/dev/app.js +4 -60
  29. package/dist/core/app/entrypoints/virtual/dev.js +2 -0
  30. package/dist/core/app/entrypoints/virtual/prod.js +4 -1
  31. package/dist/core/app/prepare-response.d.ts +11 -0
  32. package/dist/core/app/prepare-response.js +18 -0
  33. package/dist/core/app/render-options.d.ts +11 -0
  34. package/dist/core/app/render-options.js +11 -0
  35. package/dist/core/base-pipeline.d.ts +38 -1
  36. package/dist/core/base-pipeline.js +50 -7
  37. package/dist/core/build/app.d.ts +3 -4
  38. package/dist/core/build/app.js +3 -17
  39. package/dist/core/build/plugins/plugin-css.js +7 -1
  40. package/dist/core/build/plugins/plugin-manifest.js +11 -1
  41. package/dist/core/build/static-build.js +16 -2
  42. package/dist/core/cache/handler.d.ts +29 -0
  43. package/dist/core/cache/handler.js +81 -0
  44. package/dist/core/compile/style.js +18 -1
  45. package/dist/core/config/index.d.ts +1 -1
  46. package/dist/core/config/index.js +4 -1
  47. package/dist/core/config/schemas/base.d.ts +4 -0
  48. package/dist/core/config/schemas/base.js +4 -0
  49. package/dist/core/config/schemas/relative.d.ts +6 -0
  50. package/dist/core/config/settings.js +2 -4
  51. package/dist/core/config/tsconfig.d.ts +24 -9
  52. package/dist/core/config/tsconfig.js +54 -45
  53. package/dist/core/constants.d.ts +27 -1
  54. package/dist/core/constants.js +14 -1
  55. package/dist/core/cookies/cookies.d.ts +7 -2
  56. package/dist/core/cookies/cookies.js +11 -4
  57. package/dist/core/cookies/response.d.ts +1 -1
  58. package/dist/core/cookies/response.js +1 -2
  59. package/dist/core/create-vite.js +15 -0
  60. package/dist/core/csp/runtime.js +6 -4
  61. package/dist/core/dev/dev.js +1 -1
  62. package/dist/core/errors/build-handler.d.ts +17 -0
  63. package/dist/core/errors/build-handler.js +22 -0
  64. package/dist/core/errors/default-handler.d.ts +14 -0
  65. package/dist/core/errors/default-handler.js +144 -0
  66. package/dist/core/errors/dev-handler.d.ts +21 -0
  67. package/dist/core/errors/dev-handler.js +82 -0
  68. package/dist/core/errors/handler.d.ts +9 -0
  69. package/dist/core/errors/handler.js +0 -0
  70. package/dist/core/fetch/default-handler.d.ts +17 -0
  71. package/dist/core/fetch/default-handler.js +45 -0
  72. package/dist/core/fetch/fetch-state.d.ts +244 -0
  73. package/dist/core/fetch/fetch-state.js +779 -0
  74. package/dist/core/fetch/index.d.ts +61 -0
  75. package/dist/core/fetch/index.js +121 -0
  76. package/dist/core/fetch/types.d.ts +6 -0
  77. package/dist/core/fetch/types.js +0 -0
  78. package/dist/core/fetch/vite-plugin.d.ts +5 -0
  79. package/dist/core/fetch/vite-plugin.js +69 -0
  80. package/dist/core/hono/index.d.ts +21 -0
  81. package/dist/core/hono/index.js +98 -0
  82. package/dist/core/i18n/handler.d.ts +18 -0
  83. package/dist/core/i18n/handler.js +119 -0
  84. package/dist/core/logger/core.d.ts +8 -0
  85. package/dist/core/logger/core.js +16 -0
  86. package/dist/core/messages/runtime.js +1 -1
  87. package/dist/core/middleware/astro-middleware.d.ts +27 -0
  88. package/dist/core/middleware/astro-middleware.js +53 -0
  89. package/dist/core/pages/handler.d.ts +20 -0
  90. package/dist/core/pages/handler.js +74 -0
  91. package/dist/core/redirects/render.d.ts +2 -2
  92. package/dist/core/redirects/render.js +7 -8
  93. package/dist/core/render/params-and-props.js +1 -1
  94. package/dist/core/render/slots.js +9 -2
  95. package/dist/core/rewrites/handler.d.ts +37 -0
  96. package/dist/core/rewrites/handler.js +67 -0
  97. package/dist/core/routing/3xx.js +8 -4
  98. package/dist/core/routing/handler.d.ts +17 -0
  99. package/dist/core/routing/handler.js +172 -0
  100. package/dist/core/routing/match.d.ts +0 -7
  101. package/dist/core/routing/match.js +0 -5
  102. package/dist/core/routing/pattern.js +1 -1
  103. package/dist/core/routing/rewrite.js +1 -4
  104. package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
  105. package/dist/core/routing/trailing-slash-handler.js +67 -0
  106. package/dist/core/session/drivers.d.ts +1 -1
  107. package/dist/core/session/handler.d.ts +11 -0
  108. package/dist/core/session/handler.js +33 -0
  109. package/dist/core/session/runtime.js +7 -2
  110. package/dist/core/util/normalized-url.d.ts +10 -0
  111. package/dist/core/util/normalized-url.js +21 -0
  112. package/dist/i18n/middleware.d.ts +10 -0
  113. package/dist/i18n/middleware.js +4 -88
  114. package/dist/i18n/utils.js +2 -2
  115. package/dist/prefetch/index.js +12 -7
  116. package/dist/runtime/server/astro-island.js +57 -20
  117. package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
  118. package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
  119. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  120. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  121. package/dist/runtime/server/render/common.js +10 -4
  122. package/dist/runtime/server/render/server-islands.js +2 -1
  123. package/dist/runtime/server/scripts.js +6 -0
  124. package/dist/types/public/config.d.ts +46 -12
  125. package/dist/types/public/content.d.ts +4 -4
  126. package/dist/types/public/internal.d.ts +1 -1
  127. package/dist/vite-plugin-app/app.d.ts +4 -5
  128. package/dist/vite-plugin-app/app.js +20 -68
  129. package/dist/vite-plugin-astro/compile.js +2 -2
  130. package/dist/vite-plugin-astro/utils.d.ts +1 -0
  131. package/dist/vite-plugin-astro/utils.js +9 -1
  132. package/dist/vite-plugin-head/index.js +36 -19
  133. package/dist/vite-plugin-utils/index.d.ts +1 -0
  134. package/dist/vite-plugin-utils/index.js +3 -0
  135. package/package.json +13 -6
  136. package/dist/core/render-context.d.ts +0 -77
  137. package/dist/core/render-context.js +0 -826
@@ -0,0 +1,61 @@
1
+ import { FetchState as BaseFetchState } from './fetch-state.js';
2
+ import type { AstroFetchState } from './fetch-state.js';
3
+ export type { AstroFetchState };
4
+ export declare class FetchState extends BaseFetchState {
5
+ constructor(request: Request);
6
+ }
7
+ export declare function astro(state: FetchState): Promise<Response>;
8
+ /**
9
+ * Checks if the request pathname needs trailing-slash normalization and
10
+ * returns a redirect `Response` if so. Returns `undefined` when no
11
+ * redirect is needed and the caller should continue processing.
12
+ */
13
+ export declare function trailingSlash(state: FetchState): Response | undefined;
14
+ /**
15
+ * Runs Astro's middleware chain for the given state, calling `next` at
16
+ * the bottom of the chain to produce the response. Lazily creates
17
+ * the render context if needed.
18
+ */
19
+ export declare function middleware(state: FetchState, next: (state: FetchState) => Promise<Response>): Promise<Response>;
20
+ /**
21
+ * Dispatches the request to the matched route (endpoint, page, redirect,
22
+ * or fallback). Lazily creates the render context if needed.
23
+ */
24
+ export declare function pages(state: FetchState): Promise<Response>;
25
+ /**
26
+ * Registers the session provider on the state. The session is created
27
+ * lazily when user code accesses `ctx.session`, and persisted when
28
+ * `state.finalizeAll()` is called. No-op if sessions are not configured.
29
+ *
30
+ * Call this early (before middleware runs). Call `state.finalizeAll()`
31
+ * in a `finally` block after the response is produced to persist
32
+ * any session mutations.
33
+ */
34
+ export declare function sessions(state: FetchState): Promise<void> | void;
35
+ /**
36
+ * Checks if the matched route is a redirect and returns the redirect
37
+ * `Response` if so. Returns `undefined` when the route is not a
38
+ * redirect and the caller should continue processing.
39
+ * `state.routeData` must be set before calling this.
40
+ */
41
+ export declare function redirects(state: FetchState): Promise<Response> | undefined;
42
+ /**
43
+ * Handles Astro Action requests (RPC + form). Returns a `Response` for
44
+ * RPC actions, or `undefined` for form actions / non-action requests
45
+ * (the caller should continue to page rendering). Lazily creates
46
+ * the render context if needed.
47
+ */
48
+ export declare function actions(state: FetchState): Promise<Response | undefined> | undefined;
49
+ /**
50
+ * Post-processes a response against the app's i18n configuration.
51
+ * Handles locale redirects, 404s for invalid locales, and fallback
52
+ * routing. Returns the response unmodified if i18n is not configured.
53
+ */
54
+ export declare function i18n(state: FetchState, response: Response): Promise<Response>;
55
+ /**
56
+ * Wraps a render callback with cache provider logic. Handles runtime
57
+ * caching (onRequest), CDN-based providers (headers only), and the
58
+ * no-cache case transparently. Cache headers are applied and stripped
59
+ * internally.
60
+ */
61
+ export declare function cache(state: FetchState, next: () => Promise<Response>): Promise<Response>;
@@ -0,0 +1,121 @@
1
+ import { ActionHandler } from "../../actions/handler.js";
2
+ import { FetchState as BaseFetchState } from "./fetch-state.js";
3
+ import { CacheHandler } from "../cache/handler.js";
4
+ import { appSymbol } from "../constants.js";
5
+ import { I18n } from "../i18n/handler.js";
6
+ import { AstroMiddleware } from "../middleware/astro-middleware.js";
7
+ import { PagesHandler } from "../pages/handler.js";
8
+ import { renderRedirect } from "../redirects/render.js";
9
+ import { AstroHandler } from "../routing/handler.js";
10
+ import { provideSession } from "../session/handler.js";
11
+ import { TrailingSlashHandler } from "../routing/trailing-slash-handler.js";
12
+ function getApp(request) {
13
+ const app = Reflect.get(request, appSymbol);
14
+ if (!app) {
15
+ throw new Error(
16
+ "FetchState(request) called on a request without an attached app. Ensure it runs inside Astro's request pipeline."
17
+ );
18
+ }
19
+ return app;
20
+ }
21
+ class FetchState extends BaseFetchState {
22
+ constructor(request) {
23
+ super(getApp(request).pipeline, request);
24
+ }
25
+ }
26
+ const astroHandlers = /* @__PURE__ */ new WeakMap();
27
+ function astro(state) {
28
+ const app = getApp(state.request);
29
+ let handler = astroHandlers.get(app);
30
+ if (!handler) {
31
+ handler = new AstroHandler(app);
32
+ astroHandlers.set(app, handler);
33
+ }
34
+ return handler.handle(state);
35
+ }
36
+ const trailingSlashHandlers = /* @__PURE__ */ new WeakMap();
37
+ function trailingSlash(state) {
38
+ const app = getApp(state.request);
39
+ let handler = trailingSlashHandlers.get(app);
40
+ if (!handler) {
41
+ handler = new TrailingSlashHandler(app);
42
+ trailingSlashHandlers.set(app, handler);
43
+ }
44
+ return handler.handle(state);
45
+ }
46
+ const middlewareInstances = /* @__PURE__ */ new WeakMap();
47
+ function middleware(state, next) {
48
+ const app = getApp(state.request);
49
+ let mw = middlewareInstances.get(app);
50
+ if (!mw) {
51
+ mw = new AstroMiddleware(app.pipeline);
52
+ middlewareInstances.set(app, mw);
53
+ }
54
+ return mw.handle(state, (s, _ctx) => next(s));
55
+ }
56
+ const pagesHandlers = /* @__PURE__ */ new WeakMap();
57
+ function pages(state) {
58
+ const app = getApp(state.request);
59
+ let handler = pagesHandlers.get(app);
60
+ if (!handler) {
61
+ handler = new PagesHandler(app.pipeline);
62
+ pagesHandlers.set(app, handler);
63
+ }
64
+ return handler.handle(state, state.getAPIContext());
65
+ }
66
+ function sessions(state) {
67
+ return provideSession(state);
68
+ }
69
+ function redirects(state) {
70
+ if (state.routeData?.type === "redirect") {
71
+ return renderRedirect(state);
72
+ }
73
+ return void 0;
74
+ }
75
+ const actionHandlers = /* @__PURE__ */ new WeakMap();
76
+ function actions(state) {
77
+ const app = getApp(state.request);
78
+ let handler = actionHandlers.get(app);
79
+ if (!handler) {
80
+ handler = new ActionHandler();
81
+ actionHandlers.set(app, handler);
82
+ }
83
+ return handler.handle(state.getAPIContext(), state);
84
+ }
85
+ const i18nHandlers = /* @__PURE__ */ new WeakMap();
86
+ function getI18n(app) {
87
+ let handler = i18nHandlers.get(app);
88
+ if (handler === void 0) {
89
+ const config = app.manifest.i18n;
90
+ handler = config && config.strategy !== "manual" ? new I18n(config, app.manifest.base, app.manifest.trailingSlash, app.manifest.buildFormat) : null;
91
+ i18nHandlers.set(app, handler);
92
+ }
93
+ return handler;
94
+ }
95
+ function i18n(state, response) {
96
+ const handler = getI18n(getApp(state.request));
97
+ if (!handler) return Promise.resolve(response);
98
+ return handler.finalize(state, response);
99
+ }
100
+ const cacheHandlers = /* @__PURE__ */ new WeakMap();
101
+ function cache(state, next) {
102
+ const app = getApp(state.request);
103
+ let handler = cacheHandlers.get(app);
104
+ if (!handler) {
105
+ handler = new CacheHandler(app);
106
+ cacheHandlers.set(app, handler);
107
+ }
108
+ return handler.handle(state, next);
109
+ }
110
+ export {
111
+ FetchState,
112
+ actions,
113
+ astro,
114
+ cache,
115
+ i18n,
116
+ middleware,
117
+ pages,
118
+ redirects,
119
+ sessions,
120
+ trailingSlash
121
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A framework-agnostic request handler. Takes a standard `Request` and
3
+ * returns a `Response`. This mirrors the Web Fetch API handler shape, which
4
+ * lets handlers compose easily with other middleware systems later.
5
+ */
6
+ export type FetchHandler = (request: Request) => Promise<Response>;
File without changes
@@ -0,0 +1,5 @@
1
+ import { type Plugin as VitePlugin } from 'vite';
2
+ import type { AstroSettings } from '../../types/astro.js';
3
+ export declare function vitePluginFetchable({ settings }: {
4
+ settings: AstroSettings;
5
+ }): VitePlugin;
@@ -0,0 +1,69 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import {
3
+ normalizePath as viteNormalizePath
4
+ } from "vite";
5
+ import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../constants.js";
6
+ const FETCHABLE_MODULE_ID = "virtual:astro:fetchable";
7
+ const FETCHABLE_RESOLVED_MODULE_ID = "\0" + FETCHABLE_MODULE_ID;
8
+ const APP_PATH_SEGMENT_NAME = "app";
9
+ function vitePluginFetchable({ settings }) {
10
+ let resolvedUserAppId;
11
+ let userAppPresent = false;
12
+ const advancedRoutingEnabled = settings.config.experimental.advancedRouting;
13
+ const normalizedSrcDir = viteNormalizePath(fileURLToPath(settings.config.srcDir));
14
+ return {
15
+ name: "@astro/plugin-fetchable",
16
+ applyToEnvironment(environment) {
17
+ return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.astro || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender;
18
+ },
19
+ configureServer(server) {
20
+ server.watcher.on("change", (path) => {
21
+ const normalizedPath = viteNormalizePath(path);
22
+ if (!normalizedPath.startsWith(normalizedSrcDir)) return;
23
+ const relativePath = normalizedPath.slice(normalizedSrcDir.length);
24
+ if (!relativePath.startsWith(`${APP_PATH_SEGMENT_NAME}.`)) return;
25
+ for (const name of [
26
+ ASTRO_VITE_ENVIRONMENT_NAMES.ssr,
27
+ ASTRO_VITE_ENVIRONMENT_NAMES.astro
28
+ ]) {
29
+ const environment = server.environments[name];
30
+ if (!environment) continue;
31
+ const virtualMod = environment.moduleGraph.getModuleById(FETCHABLE_RESOLVED_MODULE_ID);
32
+ if (virtualMod) {
33
+ environment.moduleGraph.invalidateModule(virtualMod);
34
+ }
35
+ }
36
+ });
37
+ },
38
+ resolveId: {
39
+ filter: {
40
+ id: new RegExp(`^${FETCHABLE_MODULE_ID}$`)
41
+ },
42
+ async handler() {
43
+ const resolved = await this.resolve(`${normalizedSrcDir}${APP_PATH_SEGMENT_NAME}`);
44
+ userAppPresent = advancedRoutingEnabled && !!resolved;
45
+ resolvedUserAppId = resolved?.id;
46
+ return FETCHABLE_RESOLVED_MODULE_ID;
47
+ }
48
+ },
49
+ load: {
50
+ filter: {
51
+ id: new RegExp(`^${FETCHABLE_RESOLVED_MODULE_ID}$`)
52
+ },
53
+ handler() {
54
+ if (userAppPresent && resolvedUserAppId) {
55
+ return {
56
+ code: `export { default } from '${resolvedUserAppId}';`
57
+ };
58
+ }
59
+ return {
60
+ code: `import { DefaultFetchHandler } from 'astro/app/fetch/default-handler';
61
+ export default new DefaultFetchHandler();`
62
+ };
63
+ }
64
+ }
65
+ };
66
+ }
67
+ export {
68
+ vitePluginFetchable
69
+ };
@@ -0,0 +1,21 @@
1
+ import { FetchState } from '../fetch/index.js';
2
+ export { FetchState };
3
+ export type { AstroFetchState } from '../fetch/index.js';
4
+ type HonoContextLike = {
5
+ req: {
6
+ raw: Request;
7
+ };
8
+ res: Response;
9
+ get?: (key: string) => unknown;
10
+ set?: (key: string, value: unknown) => void;
11
+ };
12
+ type HonoMiddlewareHandler = (context: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
13
+ export declare function astro(): HonoMiddlewareHandler;
14
+ export declare function trailingSlash(): HonoMiddlewareHandler;
15
+ export declare function middleware(): HonoMiddlewareHandler;
16
+ export declare function redirects(): HonoMiddlewareHandler;
17
+ export declare function actions(): HonoMiddlewareHandler;
18
+ export declare function pages(): HonoMiddlewareHandler;
19
+ export declare function sessions(): HonoMiddlewareHandler;
20
+ export declare function cache(next: () => Promise<Response>): HonoMiddlewareHandler;
21
+ export declare function i18n(): HonoMiddlewareHandler;
@@ -0,0 +1,98 @@
1
+ import {
2
+ FetchState,
3
+ actions as fetchActions,
4
+ astro as fetchAstro,
5
+ cache as fetchCache,
6
+ i18n as fetchI18n,
7
+ middleware as fetchMiddleware,
8
+ pages as fetchPages,
9
+ redirects as fetchRedirects,
10
+ sessions as fetchSessions,
11
+ trailingSlash as fetchTrailingSlash
12
+ } from "../fetch/index.js";
13
+ const FETCH_STATE_KEY = "fetchState";
14
+ function getFetchState(context) {
15
+ const state = context.get?.(FETCH_STATE_KEY);
16
+ if (state) {
17
+ return state;
18
+ }
19
+ const nextState = new FetchState(context.req.raw);
20
+ context.set?.(FETCH_STATE_KEY, nextState);
21
+ return nextState;
22
+ }
23
+ function astro() {
24
+ return async (context, _next) => {
25
+ return fetchAstro(getFetchState(context));
26
+ };
27
+ }
28
+ function trailingSlash() {
29
+ return async (context, honoNext) => {
30
+ const redirect = fetchTrailingSlash(getFetchState(context));
31
+ if (redirect) return redirect;
32
+ await honoNext();
33
+ };
34
+ }
35
+ function middleware() {
36
+ return async (context, honoNext) => {
37
+ return fetchMiddleware(getFetchState(context), async () => {
38
+ await honoNext();
39
+ return context.res;
40
+ });
41
+ };
42
+ }
43
+ function redirects() {
44
+ return async (context, honoNext) => {
45
+ const response = fetchRedirects(getFetchState(context));
46
+ if (response) return response;
47
+ await honoNext();
48
+ };
49
+ }
50
+ function actions() {
51
+ return async (context, honoNext) => {
52
+ const result = fetchActions(getFetchState(context));
53
+ if (result) {
54
+ const response = await result;
55
+ if (response) return response;
56
+ }
57
+ await honoNext();
58
+ };
59
+ }
60
+ function pages() {
61
+ return async (context, _honoNext) => {
62
+ return fetchPages(getFetchState(context));
63
+ };
64
+ }
65
+ function sessions() {
66
+ return async (context, honoNext) => {
67
+ const state = getFetchState(context);
68
+ await fetchSessions(state);
69
+ try {
70
+ await honoNext();
71
+ } finally {
72
+ await state.finalizeAll();
73
+ }
74
+ };
75
+ }
76
+ function cache(next) {
77
+ return async (context, _honoNext) => {
78
+ return fetchCache(getFetchState(context), next);
79
+ };
80
+ }
81
+ function i18n() {
82
+ return async (context, honoNext) => {
83
+ await honoNext();
84
+ context.res = await fetchI18n(getFetchState(context), context.res);
85
+ };
86
+ }
87
+ export {
88
+ FetchState,
89
+ actions,
90
+ astro,
91
+ cache,
92
+ i18n,
93
+ middleware,
94
+ pages,
95
+ redirects,
96
+ sessions,
97
+ trailingSlash
98
+ };
@@ -0,0 +1,18 @@
1
+ import type { SSRManifest } from '../app/types.js';
2
+ import type { FetchState } from '../fetch/fetch-state.js';
3
+ /**
4
+ * Post-processes a rendered `Response` against the app's i18n
5
+ * configuration. This is the logic that previously ran as the internal
6
+ * `createI18nMiddleware` middleware — lifted out of the middleware layer
7
+ * so it runs as an explicit step in `AstroHandler.render` after the
8
+ * middleware chain returns.
9
+ *
10
+ * Public entry points in `astro:i18n` (`createMiddleware`) preserve the
11
+ * middleware-shaped API by wrapping an `I18n` instance in a
12
+ * `MiddlewareHandler` closure.
13
+ */
14
+ export declare class I18n {
15
+ #private;
16
+ constructor(i18n: NonNullable<SSRManifest['i18n']>, base: SSRManifest['base'], trailingSlash: SSRManifest['trailingSlash'], format: SSRManifest['buildFormat']);
17
+ finalize(state: FetchState, response: Response): Promise<Response>;
18
+ }
@@ -0,0 +1,119 @@
1
+ import { appendForwardSlash } from "@astrojs/internal-helpers/path";
2
+ import { computeFallbackRoute } from "../../i18n/fallback.js";
3
+ import { I18nRouter } from "../../i18n/router.js";
4
+ import { PipelineFeatures } from "../base-pipeline.js";
5
+ import { shouldAppendForwardSlash } from "../build/util.js";
6
+ import { REROUTE_DIRECTIVE_HEADER, ROUTE_TYPE_HEADER } from "../constants.js";
7
+ class I18n {
8
+ #i18n;
9
+ #base;
10
+ #trailingSlash;
11
+ #format;
12
+ #router;
13
+ constructor(i18n, base, trailingSlash, format) {
14
+ this.#i18n = i18n;
15
+ this.#base = base;
16
+ this.#trailingSlash = trailingSlash;
17
+ this.#format = format;
18
+ this.#router = new I18nRouter({
19
+ strategy: i18n.strategy,
20
+ defaultLocale: i18n.defaultLocale,
21
+ locales: i18n.locales,
22
+ base,
23
+ domains: i18n.domainLookupTable ? Object.keys(i18n.domainLookupTable).reduce(
24
+ (acc, domain) => {
25
+ const locale = i18n.domainLookupTable[domain];
26
+ if (!acc[domain]) {
27
+ acc[domain] = [];
28
+ }
29
+ acc[domain].push(locale);
30
+ return acc;
31
+ },
32
+ {}
33
+ ) : void 0
34
+ });
35
+ }
36
+ async finalize(state, response) {
37
+ state.pipeline.usedFeatures |= PipelineFeatures.i18n;
38
+ const i18n = this.#i18n;
39
+ const typeHeader = response.headers.get(ROUTE_TYPE_HEADER);
40
+ const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER);
41
+ if (isReroute === "no" && typeof i18n.fallback === "undefined") {
42
+ return response;
43
+ }
44
+ if (typeHeader !== "page" && typeHeader !== "fallback") {
45
+ return response;
46
+ }
47
+ const url = new URL(state.request.url);
48
+ const currentLocale = state.computeCurrentLocale();
49
+ const isPrerendered = state.routeData.prerender;
50
+ const routerContext = {
51
+ currentLocale,
52
+ currentDomain: url.hostname,
53
+ routeType: typeHeader,
54
+ isReroute: isReroute === "yes"
55
+ };
56
+ const routeDecision = this.#router.match(url.pathname, routerContext);
57
+ switch (routeDecision.type) {
58
+ case "redirect": {
59
+ let location = routeDecision.location;
60
+ if (shouldAppendForwardSlash(this.#trailingSlash, this.#format)) {
61
+ location = appendForwardSlash(location);
62
+ }
63
+ return new Response(null, {
64
+ status: routeDecision.status ?? 302,
65
+ headers: { Location: location }
66
+ });
67
+ }
68
+ case "notFound": {
69
+ if (isPrerendered) {
70
+ const prerenderedRes = new Response(response.body, {
71
+ status: 404,
72
+ headers: response.headers
73
+ });
74
+ prerenderedRes.headers.set(REROUTE_DIRECTIVE_HEADER, "no");
75
+ if (routeDecision.location) {
76
+ prerenderedRes.headers.set("Location", routeDecision.location);
77
+ }
78
+ return prerenderedRes;
79
+ }
80
+ const headers = new Headers();
81
+ if (routeDecision.location) {
82
+ headers.set("Location", routeDecision.location);
83
+ }
84
+ return new Response(null, { status: 404, headers });
85
+ }
86
+ case "continue":
87
+ break;
88
+ }
89
+ if (i18n.fallback && i18n.fallbackType) {
90
+ const effectiveStatus = typeHeader === "fallback" ? 404 : response.status;
91
+ const fallbackDecision = computeFallbackRoute({
92
+ pathname: url.pathname,
93
+ responseStatus: effectiveStatus,
94
+ currentLocale,
95
+ fallback: i18n.fallback,
96
+ fallbackType: i18n.fallbackType,
97
+ locales: i18n.locales,
98
+ defaultLocale: i18n.defaultLocale,
99
+ strategy: i18n.strategy,
100
+ base: this.#base
101
+ });
102
+ switch (fallbackDecision.type) {
103
+ case "redirect":
104
+ return new Response(null, {
105
+ status: 302,
106
+ headers: { Location: fallbackDecision.pathname + url.search }
107
+ });
108
+ case "rewrite":
109
+ return await state.rewrite(fallbackDecision.pathname + url.search);
110
+ case "none":
111
+ break;
112
+ }
113
+ }
114
+ return response;
115
+ }
116
+ }
117
+ export {
118
+ I18n
119
+ };
@@ -100,5 +100,13 @@ export declare class AstroIntegrationLogger {
100
100
  warn(message: string): void;
101
101
  error(message: string): void;
102
102
  debug(message: string): void;
103
+ /**
104
+ * It calls the `flush` function of the provided destination, if it exists.
105
+ */
106
+ flush(): void;
107
+ /**
108
+ * It calls the `close` function of the provided destination, if it exists.
109
+ */
110
+ close(): void;
103
111
  }
104
112
  export {};
@@ -169,6 +169,22 @@ class AstroIntegrationLogger {
169
169
  debug(message) {
170
170
  debug(this.label, message);
171
171
  }
172
+ /**
173
+ * It calls the `flush` function of the provided destination, if it exists.
174
+ */
175
+ flush() {
176
+ if (this.options.destination.flush) {
177
+ this.options.destination.flush();
178
+ }
179
+ }
180
+ /**
181
+ * It calls the `close` function of the provided destination, if it exists.
182
+ */
183
+ close() {
184
+ if (this.options.destination.close) {
185
+ this.options.destination.close();
186
+ }
187
+ }
172
188
  }
173
189
  export {
174
190
  AstroIntegrationLogger,
@@ -276,7 +276,7 @@ function printHelp({
276
276
  message.push(
277
277
  linebreak(),
278
278
  ` ${bgGreen(black(` ${commandName} `))} ${green(
279
- `v${"6.2.1"}`
279
+ `v${"6.3.0"}`
280
280
  )} ${headline}`
281
281
  );
282
282
  }
@@ -0,0 +1,27 @@
1
+ import type { FetchState } from '../fetch/fetch-state.js';
2
+ import type { APIContext } from '../../types/public/context.js';
3
+ import { type Pipeline } from '../base-pipeline.js';
4
+ /**
5
+ * Callback invoked at the bottom of the middleware chain to dispatch the
6
+ * request to the matched route (endpoint / redirect / page / fallback).
7
+ *
8
+ * Callers of `AstroMiddleware.handle` pass their owned `PagesHandler`'s
9
+ * `handle` method (bound) so route dispatch logic stays out of the
10
+ * middleware layer.
11
+ */
12
+ export type RenderRouteCallback = (state: FetchState, ctx: APIContext) => Promise<Response>;
13
+ /**
14
+ * Handles the execution of Astro's middleware chain (internal + user) for a
15
+ * single render. Holds a reference to the `Pipeline` and composes the
16
+ * internal and user middleware at render time.
17
+ *
18
+ * Reads per-request data (componentInstance, slots, props, API contexts)
19
+ * off the supplied `FetchState`. The actual route dispatch (endpoint /
20
+ * redirect / page / fallback) is supplied by the caller as
21
+ * `renderRouteCallback` — typically bound to a `PagesHandler.handle`.
22
+ */
23
+ export declare class AstroMiddleware {
24
+ #private;
25
+ constructor(pipeline: Pipeline);
26
+ handle(state: FetchState, renderRouteCallback: RenderRouteCallback): Promise<Response>;
27
+ }
@@ -0,0 +1,53 @@
1
+ import { PipelineFeatures } from "../base-pipeline.js";
2
+ import { ROUTE_TYPE_HEADER } from "../constants.js";
3
+ import { attachCookiesToResponse } from "../cookies/index.js";
4
+ import { applyRewriteToState } from "../rewrites/handler.js";
5
+ import { callMiddleware } from "./callMiddleware.js";
6
+ import { sequence } from "./index.js";
7
+ class AstroMiddleware {
8
+ #pipeline;
9
+ constructor(pipeline) {
10
+ this.#pipeline = pipeline;
11
+ }
12
+ async handle(state, renderRouteCallback) {
13
+ state.pipeline.usedFeatures |= PipelineFeatures.middleware;
14
+ const pipeline = this.#pipeline;
15
+ await state.getProps();
16
+ const apiContext = state.getAPIContext();
17
+ state.counter++;
18
+ if (state.counter === 4) {
19
+ return new Response("Loop Detected", {
20
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/508
21
+ status: 508,
22
+ statusText: "Astro detected a loop where you tried to call the rewriting logic more than four times."
23
+ });
24
+ }
25
+ const next = async (ctx, payload) => {
26
+ if (payload) {
27
+ pipeline.logger.debug("router", "Called rewriting to:", payload);
28
+ const result = await pipeline.tryRewrite(payload, state.request);
29
+ applyRewriteToState(state, payload, result);
30
+ }
31
+ return renderRouteCallback(state, ctx);
32
+ };
33
+ let response;
34
+ if (state.skipMiddleware) {
35
+ response = await next(apiContext);
36
+ } else {
37
+ const pipelineMiddleware = await pipeline.getMiddleware();
38
+ const composed = sequence(...pipeline.internalMiddleware, pipelineMiddleware);
39
+ response = await callMiddleware(composed, apiContext, next);
40
+ }
41
+ return this.#finalize(state, response);
42
+ }
43
+ #finalize(state, response) {
44
+ if (response.headers.get(ROUTE_TYPE_HEADER)) {
45
+ response.headers.delete(ROUTE_TYPE_HEADER);
46
+ }
47
+ attachCookiesToResponse(response, state.cookies);
48
+ return response;
49
+ }
50
+ }
51
+ export {
52
+ AstroMiddleware
53
+ };
@@ -0,0 +1,20 @@
1
+ import type { APIContext } from '../../types/public/context.js';
2
+ import type { FetchState } from '../fetch/fetch-state.js';
3
+ import type { Pipeline } from '../base-pipeline.js';
4
+ /**
5
+ * Handles dispatch of a matched route (endpoint / redirect / page / fallback)
6
+ * at the bottom of the middleware chain. This is a pure dispatch layer — it
7
+ * renders whatever route the `FetchState` currently points to without any
8
+ * rewrite logic. Rewrites are handled upstream: `Rewrites.execute()` for
9
+ * `Astro.rewrite()` and `AstroMiddleware` for `next(payload)`.
10
+ *
11
+ * `PagesHandler` is the `next` callback that `AstroMiddleware` invokes at
12
+ * the end of the middleware chain. `AstroHandler` owns a single instance
13
+ * and passes its `handle` method as the callback. Error handlers and the
14
+ * container also use `PagesHandler` directly for the same dispatch behavior.
15
+ */
16
+ export declare class PagesHandler {
17
+ #private;
18
+ constructor(pipeline: Pipeline);
19
+ handle(state: FetchState, ctx: APIContext): Promise<Response>;
20
+ }