astro 7.0.0-alpha.0 → 7.0.0-alpha.2
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/components/Code.astro +1 -1
- 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/dev.js +1 -1
- 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/fonts/config.d.ts +4 -4
- package/dist/assets/fonts/core/optimize-fallbacks.js +38 -13
- package/dist/assets/fonts/definitions.d.ts +2 -2
- package/dist/assets/fonts/infra/system-fallbacks-provider.d.ts +2 -2
- package/dist/assets/fonts/infra/system-fallbacks-provider.js +46 -9
- package/dist/assets/fonts/types.d.ts +1 -0
- package/dist/assets/index.d.ts +1 -0
- package/dist/assets/index.js +2 -0
- package/dist/assets/internal.js +22 -3
- package/dist/assets/services/service.d.ts +1 -1
- package/dist/assets/services/service.js +9 -9
- package/dist/assets/services/sharp.js +53 -18
- package/dist/assets/utils/generateImageStylesCSS.js +26 -6
- package/dist/assets/utils/index.d.ts +1 -0
- package/dist/assets/utils/index.js +2 -0
- package/dist/assets/utils/inferSourceFormat.d.ts +8 -3
- package/dist/assets/utils/inferSourceFormat.js +15 -4
- package/dist/assets/utils/metadata.js +1 -1
- 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/assets/utils/vendor/image-size/types/svg.js +1 -1
- package/dist/cli/add/index.js +7 -58
- package/dist/cli/dev/background.d.ts +16 -0
- package/dist/cli/dev/background.js +116 -0
- package/dist/cli/dev/index.js +82 -3
- package/dist/cli/dev/logs.d.ts +6 -0
- package/dist/cli/dev/logs.js +72 -0
- package/dist/cli/dev/status.d.ts +15 -0
- package/dist/cli/dev/status.js +27 -0
- package/dist/cli/dev/stop.d.ts +12 -0
- package/dist/cli/dev/stop.js +43 -0
- 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 +16 -11
- package/dist/content/data-store.d.ts +1 -1
- package/dist/content/loaders/types.d.ts +1 -1
- package/dist/content/runtime-assets.d.ts +2 -2
- package/dist/content/runtime.d.ts +1 -1
- package/dist/content/runtime.js +9 -4
- package/dist/content/server-listeners.js +0 -4
- package/dist/content/types-generator.js +5 -1
- package/dist/content/utils.d.ts +1 -1
- package/dist/content/utils.js +1 -1
- package/dist/content/vite-plugin-content-assets.js +1 -0
- package/dist/content/vite-plugin-content-virtual-mod.js +9 -1
- package/dist/core/app/base.d.ts +42 -15
- package/dist/core/app/base.js +151 -375
- package/dist/core/app/dev/app.d.ts +3 -2
- package/dist/core/app/dev/app.js +4 -60
- package/dist/core/app/entrypoints/node.d.ts +1 -1
- package/dist/core/app/entrypoints/node.js +2 -0
- package/dist/core/app/entrypoints/virtual/dev.js +2 -0
- package/dist/core/app/entrypoints/virtual/prod.js +4 -1
- package/dist/core/app/node.d.ts +16 -0
- package/dist/core/app/node.js +59 -13
- 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 +48 -1
- package/dist/core/base-pipeline.js +63 -8
- package/dist/core/build/app.d.ts +3 -4
- package/dist/core/build/app.js +3 -17
- package/dist/core/build/generate.js +8 -1
- package/dist/core/build/index.d.ts +0 -11
- package/dist/core/build/index.js +0 -3
- package/dist/core/build/internal.d.ts +7 -0
- package/dist/core/build/plugins/plugin-chunk-imports.d.ts +6 -0
- package/dist/core/build/plugins/plugin-chunk-imports.js +29 -17
- package/dist/core/build/plugins/plugin-css.js +40 -1
- package/dist/core/build/plugins/plugin-internals.js +1 -1
- package/dist/core/build/plugins/plugin-manifest.js +11 -1
- package/dist/core/build/static-build.js +22 -141
- package/dist/core/build/types.d.ts +0 -1
- package/dist/core/build/util.js +8 -1
- package/dist/core/build/vite-build-config.d.ts +28 -0
- package/dist/core/build/vite-build-config.js +165 -0
- package/dist/core/cache/handler.d.ts +29 -0
- package/dist/core/cache/handler.js +81 -0
- package/dist/core/compile/style.js +18 -1
- package/dist/core/config/index.d.ts +1 -1
- package/dist/core/config/index.js +4 -1
- package/dist/core/config/merge.js +4 -0
- package/dist/core/config/schemas/base.d.ts +25 -13
- package/dist/core/config/schemas/base.js +39 -10
- package/dist/core/config/schemas/relative.d.ts +76 -49
- package/dist/core/config/schemas/relative.js +2 -3
- package/dist/core/config/settings.js +2 -4
- package/dist/core/config/tsconfig.d.ts +24 -9
- package/dist/core/config/tsconfig.js +54 -45
- package/dist/core/config/validate.js +59 -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 +18 -1
- package/dist/core/csp/config.js +17 -5
- package/dist/core/csp/runtime.js +6 -4
- package/dist/core/dev/dev.d.ts +1 -0
- package/dist/core/dev/dev.js +4 -13
- package/dist/core/dev/lockfile.d.ts +54 -0
- package/dist/core/dev/lockfile.js +93 -0
- 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/errors-data.d.ts +43 -38
- package/dist/core/errors/errors-data.js +79 -73
- package/dist/core/errors/handler.d.ts +9 -0
- package/dist/core/errors/handler.js +0 -0
- package/dist/core/errors/zod-error-map.js +30 -1
- 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 +230 -0
- package/dist/core/fetch/fetch-state.js +896 -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 +25 -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 +76 -0
- package/dist/core/hono/index.d.ts +21 -0
- package/dist/core/hono/index.js +101 -0
- package/dist/core/i18n/domain.d.ts +12 -0
- package/dist/core/i18n/domain.js +66 -0
- package/dist/core/i18n/handler.d.ts +18 -0
- package/dist/core/i18n/handler.js +122 -0
- package/dist/core/logger/core.d.ts +9 -1
- package/dist/core/logger/core.js +17 -1
- package/dist/core/messages/runtime.d.ts +0 -3
- package/dist/core/messages/runtime.js +1 -9
- package/dist/core/middleware/astro-middleware.d.ts +27 -0
- package/dist/core/middleware/astro-middleware.js +51 -0
- package/dist/core/module-loader/vite.js +1 -2
- package/dist/core/pages/handler.d.ts +20 -0
- package/dist/core/pages/handler.js +75 -0
- package/dist/core/preview/index.js +6 -5
- package/dist/core/preview/static-preview-server.js +5 -2
- package/dist/core/redirects/render.d.ts +2 -2
- package/dist/core/redirects/render.js +7 -8
- package/dist/core/render/params-and-props.js +2 -2
- package/dist/core/render/route-cache.d.ts +1 -0
- package/dist/core/render/route-cache.js +4 -4
- package/dist/core/render/slots.js +9 -2
- 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/create-manifest.js +11 -1
- package/dist/core/routing/handler.d.ts +17 -0
- package/dist/core/routing/handler.js +171 -0
- package/dist/core/routing/match.d.ts +0 -7
- package/dist/core/routing/match.js +0 -5
- package/dist/core/routing/parse-route.js +1 -1
- package/dist/core/routing/pattern.js +1 -1
- package/dist/core/routing/rewrite.js +2 -5
- package/dist/core/routing/router.d.ts +8 -0
- package/dist/core/routing/router.js +28 -0
- package/dist/core/routing/trailing-slash-handler.d.ts +18 -0
- package/dist/core/routing/trailing-slash-handler.js +67 -0
- package/dist/core/routing/validation.js +1 -1
- package/dist/core/server-islands/vite-plugin-server-islands.d.ts +6 -1
- package/dist/core/server-islands/vite-plugin-server-islands.js +13 -3
- package/dist/core/session/config.d.ts +1 -1
- 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/session/runtime.js +7 -2
- package/dist/core/util/normalized-url.d.ts +10 -0
- package/dist/core/util/normalized-url.js +24 -0
- package/dist/core/util/pathname.d.ts +10 -1
- package/dist/core/util/pathname.js +13 -4
- package/dist/environments.js +1 -1
- package/dist/events/session.d.ts +8 -0
- package/dist/events/session.js +11 -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/jsx/rehype.d.ts +1 -1
- package/dist/manifest/virtual-module.js +3 -1
- package/dist/markdown/index.d.ts +4 -0
- package/dist/markdown/index.js +14 -0
- package/dist/prefetch/index.js +12 -7
- package/dist/prerender/utils.js +5 -1
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +9 -0
- 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/jsx.js +1 -1
- package/dist/runtime/server/render/common.js +10 -4
- package/dist/runtime/server/render/component.js +8 -6
- package/dist/runtime/server/render/head.js +1 -5
- package/dist/runtime/server/render/server-islands.js +2 -1
- package/dist/runtime/server/render/util.js +2 -2
- package/dist/runtime/server/scripts.js +6 -0
- package/dist/runtime/server/transition.d.ts +1 -6
- package/dist/runtime/server/transition.js +0 -8
- package/dist/transitions/events.d.ts +0 -14
- package/dist/transitions/events.js +0 -14
- package/dist/transitions/index.d.ts +0 -1
- package/dist/transitions/index.js +0 -2
- package/dist/transitions/vite-plugin-transitions.js +2 -4
- package/dist/types/public/config.d.ts +96 -14
- package/dist/types/public/content.d.ts +5 -5
- package/dist/types/public/index.d.ts +2 -1
- package/dist/types/public/integrations.d.ts +11 -3
- package/dist/types/public/internal.d.ts +1 -1
- package/dist/types/public/manifest.d.ts +1 -1
- package/dist/virtual-modules/i18n.d.ts +2 -2
- package/dist/virtual-modules/i18n.js +1 -1
- package/dist/vite-plugin-app/app.d.ts +13 -6
- package/dist/vite-plugin-app/app.js +51 -89
- package/dist/vite-plugin-app/createAstroServerApp.d.ts +3 -1
- package/dist/vite-plugin-app/createAstroServerApp.js +4 -3
- package/dist/vite-plugin-astro-server/plugin.js +11 -5
- package/dist/vite-plugin-astro-server/route-guard.d.ts +33 -0
- package/dist/vite-plugin-astro-server/route-guard.js +42 -23
- package/dist/vite-plugin-dev-status/index.d.ts +2 -0
- package/dist/vite-plugin-dev-status/index.js +15 -0
- package/dist/vite-plugin-head/index.js +36 -19
- package/dist/vite-plugin-hmr-reload/index.d.ts +1 -1
- package/dist/vite-plugin-hmr-reload/index.js +23 -1
- package/dist/vite-plugin-integrations-container/index.js +15 -6
- package/dist/vite-plugin-markdown/content-entry-type.js +7 -4
- package/dist/vite-plugin-markdown/images.js +9 -11
- package/dist/vite-plugin-markdown/index.js +12 -11
- package/dist/vite-plugin-utils/index.d.ts +1 -0
- package/dist/vite-plugin-utils/index.js +10 -1
- package/package.json +23 -16
- package/templates/content/types.d.ts +1 -0
- package/types/transitions.d.ts +0 -7
- package/dist/core/render-context.d.ts +0 -77
- package/dist/core/render-context.js +0 -826
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { ActionHandler } from "../../actions/handler.js";
|
|
2
|
+
import {
|
|
3
|
+
REROUTABLE_STATUS_CODES,
|
|
4
|
+
REROUTE_DIRECTIVE_HEADER,
|
|
5
|
+
REWRITE_DIRECTIVE_HEADER_KEY
|
|
6
|
+
} from "../constants.js";
|
|
7
|
+
import { TrailingSlashHandler } from "./trailing-slash-handler.js";
|
|
8
|
+
import { CacheHandler, provideCache } from "../cache/handler.js";
|
|
9
|
+
import { I18n } from "../i18n/handler.js";
|
|
10
|
+
import { AstroMiddleware } from "../middleware/astro-middleware.js";
|
|
11
|
+
import { PagesHandler } from "../pages/handler.js";
|
|
12
|
+
import { renderRedirect } from "../redirects/render.js";
|
|
13
|
+
import { provideSession } from "../session/handler.js";
|
|
14
|
+
import { prepareResponse } from "../app/prepare-response.js";
|
|
15
|
+
import { ALL_PIPELINE_FEATURES, PipelineFeatures } from "../base-pipeline.js";
|
|
16
|
+
class AstroHandler {
|
|
17
|
+
#app;
|
|
18
|
+
#trailingSlashHandler;
|
|
19
|
+
#actionHandler;
|
|
20
|
+
#astroMiddleware;
|
|
21
|
+
#pagesHandler;
|
|
22
|
+
#cacheHandler;
|
|
23
|
+
/** Bound callback for the middleware chain — created once, reused per request. */
|
|
24
|
+
#renderRouteCallback;
|
|
25
|
+
/**
|
|
26
|
+
* i18n post-processor. Only set when the app has i18n configured and
|
|
27
|
+
* the strategy is not `manual` — for the manual strategy users wire
|
|
28
|
+
* `astro:i18n.middleware(...)` into their own `onRequest`.
|
|
29
|
+
*/
|
|
30
|
+
#i18n;
|
|
31
|
+
/** Whether sessions are configured on the manifest. */
|
|
32
|
+
#hasSession;
|
|
33
|
+
constructor(app) {
|
|
34
|
+
this.#app = app;
|
|
35
|
+
this.#trailingSlashHandler = new TrailingSlashHandler(app);
|
|
36
|
+
this.#actionHandler = new ActionHandler();
|
|
37
|
+
this.#astroMiddleware = new AstroMiddleware(app.pipeline);
|
|
38
|
+
this.#pagesHandler = new PagesHandler(app.pipeline);
|
|
39
|
+
this.#cacheHandler = new CacheHandler(app);
|
|
40
|
+
this.#renderRouteCallback = this.#actionsAndPages.bind(this);
|
|
41
|
+
this.#hasSession = !!app.manifest.sessionConfig;
|
|
42
|
+
const i18n = app.manifest.i18n;
|
|
43
|
+
if (i18n && i18n.strategy !== "manual") {
|
|
44
|
+
this.#i18n = new I18n(
|
|
45
|
+
i18n,
|
|
46
|
+
app.manifest.base,
|
|
47
|
+
app.manifest.trailingSlash,
|
|
48
|
+
app.manifest.buildFormat
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Runs actions then pages — the callback at the bottom of the
|
|
54
|
+
* middleware chain. Bound once in the constructor to avoid
|
|
55
|
+
* per-request closure allocation.
|
|
56
|
+
*/
|
|
57
|
+
#actionsAndPages(state, ctx) {
|
|
58
|
+
if (!state.skipMiddleware) {
|
|
59
|
+
const actionResult = this.#actionHandler.handle(ctx, state);
|
|
60
|
+
if (actionResult) {
|
|
61
|
+
return actionResult.then((response) => response ?? this.#pagesHandler.handle(state, ctx));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return this.#pagesHandler.handle(state, ctx);
|
|
65
|
+
}
|
|
66
|
+
async handle(state) {
|
|
67
|
+
state.pipeline.usedFeatures |= ALL_PIPELINE_FEATURES;
|
|
68
|
+
const trailingSlashRedirect = this.#trailingSlashHandler.handle(state);
|
|
69
|
+
if (trailingSlashRedirect) {
|
|
70
|
+
return trailingSlashRedirect;
|
|
71
|
+
}
|
|
72
|
+
if (!state.routeData) {
|
|
73
|
+
return this.#app.renderError(state.request, {
|
|
74
|
+
...state.renderOptions,
|
|
75
|
+
status: 404,
|
|
76
|
+
pathname: state.pathname
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return this.render(state);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Renders a response for the given `FetchState`. Assumes
|
|
83
|
+
* trailing-slash redirects and routeData resolution have already run.
|
|
84
|
+
*
|
|
85
|
+
* User-triggered rewrites (`Astro.rewrite` / `ctx.rewrite`) go through
|
|
86
|
+
* `Rewrites.execute` on the current `FetchState` — they mutate the
|
|
87
|
+
* existing state in place and re-run middleware + page dispatch.
|
|
88
|
+
*/
|
|
89
|
+
async render(state) {
|
|
90
|
+
const routeData = state.routeData;
|
|
91
|
+
const pathname = state.pathname;
|
|
92
|
+
const request = state.request;
|
|
93
|
+
const { addCookieHeader } = state.renderOptions;
|
|
94
|
+
const defaultStatus = this.#app.getDefaultStatusCode(routeData, pathname);
|
|
95
|
+
state.status = defaultStatus;
|
|
96
|
+
let response;
|
|
97
|
+
try {
|
|
98
|
+
const sessionP = this.#hasSession ? provideSession(state) : void 0;
|
|
99
|
+
const cacheP = provideCache(state);
|
|
100
|
+
if (sessionP || cacheP) await Promise.all([sessionP, cacheP]);
|
|
101
|
+
state.pipeline.usedFeatures |= PipelineFeatures.sessions;
|
|
102
|
+
if (routeData.type === "redirect") {
|
|
103
|
+
const redirectResponse = await renderRedirect(state);
|
|
104
|
+
this.#app.logThisRequest({
|
|
105
|
+
pathname,
|
|
106
|
+
method: request.method,
|
|
107
|
+
statusCode: redirectResponse.status,
|
|
108
|
+
isRewrite: false,
|
|
109
|
+
timeStart: state.timeStart
|
|
110
|
+
});
|
|
111
|
+
prepareResponse(redirectResponse, { addCookieHeader });
|
|
112
|
+
this.#app.pipeline.logger.flush();
|
|
113
|
+
return redirectResponse;
|
|
114
|
+
}
|
|
115
|
+
if (!this.#app.pipeline.cacheProvider) {
|
|
116
|
+
this.#app.pipeline.usedFeatures |= PipelineFeatures.cache;
|
|
117
|
+
response = await this.#astroMiddleware.handle(state, this.#renderRouteCallback);
|
|
118
|
+
if (this.#i18n) {
|
|
119
|
+
response = await this.#i18n.finalize(state, response);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
const runPipeline = async () => {
|
|
123
|
+
let res = await this.#astroMiddleware.handle(state, this.#renderRouteCallback);
|
|
124
|
+
if (this.#i18n) {
|
|
125
|
+
res = await this.#i18n.finalize(state, res);
|
|
126
|
+
}
|
|
127
|
+
return res;
|
|
128
|
+
};
|
|
129
|
+
response = await this.#cacheHandler.handle(state, runPipeline);
|
|
130
|
+
}
|
|
131
|
+
const isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY);
|
|
132
|
+
this.#app.logThisRequest({
|
|
133
|
+
pathname,
|
|
134
|
+
method: request.method,
|
|
135
|
+
statusCode: response.status,
|
|
136
|
+
isRewrite,
|
|
137
|
+
timeStart: state.timeStart
|
|
138
|
+
});
|
|
139
|
+
} catch (err) {
|
|
140
|
+
this.#app.logger.error(null, err.stack || err.message || String(err));
|
|
141
|
+
return this.#app.renderError(request, {
|
|
142
|
+
...state.renderOptions,
|
|
143
|
+
status: 500,
|
|
144
|
+
error: err,
|
|
145
|
+
pathname: state.pathname
|
|
146
|
+
});
|
|
147
|
+
} finally {
|
|
148
|
+
const finalize = state.finalizeAll();
|
|
149
|
+
if (finalize) await finalize;
|
|
150
|
+
}
|
|
151
|
+
if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
|
|
152
|
+
// but uses the current route to handle the 404
|
|
153
|
+
response.body === null && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") {
|
|
154
|
+
return this.#app.renderError(request, {
|
|
155
|
+
...state.renderOptions,
|
|
156
|
+
response,
|
|
157
|
+
status: response.status,
|
|
158
|
+
// We don't have an error to report here. Passing null means we pass nothing intentionally
|
|
159
|
+
// while undefined means there's no error
|
|
160
|
+
error: response.status === 500 ? null : void 0,
|
|
161
|
+
pathname: state.pathname
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
prepareResponse(response, { addCookieHeader });
|
|
165
|
+
this.#app.pipeline.logger.flush();
|
|
166
|
+
return response;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
AstroHandler
|
|
171
|
+
};
|
|
@@ -18,10 +18,3 @@ export declare function isRoute404or500(route: RouteData): boolean;
|
|
|
18
18
|
* @return {boolean} Returns true if the route's component is the server island component; otherwise, false.
|
|
19
19
|
*/
|
|
20
20
|
export declare function isRouteServerIsland(route: RouteData): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Determines whether a given route is an external redirect.
|
|
23
|
-
*
|
|
24
|
-
* @param {RouteData} route - The route object to check.
|
|
25
|
-
* @return {boolean} Returns true if the route is an external redirect; otherwise, false.
|
|
26
|
-
*/
|
|
27
|
-
export declare function isRouteExternalRedirect(route: RouteData): boolean;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { redirectIsExternal } from "../redirects/render.js";
|
|
2
1
|
import { SERVER_ISLAND_COMPONENT } from "../server-islands/endpoint.js";
|
|
3
2
|
import { isRoute404, isRoute500 } from "./internal/route-errors.js";
|
|
4
3
|
function matchRoute(pathname, manifest) {
|
|
@@ -23,12 +22,8 @@ function isRoute404or500(route) {
|
|
|
23
22
|
function isRouteServerIsland(route) {
|
|
24
23
|
return route.component === SERVER_ISLAND_COMPONENT;
|
|
25
24
|
}
|
|
26
|
-
function isRouteExternalRedirect(route) {
|
|
27
|
-
return !!(route.type === "redirect" && route.redirect && redirectIsExternal(route.redirect));
|
|
28
|
-
}
|
|
29
25
|
export {
|
|
30
26
|
isRoute404or500,
|
|
31
|
-
isRouteExternalRedirect,
|
|
32
27
|
isRouteServerIsland,
|
|
33
28
|
matchAllRoutes,
|
|
34
29
|
matchRoute
|
|
@@ -58,7 +58,7 @@ function joinSegments(segments) {
|
|
|
58
58
|
const arr = segments.map((segment) => {
|
|
59
59
|
return segment.map((part) => part.dynamic ? `[${part.content}]` : part.content).join("");
|
|
60
60
|
});
|
|
61
|
-
return `/${arr.join("/")}
|
|
61
|
+
return `/${arr.join("/")}`;
|
|
62
62
|
}
|
|
63
63
|
export {
|
|
64
64
|
parseRoute
|
|
@@ -16,7 +16,7 @@ function getPattern(segments, base, addTrailingSlash) {
|
|
|
16
16
|
}).join("");
|
|
17
17
|
const trailing = addTrailingSlash && segments.length ? getTrailingSlashPattern(addTrailingSlash) : "$";
|
|
18
18
|
let initial = "\\/";
|
|
19
|
-
if (addTrailingSlash === "never" && base !== "/") {
|
|
19
|
+
if (addTrailingSlash === "never" && base !== "/" && pathname !== "") {
|
|
20
20
|
initial = "";
|
|
21
21
|
}
|
|
22
22
|
return new RegExp(`^${pathname || initial}${trailing}`);
|
|
@@ -101,7 +101,7 @@ function copyRequest(newUrl, oldRequest, isPrerendered, logger, routePattern) {
|
|
|
101
101
|
signal: oldRequest.signal,
|
|
102
102
|
keepalive: oldRequest.keepalive,
|
|
103
103
|
// https://fetch.spec.whatwg.org/#dom-request-duplex
|
|
104
|
-
// @ts-expect-error It isn't part of the types, but undici accepts it and it allows
|
|
104
|
+
// @ts-expect-error It isn't part of the types, but undici accepts it and it allows carrying over the body to a new request
|
|
105
105
|
duplex: "half"
|
|
106
106
|
}
|
|
107
107
|
});
|
|
@@ -134,7 +134,7 @@ function normalizeRewritePathname(urlPathname, base, trailingSlash, buildFormat)
|
|
|
134
134
|
if (base !== "/") {
|
|
135
135
|
const isBasePathRequest = urlPathname === base || urlPathname === removeTrailingForwardSlash(base);
|
|
136
136
|
if (isBasePathRequest) {
|
|
137
|
-
pathname =
|
|
137
|
+
pathname = "/";
|
|
138
138
|
} else if (urlPathname.startsWith(base)) {
|
|
139
139
|
pathname = shouldAppendSlash ? appendForwardSlash(urlPathname) : removeTrailingForwardSlash(urlPathname);
|
|
140
140
|
pathname = pathname.slice(base.length);
|
|
@@ -143,9 +143,6 @@ function normalizeRewritePathname(urlPathname, base, trailingSlash, buildFormat)
|
|
|
143
143
|
if (!pathname.startsWith("/") && shouldAppendSlash && urlPathname.endsWith("/")) {
|
|
144
144
|
pathname = prependForwardSlash(pathname);
|
|
145
145
|
}
|
|
146
|
-
if (pathname === "/" && base !== "/" && !shouldAppendSlash) {
|
|
147
|
-
pathname = "";
|
|
148
|
-
}
|
|
149
146
|
if (buildFormat === "file") {
|
|
150
147
|
pathname = pathname.replace(/\.html$/, "");
|
|
151
148
|
}
|
|
@@ -46,5 +46,13 @@ export declare class Router {
|
|
|
46
46
|
match(inputPathname: string, { allowWithoutBase }?: {
|
|
47
47
|
allowWithoutBase?: boolean;
|
|
48
48
|
}): RouterMatch;
|
|
49
|
+
/**
|
|
50
|
+
* Returns all routes that match the given pathname, in priority order.
|
|
51
|
+
* Used when the first match (e.g. a prerendered route) cannot serve
|
|
52
|
+
* the request and subsequent matches need to be tried.
|
|
53
|
+
*/
|
|
54
|
+
matchAll(inputPathname: string, { allowWithoutBase }?: {
|
|
55
|
+
allowWithoutBase?: boolean;
|
|
56
|
+
}): RouteData[];
|
|
49
57
|
}
|
|
50
58
|
export {};
|
|
@@ -57,6 +57,34 @@ class Router {
|
|
|
57
57
|
const params = getParams(route, pathname);
|
|
58
58
|
return { type: "match", route, params, pathname };
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns all routes that match the given pathname, in priority order.
|
|
62
|
+
* Used when the first match (e.g. a prerendered route) cannot serve
|
|
63
|
+
* the request and subsequent matches need to be tried.
|
|
64
|
+
*/
|
|
65
|
+
matchAll(inputPathname, { allowWithoutBase = false } = {}) {
|
|
66
|
+
const normalized = getRedirectForPathname(inputPathname);
|
|
67
|
+
if (normalized.redirect) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const baseResult = stripBase(
|
|
71
|
+
normalized.pathname,
|
|
72
|
+
this.#base,
|
|
73
|
+
this.#baseWithoutTrailingSlash,
|
|
74
|
+
this.#trailingSlash
|
|
75
|
+
);
|
|
76
|
+
if (!baseResult && !allowWithoutBase) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
let pathname = baseResult ?? normalized.pathname;
|
|
80
|
+
if (this.#buildFormat === "file") {
|
|
81
|
+
pathname = normalizeFileFormatPathname(pathname);
|
|
82
|
+
}
|
|
83
|
+
return this.#routes.filter((candidate) => {
|
|
84
|
+
if (candidate.pattern.test(pathname)) return true;
|
|
85
|
+
return candidate.fallbackRoutes.some((fallbackRoute) => fallbackRoute.pattern.test(pathname));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
60
88
|
}
|
|
61
89
|
function normalizeBase(base) {
|
|
62
90
|
if (!base) return "/";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BaseApp } from '../app/base.js';
|
|
2
|
+
import type { Pipeline } from '../base-pipeline.js';
|
|
3
|
+
import type { FetchState } from '../fetch/fetch-state.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handles trailing-slash normalization for incoming requests. If the
|
|
6
|
+
* request's pathname does not match the app's configured `trailingSlash`
|
|
7
|
+
* policy, a redirect response is returned. Otherwise, returns `undefined`
|
|
8
|
+
* so the caller can continue processing the request.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TrailingSlashHandler {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(app: BaseApp<Pipeline>);
|
|
13
|
+
/**
|
|
14
|
+
* Returns a redirect `Response` if the request pathname needs
|
|
15
|
+
* normalization, or `undefined` if no redirect is required.
|
|
16
|
+
*/
|
|
17
|
+
handle(state: FetchState): Response | undefined;
|
|
18
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendForwardSlash,
|
|
3
|
+
collapseDuplicateTrailingSlashes,
|
|
4
|
+
hasFileExtension,
|
|
5
|
+
isInternalPath,
|
|
6
|
+
removeTrailingForwardSlash
|
|
7
|
+
} from "@astrojs/internal-helpers/path";
|
|
8
|
+
import { prepareResponse } from "../app/prepare-response.js";
|
|
9
|
+
import { redirectTemplate } from "./3xx.js";
|
|
10
|
+
class TrailingSlashHandler {
|
|
11
|
+
#app;
|
|
12
|
+
constructor(app) {
|
|
13
|
+
this.#app = app;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns a redirect `Response` if the request pathname needs
|
|
17
|
+
* normalization, or `undefined` if no redirect is required.
|
|
18
|
+
*/
|
|
19
|
+
handle(state) {
|
|
20
|
+
const url = new URL(state.request.url);
|
|
21
|
+
const redirect = this.#redirectTrailingSlash(url.pathname);
|
|
22
|
+
if (redirect === url.pathname) {
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
const addCookieHeader = state.renderOptions.addCookieHeader;
|
|
26
|
+
const status = state.request.method === "GET" ? 301 : 308;
|
|
27
|
+
const response = new Response(
|
|
28
|
+
redirectTemplate({
|
|
29
|
+
status,
|
|
30
|
+
relativeLocation: url.pathname,
|
|
31
|
+
absoluteLocation: redirect,
|
|
32
|
+
from: state.request.url
|
|
33
|
+
}),
|
|
34
|
+
{
|
|
35
|
+
status,
|
|
36
|
+
headers: {
|
|
37
|
+
location: redirect + url.search
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
prepareResponse(response, { addCookieHeader });
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
#redirectTrailingSlash(pathname) {
|
|
45
|
+
const { trailingSlash } = this.#app.manifest;
|
|
46
|
+
if (pathname === "/" || isInternalPath(pathname)) {
|
|
47
|
+
return pathname;
|
|
48
|
+
}
|
|
49
|
+
const path = collapseDuplicateTrailingSlashes(pathname, trailingSlash !== "never");
|
|
50
|
+
if (path !== pathname) {
|
|
51
|
+
return path;
|
|
52
|
+
}
|
|
53
|
+
if (trailingSlash === "ignore") {
|
|
54
|
+
return pathname;
|
|
55
|
+
}
|
|
56
|
+
if (trailingSlash === "always" && !hasFileExtension(pathname)) {
|
|
57
|
+
return appendForwardSlash(pathname);
|
|
58
|
+
}
|
|
59
|
+
if (trailingSlash === "never") {
|
|
60
|
+
return removeTrailingForwardSlash(pathname);
|
|
61
|
+
}
|
|
62
|
+
return pathname;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
TrailingSlashHandler
|
|
67
|
+
};
|
|
@@ -3,7 +3,7 @@ function validateDynamicRouteModule(mod, {
|
|
|
3
3
|
ssr,
|
|
4
4
|
route
|
|
5
5
|
}) {
|
|
6
|
-
if ((!ssr || route.prerender) && !mod.getStaticPaths) {
|
|
6
|
+
if ((!ssr || route.prerender) && route.origin !== "internal" && !mod.getStaticPaths) {
|
|
7
7
|
throw new AstroError({
|
|
8
8
|
...AstroErrorData.GetStaticPathsRequired,
|
|
9
9
|
location: { file: route.component }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Plugin as VitePlugin } from 'vite';
|
|
1
|
+
import type { BuildEnvironment, Plugin as VitePlugin } from 'vite';
|
|
2
2
|
import type { AstroPluginOptions } from '../../types/astro.js';
|
|
3
3
|
import type { ServerIslandsState } from './shared-state.js';
|
|
4
4
|
export declare const SERVER_ISLAND_MANIFEST = "virtual:astro:server-island-manifest";
|
|
@@ -6,3 +6,8 @@ export declare const SERVER_ISLAND_MAP_MARKER = "$$server-islands-map$$";
|
|
|
6
6
|
export declare function vitePluginServerIslands({ settings, serverIslandsState, }: AstroPluginOptions & {
|
|
7
7
|
serverIslandsState: ServerIslandsState;
|
|
8
8
|
}): VitePlugin;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the prerender environment discovered any server islands during the build.
|
|
11
|
+
* This encapsulates the logic of finding the server islands plugin and querying its state.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hasServerIslands(environment: BuildEnvironment): boolean;
|
|
@@ -28,6 +28,11 @@ function vitePluginServerIslands({
|
|
|
28
28
|
return {
|
|
29
29
|
name: "astro:server-islands",
|
|
30
30
|
enforce: "post",
|
|
31
|
+
api: {
|
|
32
|
+
hasServerIslands() {
|
|
33
|
+
return serverIslandsState.hasIslands();
|
|
34
|
+
}
|
|
35
|
+
},
|
|
31
36
|
config(_config, { command: _command }) {
|
|
32
37
|
command = _command;
|
|
33
38
|
},
|
|
@@ -111,9 +116,8 @@ export const serverIslandNameMap = ${serverIslandPlaceholderNameMap};`
|
|
|
111
116
|
}
|
|
112
117
|
}
|
|
113
118
|
if (id === RESOLVED_SERVER_ISLAND_MANIFEST) {
|
|
114
|
-
if (command === "build"
|
|
115
|
-
|
|
116
|
-
if (hasServerIslands && settings.buildOutput !== "server") {
|
|
119
|
+
if (command === "build") {
|
|
120
|
+
if (serverIslandsState.hasIslands() && !settings.adapter) {
|
|
117
121
|
throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands);
|
|
118
122
|
}
|
|
119
123
|
}
|
|
@@ -163,8 +167,14 @@ export const serverIslandNameMap = ${serverIslandPlaceholderNameMap};`
|
|
|
163
167
|
}
|
|
164
168
|
};
|
|
165
169
|
}
|
|
170
|
+
function hasServerIslands(environment) {
|
|
171
|
+
const plugins = environment.config.plugins ?? [];
|
|
172
|
+
const serverIslandsPlugin = plugins.find((p) => p.name === "astro:server-islands");
|
|
173
|
+
return typeof serverIslandsPlugin?.api?.hasServerIslands === "function" && serverIslandsPlugin.api.hasServerIslands();
|
|
174
|
+
}
|
|
166
175
|
export {
|
|
167
176
|
SERVER_ISLAND_MANIFEST,
|
|
168
177
|
SERVER_ISLAND_MAP_MARKER,
|
|
178
|
+
hasServerIslands,
|
|
169
179
|
vitePluginServerIslands
|
|
170
180
|
};
|
|
@@ -15,9 +15,9 @@ export declare const SessionSchema: z.ZodObject<{
|
|
|
15
15
|
path: z.ZodOptional<z.ZodString>;
|
|
16
16
|
maxAge: z.ZodOptional<z.ZodNumber>;
|
|
17
17
|
sameSite: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
18
|
+
none: "none";
|
|
18
19
|
strict: "strict";
|
|
19
20
|
lax: "lax";
|
|
20
|
-
none: "none";
|
|
21
21
|
}>, z.ZodBoolean]>>;
|
|
22
22
|
secure: z.ZodOptional<z.ZodBoolean>;
|
|
23
23
|
}, z.core.$strip>, z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SessionDriverConfig } from './types.js';
|
|
2
2
|
export declare const sessionDrivers: {
|
|
3
3
|
http: (config?: import("unstorage/drivers/http").HTTPOptions | undefined) => SessionDriverConfig;
|
|
4
|
+
fs: (config?: import("unstorage/drivers/fs").FSStorageOptions | undefined) => SessionDriverConfig;
|
|
4
5
|
azureAppConfiguration: (config?: import("unstorage/drivers/azure-app-configuration").AzureAppConfigurationOptions | undefined) => SessionDriverConfig;
|
|
5
6
|
azureCosmos: (config?: import("unstorage/drivers/azure-cosmos").AzureCosmosOptions | undefined) => SessionDriverConfig;
|
|
6
7
|
azureKeyVault: (config?: import("unstorage/drivers/azure-key-vault").AzureKeyVaultOptions | undefined) => SessionDriverConfig;
|
|
@@ -14,7 +15,6 @@ export declare const sessionDrivers: {
|
|
|
14
15
|
denoKVNode: (config?: import("unstorage/drivers/deno-kv-node").DenoKvNodeOptions | undefined) => SessionDriverConfig;
|
|
15
16
|
denoKV: (config?: import("unstorage/drivers/deno-kv").DenoKvOptions | undefined) => SessionDriverConfig;
|
|
16
17
|
fsLite: (config?: import("unstorage/drivers/fs-lite").FSStorageOptions | undefined) => SessionDriverConfig;
|
|
17
|
-
fs: (config?: import("unstorage/drivers/fs").FSStorageOptions | undefined) => SessionDriverConfig;
|
|
18
18
|
github: (config?: import("unstorage/drivers/github").GithubOptions | undefined) => SessionDriverConfig;
|
|
19
19
|
indexedb: (config?: import("unstorage/drivers/indexedb").IDBKeyvalOptions | undefined) => SessionDriverConfig;
|
|
20
20
|
localstorage: (config?: import("unstorage/drivers/localstorage").LocalStorageOptions | undefined) => SessionDriverConfig;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FetchState } from '../fetch/fetch-state.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registers a session provider on the given `FetchState`. When
|
|
4
|
+
* `state.resolve('session')` is first called, the `AstroSession` is
|
|
5
|
+
* created lazily. When `state.finalizeAll()` runs, any mutations are
|
|
6
|
+
* persisted.
|
|
7
|
+
*
|
|
8
|
+
* No-op (returns synchronously) if sessions are not configured on the
|
|
9
|
+
* pipeline, avoiding promise allocation on the hot path.
|
|
10
|
+
*/
|
|
11
|
+
export declare function provideSession(state: FetchState): Promise<void> | void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { PipelineFeatures } from "../base-pipeline.js";
|
|
2
|
+
import { AstroSession, PERSIST_SYMBOL } from "./runtime.js";
|
|
3
|
+
const SESSION_KEY = "session";
|
|
4
|
+
function provideSession(state) {
|
|
5
|
+
state.pipeline.usedFeatures |= PipelineFeatures.sessions;
|
|
6
|
+
const pipeline = state.pipeline;
|
|
7
|
+
const config = pipeline.manifest.sessionConfig;
|
|
8
|
+
if (!config) return;
|
|
9
|
+
return provideSessionAsync(state, config);
|
|
10
|
+
}
|
|
11
|
+
async function provideSessionAsync(state, config) {
|
|
12
|
+
const pipeline = state.pipeline;
|
|
13
|
+
const driverFactory = await pipeline.getSessionDriver();
|
|
14
|
+
if (!driverFactory) return;
|
|
15
|
+
state.provide(SESSION_KEY, {
|
|
16
|
+
create() {
|
|
17
|
+
const cookies = state.cookies;
|
|
18
|
+
return new AstroSession({
|
|
19
|
+
cookies,
|
|
20
|
+
config,
|
|
21
|
+
runtimeMode: pipeline.runtimeMode,
|
|
22
|
+
driverFactory,
|
|
23
|
+
mockStorage: null
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
finalize(session) {
|
|
27
|
+
return session[PERSIST_SYMBOL]();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
provideSession
|
|
33
|
+
};
|
|
@@ -121,7 +121,8 @@ class AstroSession {
|
|
|
121
121
|
* Deletes a session value.
|
|
122
122
|
*/
|
|
123
123
|
delete(key) {
|
|
124
|
-
this.#data
|
|
124
|
+
this.#data ??= /* @__PURE__ */ new Map();
|
|
125
|
+
this.#data.delete(key);
|
|
125
126
|
if (this.#partial) {
|
|
126
127
|
this.#toDelete.add(key);
|
|
127
128
|
}
|
|
@@ -272,11 +273,15 @@ class AstroSession {
|
|
|
272
273
|
* If there is existing partial data, it will be merged into the new data object.
|
|
273
274
|
*/
|
|
274
275
|
async #ensureData() {
|
|
275
|
-
const storage = await this.#ensureStorage();
|
|
276
276
|
if (this.#data && !this.#partial) {
|
|
277
277
|
return this.#data;
|
|
278
278
|
}
|
|
279
279
|
this.#data ??= /* @__PURE__ */ new Map();
|
|
280
|
+
if (!this.#sessionID && !this.#cookies.get(this.#cookieName)?.value) {
|
|
281
|
+
this.#partial = false;
|
|
282
|
+
return this.#data;
|
|
283
|
+
}
|
|
284
|
+
const storage = await this.#ensureStorage();
|
|
280
285
|
const raw = await storage.get(this.#ensureSessionID());
|
|
281
286
|
if (!raw) {
|
|
282
287
|
if (this.#sessionIDFromCookie) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a normalized URL from a request URL string.
|
|
3
|
+
* Decodes and validates the pathname, collapses duplicate slashes.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createNormalizedUrl(requestUrl: string): URL;
|
|
6
|
+
/**
|
|
7
|
+
* Normalizes an already-parsed URL in place: decodes and validates the
|
|
8
|
+
* pathname, collapses duplicate slashes. Returns the same URL object.
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeUrl(url: URL): URL;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { collapseDuplicateSlashes } from "@astrojs/internal-helpers/path";
|
|
2
|
+
import { MultiLevelEncodingError, validateAndDecodePathname } from "./pathname.js";
|
|
3
|
+
function createNormalizedUrl(requestUrl) {
|
|
4
|
+
return normalizeUrl(new URL(requestUrl));
|
|
5
|
+
}
|
|
6
|
+
function normalizeUrl(url) {
|
|
7
|
+
try {
|
|
8
|
+
url.pathname = validateAndDecodePathname(url.pathname);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
if (e instanceof MultiLevelEncodingError) {
|
|
11
|
+
throw e;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
url.pathname = decodeURI(url.pathname);
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
url.pathname = collapseDuplicateSlashes(url.pathname);
|
|
19
|
+
return url;
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
createNormalizedUrl,
|
|
23
|
+
normalizeUrl
|
|
24
|
+
};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when multi-level URL encoding is detected in a pathname.
|
|
3
|
+
* This is a distinct error type so callers can handle it specifically
|
|
4
|
+
* (e.g., returning a 400 response) rather than falling back to partial decoding.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MultiLevelEncodingError extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Validates that a pathname is not multi-level encoded.
|
|
3
11
|
* Detects if a pathname contains encoding that was encoded again (e.g., %2561dmin where %25 decodes to %).
|
|
@@ -5,6 +13,7 @@
|
|
|
5
13
|
*
|
|
6
14
|
* @param pathname - The pathname to validate
|
|
7
15
|
* @returns The decoded pathname if valid
|
|
8
|
-
* @throws
|
|
16
|
+
* @throws MultiLevelEncodingError if multi-level encoding is detected
|
|
17
|
+
* @throws Error if the pathname contains invalid URL encoding
|
|
9
18
|
*/
|
|
10
19
|
export declare function validateAndDecodePathname(pathname: string): string;
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
class MultiLevelEncodingError extends Error {
|
|
2
|
+
constructor() {
|
|
3
|
+
super("Multi-level URL encoding is not allowed");
|
|
4
|
+
this.name = "MultiLevelEncodingError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
const ENCODING_REGEX = /%25[0-9a-fA-F]{2}/;
|
|
1
8
|
function validateAndDecodePathname(pathname) {
|
|
9
|
+
if (ENCODING_REGEX.test(pathname)) {
|
|
10
|
+
throw new MultiLevelEncodingError();
|
|
11
|
+
}
|
|
2
12
|
let decoded;
|
|
3
13
|
try {
|
|
4
14
|
decoded = decodeURI(pathname);
|
|
5
15
|
} catch (_e) {
|
|
6
16
|
throw new Error("Invalid URL encoding");
|
|
7
17
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (hasDecoding && decodedStillHasEncoding) {
|
|
11
|
-
throw new Error("Multi-level URL encoding is not allowed");
|
|
18
|
+
if (ENCODING_REGEX.test(decoded)) {
|
|
19
|
+
throw new MultiLevelEncodingError();
|
|
12
20
|
}
|
|
13
21
|
return decoded;
|
|
14
22
|
}
|
|
15
23
|
export {
|
|
24
|
+
MultiLevelEncodingError,
|
|
16
25
|
validateAndDecodePathname
|
|
17
26
|
};
|
package/dist/environments.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "./core/constants.js";
|
|
2
2
|
function isAstroServerEnvironment(environment) {
|
|
3
|
-
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender;
|
|
3
|
+
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.astro;
|
|
4
4
|
}
|
|
5
5
|
function isAstroClientEnvironment(environment) {
|
|
6
6
|
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client;
|
package/dist/events/session.d.ts
CHANGED
|
@@ -5,6 +5,14 @@ interface EventPayload {
|
|
|
5
5
|
configKeys?: string[];
|
|
6
6
|
flags?: string[];
|
|
7
7
|
optionalIntegrations?: number;
|
|
8
|
+
/** Whether the CLI session was run by an AI coding agent. */
|
|
9
|
+
isAgentic?: boolean;
|
|
10
|
+
/** ID of the detected agent, e.g. "cursor-agent", "claude-code". */
|
|
11
|
+
agentId?: string;
|
|
12
|
+
/** Display name of the detected agent, e.g. "Cursor Agent", "Claude Code". */
|
|
13
|
+
agentName?: string;
|
|
14
|
+
/** Type of agentic environment: "agent", "interactive", or "hybrid". */
|
|
15
|
+
agentType?: string;
|
|
8
16
|
}
|
|
9
17
|
type ConfigInfoValue = string | boolean | string[] | undefined;
|
|
10
18
|
type ConfigInfoRecord = Record<string, ConfigInfoValue>;
|