astro 6.2.2 → 6.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.
- package/dist/actions/handler.d.ts +32 -0
- package/dist/actions/handler.js +45 -0
- package/dist/actions/runtime/server.js +1 -1
- package/dist/assets/build/generate.js +1 -1
- package/dist/assets/build/remote.d.ts +3 -2
- package/dist/assets/build/remote.js +16 -9
- package/dist/assets/endpoint/generic.js +8 -20
- package/dist/assets/endpoint/loadImage.d.ts +11 -0
- package/dist/assets/endpoint/loadImage.js +19 -0
- package/dist/assets/endpoint/shared.js +7 -2
- package/dist/assets/index.d.ts +1 -0
- package/dist/assets/index.js +2 -0
- package/dist/assets/services/sharp.js +7 -0
- package/dist/assets/utils/index.d.ts +1 -0
- package/dist/assets/utils/index.js +2 -0
- package/dist/assets/utils/redirectValidation.d.ts +48 -0
- package/dist/assets/utils/redirectValidation.js +48 -0
- package/dist/assets/utils/remoteProbe.js +25 -2
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/container/index.js +18 -14
- package/dist/content/content-layer.js +3 -4
- package/dist/content/server-listeners.js +0 -4
- package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
- package/dist/core/app/base.d.ts +33 -15
- package/dist/core/app/base.js +120 -324
- package/dist/core/app/dev/app.d.ts +3 -2
- package/dist/core/app/dev/app.js +4 -60
- package/dist/core/app/entrypoints/virtual/dev.js +2 -0
- package/dist/core/app/entrypoints/virtual/prod.js +4 -1
- package/dist/core/app/prepare-response.d.ts +11 -0
- package/dist/core/app/prepare-response.js +18 -0
- package/dist/core/app/render-options.d.ts +11 -0
- package/dist/core/app/render-options.js +11 -0
- package/dist/core/base-pipeline.d.ts +38 -1
- package/dist/core/base-pipeline.js +50 -7
- package/dist/core/build/app.d.ts +3 -4
- package/dist/core/build/app.js +3 -17
- package/dist/core/cache/handler.d.ts +29 -0
- package/dist/core/cache/handler.js +81 -0
- package/dist/core/config/schemas/base.d.ts +4 -0
- package/dist/core/config/schemas/base.js +4 -0
- package/dist/core/config/schemas/relative.d.ts +6 -0
- package/dist/core/constants.d.ts +27 -1
- package/dist/core/constants.js +14 -1
- package/dist/core/cookies/cookies.d.ts +7 -2
- package/dist/core/cookies/cookies.js +11 -4
- package/dist/core/cookies/response.d.ts +1 -1
- package/dist/core/cookies/response.js +1 -2
- package/dist/core/create-vite.js +15 -0
- package/dist/core/csp/runtime.js +6 -4
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/build-handler.d.ts +17 -0
- package/dist/core/errors/build-handler.js +22 -0
- package/dist/core/errors/default-handler.d.ts +14 -0
- package/dist/core/errors/default-handler.js +144 -0
- package/dist/core/errors/dev-handler.d.ts +21 -0
- package/dist/core/errors/dev-handler.js +82 -0
- package/dist/core/errors/handler.d.ts +9 -0
- package/dist/core/errors/handler.js +0 -0
- package/dist/core/fetch/default-handler.d.ts +17 -0
- package/dist/core/fetch/default-handler.js +45 -0
- package/dist/core/fetch/fetch-state.d.ts +244 -0
- package/dist/core/fetch/fetch-state.js +779 -0
- package/dist/core/fetch/index.d.ts +61 -0
- package/dist/core/fetch/index.js +121 -0
- package/dist/core/fetch/types.d.ts +6 -0
- package/dist/core/fetch/types.js +0 -0
- package/dist/core/fetch/vite-plugin.d.ts +5 -0
- package/dist/core/fetch/vite-plugin.js +69 -0
- package/dist/core/hono/index.d.ts +21 -0
- package/dist/core/hono/index.js +98 -0
- package/dist/core/i18n/handler.d.ts +18 -0
- package/dist/core/i18n/handler.js +119 -0
- package/dist/core/logger/core.d.ts +8 -0
- package/dist/core/logger/core.js +16 -0
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/astro-middleware.d.ts +27 -0
- package/dist/core/middleware/astro-middleware.js +53 -0
- package/dist/core/pages/handler.d.ts +20 -0
- package/dist/core/pages/handler.js +74 -0
- package/dist/core/preview/static-preview-server.js +3 -1
- package/dist/core/redirects/render.d.ts +2 -2
- package/dist/core/redirects/render.js +7 -8
- package/dist/core/rewrites/handler.d.ts +37 -0
- package/dist/core/rewrites/handler.js +67 -0
- package/dist/core/routing/3xx.js +8 -4
- package/dist/core/routing/handler.d.ts +17 -0
- package/dist/core/routing/handler.js +172 -0
- package/dist/core/routing/match.d.ts +0 -7
- package/dist/core/routing/match.js +0 -5
- package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
- package/dist/core/routing/trailing-slash-handler.js +67 -0
- package/dist/core/session/drivers.d.ts +1 -1
- package/dist/core/session/handler.d.ts +11 -0
- package/dist/core/session/handler.js +33 -0
- package/dist/core/util/normalized-url.d.ts +10 -0
- package/dist/core/util/normalized-url.js +21 -0
- package/dist/i18n/middleware.d.ts +10 -0
- package/dist/i18n/middleware.js +4 -88
- package/dist/i18n/utils.js +2 -2
- package/dist/runtime/server/astro-island.js +57 -20
- package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
- package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt.js +1 -1
- package/dist/runtime/server/render/server-islands.js +2 -1
- package/dist/types/public/config.d.ts +46 -12
- package/dist/types/public/internal.d.ts +1 -1
- package/dist/vite-plugin-app/app.d.ts +4 -5
- package/dist/vite-plugin-app/app.js +20 -65
- package/package.json +11 -7
- package/dist/core/render-context.d.ts +0 -77
- 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,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 {};
|
package/dist/core/logger/core.js
CHANGED
|
@@ -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,
|
|
@@ -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
|
+
}
|