astro 7.0.0-alpha.1 → 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/assets/endpoint/dev.js +1 -1
- package/dist/assets/endpoint/generic.js +7 -16
- package/dist/assets/endpoint/loadImage.d.ts +11 -0
- package/dist/assets/endpoint/loadImage.js +19 -0
- 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/internal.js +20 -16
- package/dist/assets/services/service.d.ts +1 -1
- package/dist/assets/services/service.js +9 -9
- package/dist/assets/services/sharp.js +48 -28
- package/dist/assets/utils/generateImageStylesCSS.js +26 -6
- 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/vendor/image-size/types/svg.js +1 -1
- 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/content/content-layer.js +16 -10
- package/dist/content/data-store.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/types-generator.js +5 -1
- package/dist/content/utils.d.ts +1 -1
- package/dist/content/utils.js +1 -1
- package/dist/core/app/base.d.ts +9 -0
- package/dist/core/app/base.js +47 -67
- package/dist/core/app/entrypoints/node.d.ts +1 -1
- package/dist/core/app/entrypoints/node.js +2 -0
- package/dist/core/app/node.d.ts +16 -0
- package/dist/core/app/node.js +59 -13
- package/dist/core/base-pipeline.d.ts +10 -0
- package/dist/core/base-pipeline.js +13 -1
- 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 +33 -0
- package/dist/core/build/plugins/plugin-internals.js +1 -1
- package/dist/core/build/static-build.js +22 -155
- 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/config/merge.js +4 -0
- package/dist/core/config/schemas/base.d.ts +19 -11
- package/dist/core/config/schemas/base.js +29 -4
- package/dist/core/config/schemas/relative.d.ts +69 -45
- package/dist/core/config/validate.js +59 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +3 -1
- package/dist/core/csp/config.js +17 -5
- package/dist/core/dev/dev.d.ts +1 -0
- package/dist/core/dev/dev.js +4 -1
- package/dist/core/dev/lockfile.d.ts +54 -0
- package/dist/core/dev/lockfile.js +93 -0
- package/dist/core/errors/errors-data.d.ts +43 -38
- package/dist/core/errors/errors-data.js +79 -73
- package/dist/core/errors/zod-error-map.js +3 -1
- package/dist/core/fetch/fetch-state.d.ts +12 -26
- package/dist/core/fetch/fetch-state.js +137 -20
- package/dist/core/fetch/types.d.ts +19 -0
- package/dist/core/fetch/vite-plugin.js +11 -4
- package/dist/core/hono/index.d.ts +1 -1
- package/dist/core/hono/index.js +6 -3
- package/dist/core/i18n/domain.d.ts +12 -0
- package/dist/core/i18n/domain.js +66 -0
- package/dist/core/i18n/handler.js +3 -0
- package/dist/core/logger/core.d.ts +1 -1
- package/dist/core/logger/core.js +1 -1
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/middleware/astro-middleware.js +3 -5
- package/dist/core/module-loader/vite.js +1 -2
- package/dist/core/pages/handler.js +1 -0
- package/dist/core/preview/index.js +6 -5
- package/dist/core/preview/static-preview-server.js +5 -2
- package/dist/core/render/params-and-props.js +1 -1
- package/dist/core/render/route-cache.d.ts +1 -0
- package/dist/core/render/route-cache.js +4 -4
- package/dist/core/routing/create-manifest.js +11 -1
- package/dist/core/routing/handler.js +5 -6
- package/dist/core/routing/parse-route.js +1 -1
- package/dist/core/routing/rewrite.js +1 -1
- package/dist/core/routing/router.d.ts +8 -0
- package/dist/core/routing/router.js +28 -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/util/normalized-url.js +5 -2
- 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/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/prerender/utils.js +5 -1
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +9 -0
- package/dist/runtime/server/jsx.js +1 -1
- package/dist/runtime/server/render/component.js +8 -6
- package/dist/runtime/server/render/head.js +1 -5
- package/dist/runtime/server/render/util.js +2 -2
- 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 +66 -18
- package/dist/types/public/content.d.ts +1 -1
- package/dist/types/public/index.d.ts +2 -1
- package/dist/types/public/integrations.d.ts +11 -3
- 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 +9 -1
- package/dist/vite-plugin-app/app.js +31 -21
- 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-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.js +7 -1
- package/package.json +13 -13
- package/templates/content/types.d.ts +1 -0
- package/types/transitions.d.ts +0 -7
package/dist/core/app/base.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
appendForwardSlash,
|
|
3
2
|
collapseDuplicateLeadingSlashes,
|
|
4
|
-
joinPaths,
|
|
5
3
|
prependForwardSlash,
|
|
6
4
|
removeTrailingForwardSlash
|
|
7
5
|
} from "@astrojs/internal-helpers/path";
|
|
8
6
|
import { matchPattern } from "@astrojs/internal-helpers/remote";
|
|
9
|
-
import {
|
|
7
|
+
import { computePathnameFromDomain } from "../i18n/domain.js";
|
|
10
8
|
import { PipelineFeatures } from "../base-pipeline.js";
|
|
11
9
|
import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
|
|
12
10
|
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
|
@@ -16,6 +14,7 @@ import { DefaultFetchHandler } from "../fetch/default-handler.js";
|
|
|
16
14
|
import { appSymbol } from "../constants.js";
|
|
17
15
|
import { DefaultErrorHandler } from "../errors/default-handler.js";
|
|
18
16
|
import { setRenderOptions } from "./render-options.js";
|
|
17
|
+
import { MultiLevelEncodingError } from "../util/pathname.js";
|
|
19
18
|
class BaseApp {
|
|
20
19
|
manifest;
|
|
21
20
|
manifestData;
|
|
@@ -116,19 +115,30 @@ class BaseApp {
|
|
|
116
115
|
return pathname;
|
|
117
116
|
}
|
|
118
117
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
118
|
+
* Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
|
|
119
|
+
* contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
|
|
120
|
+
* `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
|
|
121
|
+
* `URIError: URI malformed`, and because `match()` runs before `render()` that error
|
|
122
|
+
* escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
|
|
123
|
+
* middleware can't catch.
|
|
121
124
|
*/
|
|
122
|
-
|
|
123
|
-
const url = new URL(request.url);
|
|
124
|
-
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
125
|
+
safeDecodeURI(pathname) {
|
|
125
126
|
try {
|
|
126
127
|
return decodeURI(pathname);
|
|
127
128
|
} catch (e) {
|
|
128
|
-
this.adapterLogger.
|
|
129
|
+
this.adapterLogger.debug(e.toString());
|
|
129
130
|
return pathname;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Extracts the base-stripped, decoded pathname from a request.
|
|
135
|
+
* Used by adapters to compute the pathname for dev-mode route matching.
|
|
136
|
+
*/
|
|
137
|
+
getPathnameFromRequest(request) {
|
|
138
|
+
const url = new URL(request.url);
|
|
139
|
+
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
140
|
+
return this.safeDecodeURI(pathname);
|
|
141
|
+
}
|
|
132
142
|
/**
|
|
133
143
|
* Given a `Request`, it returns the `RouteData` that matches its `pathname`. By default, prerendered
|
|
134
144
|
* routes aren't returned, even if they are matched.
|
|
@@ -144,12 +154,16 @@ class BaseApp {
|
|
|
144
154
|
if (!pathname) {
|
|
145
155
|
pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
146
156
|
}
|
|
147
|
-
const routeData = this.pipeline.matchRoute(
|
|
157
|
+
const routeData = this.pipeline.matchRoute(this.safeDecodeURI(pathname));
|
|
148
158
|
if (!routeData) return void 0;
|
|
149
159
|
if (allowPrerenderedRoutes) {
|
|
150
160
|
return routeData;
|
|
151
161
|
}
|
|
152
162
|
if (routeData.prerender) {
|
|
163
|
+
if (routeData.params.length > 0) {
|
|
164
|
+
const allMatches = this.pipeline.matchAllRoutes(this.safeDecodeURI(pathname));
|
|
165
|
+
return allMatches.find((r) => !r.prerender);
|
|
166
|
+
}
|
|
153
167
|
return void 0;
|
|
154
168
|
}
|
|
155
169
|
return routeData;
|
|
@@ -165,55 +179,14 @@ class BaseApp {
|
|
|
165
179
|
return void 0;
|
|
166
180
|
}
|
|
167
181
|
computePathnameFromDomain(request) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
protocol = url.protocol;
|
|
177
|
-
}
|
|
178
|
-
if (!host) {
|
|
179
|
-
host = request.headers.get("Host");
|
|
180
|
-
}
|
|
181
|
-
if (host && protocol) {
|
|
182
|
-
host = host.split(":")[0];
|
|
183
|
-
try {
|
|
184
|
-
let locale;
|
|
185
|
-
const hostAsUrl = new URL(`${protocol}//${host}`);
|
|
186
|
-
for (const [domainKey, localeValue] of Object.entries(
|
|
187
|
-
this.manifest.i18n.domainLookupTable
|
|
188
|
-
)) {
|
|
189
|
-
const domainKeyAsUrl = new URL(domainKey);
|
|
190
|
-
if (hostAsUrl.host === domainKeyAsUrl.host && hostAsUrl.protocol === domainKeyAsUrl.protocol) {
|
|
191
|
-
locale = localeValue;
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
if (locale) {
|
|
196
|
-
pathname = prependForwardSlash(
|
|
197
|
-
joinPaths(normalizeTheLocale(locale), this.removeBase(url.pathname))
|
|
198
|
-
);
|
|
199
|
-
if (this.manifest.trailingSlash === "always") {
|
|
200
|
-
pathname = appendForwardSlash(pathname);
|
|
201
|
-
} else if (this.manifest.trailingSlash === "never") {
|
|
202
|
-
pathname = removeTrailingForwardSlash(pathname);
|
|
203
|
-
} else if (url.pathname.endsWith("/")) {
|
|
204
|
-
pathname = appendForwardSlash(pathname);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} catch (e) {
|
|
208
|
-
this.logger.error(
|
|
209
|
-
"router",
|
|
210
|
-
`Astro tried to parse ${protocol}//${host} as an URL, but it threw a parsing error. Check the X-Forwarded-Host and X-Forwarded-Proto headers.`
|
|
211
|
-
);
|
|
212
|
-
this.logger.error("router", `Error: ${e}`);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return pathname;
|
|
182
|
+
return computePathnameFromDomain(
|
|
183
|
+
request,
|
|
184
|
+
new URL(request.url),
|
|
185
|
+
this.manifest.i18n,
|
|
186
|
+
this.manifest.base,
|
|
187
|
+
this.manifest.trailingSlash,
|
|
188
|
+
this.logger
|
|
189
|
+
);
|
|
217
190
|
}
|
|
218
191
|
async render(request, {
|
|
219
192
|
addCookieHeader = false,
|
|
@@ -254,7 +227,7 @@ class BaseApp {
|
|
|
254
227
|
if (!routeData) {
|
|
255
228
|
const domainPathname = this.computePathnameFromDomain(request);
|
|
256
229
|
if (domainPathname) {
|
|
257
|
-
routeData = this.pipeline.matchRoute(
|
|
230
|
+
routeData = this.pipeline.matchRoute(this.safeDecodeURI(domainPathname));
|
|
258
231
|
}
|
|
259
232
|
}
|
|
260
233
|
const resolvedOptions = {
|
|
@@ -266,13 +239,20 @@ class BaseApp {
|
|
|
266
239
|
waitUntil
|
|
267
240
|
};
|
|
268
241
|
let response;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
242
|
+
try {
|
|
243
|
+
if (this.#fetchHandler instanceof DefaultFetchHandler) {
|
|
244
|
+
Reflect.set(request, appSymbol, this);
|
|
245
|
+
response = await this.#fetchHandler.renderWithOptions(request, resolvedOptions);
|
|
246
|
+
} else {
|
|
247
|
+
setRenderOptions(request, resolvedOptions);
|
|
248
|
+
Reflect.set(request, appSymbol, this);
|
|
249
|
+
response = await this.#fetchHandler.fetch(request);
|
|
250
|
+
}
|
|
251
|
+
} catch (err) {
|
|
252
|
+
if (err instanceof MultiLevelEncodingError) {
|
|
253
|
+
return new Response("Bad Request", { status: 400 });
|
|
254
|
+
}
|
|
255
|
+
throw err;
|
|
276
256
|
}
|
|
277
257
|
this.#warnMissingFeatures();
|
|
278
258
|
if (response.headers.get(ASTRO_ERROR_HEADER)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { NodeApp, loadApp, loadManifest, createRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
|
|
1
|
+
export { NodeApp, loadApp, loadManifest, createRequest, createRequestFromNodeRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
|
|
@@ -3,12 +3,14 @@ import {
|
|
|
3
3
|
loadApp,
|
|
4
4
|
loadManifest,
|
|
5
5
|
createRequest,
|
|
6
|
+
createRequestFromNodeRequest,
|
|
6
7
|
writeResponse,
|
|
7
8
|
getAbortControllerCleanup
|
|
8
9
|
} from "../node.js";
|
|
9
10
|
export {
|
|
10
11
|
NodeApp,
|
|
11
12
|
createRequest,
|
|
13
|
+
createRequestFromNodeRequest,
|
|
12
14
|
getAbortControllerCleanup,
|
|
13
15
|
loadApp,
|
|
14
16
|
loadManifest,
|
package/dist/core/app/node.d.ts
CHANGED
|
@@ -25,6 +25,22 @@ interface NodeRequest extends IncomingMessage {
|
|
|
25
25
|
* })
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* Internal version of `createRequest` that skips X-Forwarded-* header
|
|
30
|
+
* validation. Forwarded headers are resolved later inside `FetchState`,
|
|
31
|
+
* so doing it here too would duplicate work on every request.
|
|
32
|
+
*
|
|
33
|
+
* Use this for all internal call sites that go through `app.render()`
|
|
34
|
+
* (which creates a `FetchState`). The public `createRequest` keeps the
|
|
35
|
+
* forwarded header logic for external adapters that may not use
|
|
36
|
+
* `FetchState`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createRequestFromNodeRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
|
|
39
|
+
skipBody?: boolean;
|
|
40
|
+
allowedDomains?: Partial<RemotePattern>[];
|
|
41
|
+
bodySizeLimit?: number;
|
|
42
|
+
port?: number;
|
|
43
|
+
}): Request;
|
|
28
44
|
export declare function createRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
|
|
29
45
|
skipBody?: boolean;
|
|
30
46
|
allowedDomains?: Partial<RemotePattern>[];
|
package/dist/core/app/node.js
CHANGED
|
@@ -9,6 +9,48 @@ import {
|
|
|
9
9
|
validateForwardedHeaders,
|
|
10
10
|
validateHost
|
|
11
11
|
} from "./validate-headers.js";
|
|
12
|
+
function createRequestFromNodeRequest(req, {
|
|
13
|
+
skipBody = false,
|
|
14
|
+
allowedDomains = [],
|
|
15
|
+
bodySizeLimit,
|
|
16
|
+
port: serverPort
|
|
17
|
+
} = {}) {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
|
|
20
|
+
const protocol = isEncrypted ? "https" : "http";
|
|
21
|
+
const hostname = typeof req.headers.host === "string" ? req.headers.host : typeof req.headers[":authority"] === "string" ? req.headers[":authority"] : serverPort ? `localhost:${serverPort}` : "localhost";
|
|
22
|
+
let url;
|
|
23
|
+
try {
|
|
24
|
+
url = new URL(`${protocol}://${hostname}${req.url}`);
|
|
25
|
+
} catch {
|
|
26
|
+
url = new URL(`${protocol}://${hostname}`);
|
|
27
|
+
}
|
|
28
|
+
const options = {
|
|
29
|
+
method: req.method || "GET",
|
|
30
|
+
headers: makeRequestHeaders(req),
|
|
31
|
+
signal: controller.signal
|
|
32
|
+
};
|
|
33
|
+
const bodyAllowed = options.method !== "HEAD" && options.method !== "GET" && skipBody === false;
|
|
34
|
+
if (bodyAllowed) {
|
|
35
|
+
Object.assign(options, makeRequestBody(req, bodySizeLimit));
|
|
36
|
+
}
|
|
37
|
+
const request = new Request(url, options);
|
|
38
|
+
wireAbortController(req, controller);
|
|
39
|
+
const untrustedHostname = req.headers.host ?? req.headers[":authority"];
|
|
40
|
+
const validatedHostname = validateHost(
|
|
41
|
+
typeof untrustedHostname === "string" ? untrustedHostname : void 0,
|
|
42
|
+
protocol,
|
|
43
|
+
allowedDomains
|
|
44
|
+
);
|
|
45
|
+
const forwardedHost = getFirstForwardedValue(req.headers["x-forwarded-host"]);
|
|
46
|
+
const hostValidated = validatedHostname !== void 0 || forwardedHost !== void 0 && allowedDomains.length > 0;
|
|
47
|
+
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
48
|
+
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
49
|
+
if (clientIp) {
|
|
50
|
+
Reflect.set(request, clientAddressSymbol, clientIp);
|
|
51
|
+
}
|
|
52
|
+
return request;
|
|
53
|
+
}
|
|
12
54
|
function createRequest(req, {
|
|
13
55
|
skipBody = false,
|
|
14
56
|
allowedDomains = [],
|
|
@@ -51,6 +93,16 @@ function createRequest(req, {
|
|
|
51
93
|
Object.assign(options, makeRequestBody(req, bodySizeLimit));
|
|
52
94
|
}
|
|
53
95
|
const request = new Request(url, options);
|
|
96
|
+
wireAbortController(req, controller);
|
|
97
|
+
const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
|
|
98
|
+
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
99
|
+
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
100
|
+
if (clientIp) {
|
|
101
|
+
Reflect.set(request, clientAddressSymbol, clientIp);
|
|
102
|
+
}
|
|
103
|
+
return request;
|
|
104
|
+
}
|
|
105
|
+
function wireAbortController(req, controller) {
|
|
54
106
|
const socket = getRequestSocket(req);
|
|
55
107
|
if (socket && typeof socket.on === "function") {
|
|
56
108
|
const existingCleanup = getAbortControllerCleanup(req);
|
|
@@ -85,13 +137,6 @@ function createRequest(req, {
|
|
|
85
137
|
onSocketClose();
|
|
86
138
|
}
|
|
87
139
|
}
|
|
88
|
-
const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
|
|
89
|
-
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
90
|
-
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
91
|
-
if (clientIp) {
|
|
92
|
-
Reflect.set(request, clientAddressSymbol, clientIp);
|
|
93
|
-
}
|
|
94
|
-
return request;
|
|
95
140
|
}
|
|
96
141
|
async function writeResponse(source, destination) {
|
|
97
142
|
const { status, headers, body, statusText } = source;
|
|
@@ -147,18 +192,15 @@ class NodeApp extends App {
|
|
|
147
192
|
}
|
|
148
193
|
match(req, allowPrerenderedRoutes = false) {
|
|
149
194
|
if (!(req instanceof Request)) {
|
|
150
|
-
req =
|
|
151
|
-
skipBody: true
|
|
152
|
-
allowedDomains: this.manifest.allowedDomains
|
|
195
|
+
req = createRequestFromNodeRequest(req, {
|
|
196
|
+
skipBody: true
|
|
153
197
|
});
|
|
154
198
|
}
|
|
155
199
|
return super.match(req, allowPrerenderedRoutes);
|
|
156
200
|
}
|
|
157
201
|
render(request, options) {
|
|
158
202
|
if (!(request instanceof Request)) {
|
|
159
|
-
request =
|
|
160
|
-
allowedDomains: this.manifest.allowedDomains
|
|
161
|
-
});
|
|
203
|
+
request = createRequestFromNodeRequest(request);
|
|
162
204
|
}
|
|
163
205
|
return super.render(request, options);
|
|
164
206
|
}
|
|
@@ -219,6 +261,9 @@ function makeRequestBody(req, bodySizeLimit) {
|
|
|
219
261
|
if (typeof req.body === "string" && req.body.length > 0) {
|
|
220
262
|
return { body: Buffer.from(req.body) };
|
|
221
263
|
}
|
|
264
|
+
if (req.body instanceof ArrayBuffer || ArrayBuffer.isView(req.body)) {
|
|
265
|
+
return { body: req.body };
|
|
266
|
+
}
|
|
222
267
|
if (typeof req.body === "object" && req.body !== null && Object.keys(req.body).length > 0) {
|
|
223
268
|
return { body: Buffer.from(JSON.stringify(req.body)) };
|
|
224
269
|
}
|
|
@@ -280,6 +325,7 @@ async function loadApp(rootFolder) {
|
|
|
280
325
|
export {
|
|
281
326
|
NodeApp,
|
|
282
327
|
createRequest,
|
|
328
|
+
createRequestFromNodeRequest,
|
|
283
329
|
getAbortControllerCleanup,
|
|
284
330
|
loadApp,
|
|
285
331
|
loadManifest,
|
|
@@ -29,6 +29,9 @@ export declare const PipelineFeatures: {
|
|
|
29
29
|
readonly i18n: number;
|
|
30
30
|
readonly cache: number;
|
|
31
31
|
};
|
|
32
|
+
/** All feature bits ORed together. Keep next to `PipelineFeatures` so
|
|
33
|
+
* new flags are hard to forget. */
|
|
34
|
+
export declare const ALL_PIPELINE_FEATURES: number;
|
|
32
35
|
/**
|
|
33
36
|
* The `Pipeline` represents the static parts of rendering that do not change between requests.
|
|
34
37
|
* These are mostly known when the server first starts up and do not change.
|
|
@@ -117,6 +120,13 @@ export declare abstract class Pipeline {
|
|
|
117
120
|
* routes or check public assets — use `BaseApp.match()` for that.
|
|
118
121
|
*/
|
|
119
122
|
matchRoute(pathname: string): RouteData | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Returns all routes matching the given pathname, in priority order.
|
|
125
|
+
* Used when the first match cannot serve the request (e.g. a
|
|
126
|
+
* prerendered dynamic route that doesn't cover this specific path)
|
|
127
|
+
* and the caller needs to try subsequent matches.
|
|
128
|
+
*/
|
|
129
|
+
matchAllRoutes(pathname: string): RouteData[];
|
|
120
130
|
/**
|
|
121
131
|
* Rebuilds the internal router after routes have been added or
|
|
122
132
|
* removed (e.g. by the dev server on HMR).
|
|
@@ -21,6 +21,7 @@ const PipelineFeatures = {
|
|
|
21
21
|
i18n: 1 << 4,
|
|
22
22
|
cache: 1 << 5
|
|
23
23
|
};
|
|
24
|
+
const ALL_PIPELINE_FEATURES = PipelineFeatures.redirects | PipelineFeatures.sessions | PipelineFeatures.actions | PipelineFeatures.middleware | PipelineFeatures.i18n | PipelineFeatures.cache;
|
|
24
25
|
class Pipeline {
|
|
25
26
|
internalMiddleware;
|
|
26
27
|
resolvedMiddleware = void 0;
|
|
@@ -123,6 +124,15 @@ class Pipeline {
|
|
|
123
124
|
if (match.type !== "match") return void 0;
|
|
124
125
|
return match.route;
|
|
125
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns all routes matching the given pathname, in priority order.
|
|
129
|
+
* Used when the first match cannot serve the request (e.g. a
|
|
130
|
+
* prerendered dynamic route that doesn't cover this specific path)
|
|
131
|
+
* and the caller needs to try subsequent matches.
|
|
132
|
+
*/
|
|
133
|
+
matchAllRoutes(pathname) {
|
|
134
|
+
return this.#router.matchAll(pathname, { allowWithoutBase: true });
|
|
135
|
+
}
|
|
126
136
|
/**
|
|
127
137
|
* Rebuilds the internal router after routes have been added or
|
|
128
138
|
* removed (e.g. by the dev server on HMR).
|
|
@@ -182,7 +192,8 @@ class Pipeline {
|
|
|
182
192
|
if (this.resolvedActions) {
|
|
183
193
|
return this.resolvedActions;
|
|
184
194
|
} else if (this.actions) {
|
|
185
|
-
|
|
195
|
+
this.resolvedActions = await this.actions();
|
|
196
|
+
return this.resolvedActions;
|
|
186
197
|
}
|
|
187
198
|
return NOOP_ACTIONS_MOD;
|
|
188
199
|
}
|
|
@@ -285,6 +296,7 @@ class Pipeline {
|
|
|
285
296
|
}
|
|
286
297
|
}
|
|
287
298
|
export {
|
|
299
|
+
ALL_PIPELINE_FEATURES,
|
|
288
300
|
Pipeline,
|
|
289
301
|
PipelineFeatures
|
|
290
302
|
};
|
|
@@ -187,13 +187,20 @@ ${colors.bgGreen(colors.black(` ${verb} static routes `))}`);
|
|
|
187
187
|
const cpuCount = os.cpus().length;
|
|
188
188
|
const assetsCreationPipeline = await prepareAssetsGenerationEnv(options, totalCount);
|
|
189
189
|
const queue = new PQueue({ concurrency: Math.max(cpuCount, 1) });
|
|
190
|
+
const errors = [];
|
|
190
191
|
const assetsTimer = performance.now();
|
|
191
192
|
for (const [originalPath, transforms] of staticImageList) {
|
|
192
193
|
queue.add(() => generateImagesForPath(originalPath, transforms, assetsCreationPipeline)).catch((e) => {
|
|
193
|
-
|
|
194
|
+
logger.warn("build", `Unable to generate optimized image for ${originalPath}: ${e}`);
|
|
195
|
+
errors.push(new Error(`Error generating image for ${originalPath}: ${e}`, { cause: e }));
|
|
194
196
|
});
|
|
195
197
|
}
|
|
196
198
|
await queue.onIdle();
|
|
199
|
+
if (errors.length === 1) {
|
|
200
|
+
throw errors[0];
|
|
201
|
+
} else if (errors.length > 1) {
|
|
202
|
+
throw new AggregateError(errors, `${errors.length} errors occurred during asset generation`);
|
|
203
|
+
}
|
|
197
204
|
const assetsTimeEnd = performance.now();
|
|
198
205
|
logger.info(null, colors.green(`\u2713 Completed in ${getTimeStat(assetsTimer, assetsTimeEnd)}.
|
|
199
206
|
`));
|
|
@@ -9,16 +9,6 @@ interface BuildOptions {
|
|
|
9
9
|
* @default false
|
|
10
10
|
*/
|
|
11
11
|
devOutput?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Teardown the compiler WASM instance after build. This can improve performance when
|
|
14
|
-
* building once, but may cause a performance hit if building multiple times in a row.
|
|
15
|
-
*
|
|
16
|
-
* When building multiple projects in the same execution (e.g. during tests), disabling
|
|
17
|
-
* this option can greatly improve performance at the cost of some extra memory usage.
|
|
18
|
-
*
|
|
19
|
-
* @default true
|
|
20
|
-
*/
|
|
21
|
-
teardownCompiler?: boolean;
|
|
22
12
|
}
|
|
23
13
|
/**
|
|
24
14
|
* Builds your site for deployment. By default, this will generate static files and place them in a dist/ directory.
|
|
@@ -50,7 +40,6 @@ export declare class AstroBuilder {
|
|
|
50
40
|
private origin;
|
|
51
41
|
private routesList;
|
|
52
42
|
private timer;
|
|
53
|
-
private teardownCompiler;
|
|
54
43
|
private sync;
|
|
55
44
|
constructor(settings: AstroSettings, options: AstroBuilderOptions);
|
|
56
45
|
/** Setup Vite and run any async setup logic that couldn't run inside of the constructor. */
|
package/dist/core/build/index.js
CHANGED
|
@@ -55,14 +55,12 @@ class AstroBuilder {
|
|
|
55
55
|
origin;
|
|
56
56
|
routesList;
|
|
57
57
|
timer;
|
|
58
|
-
teardownCompiler;
|
|
59
58
|
sync;
|
|
60
59
|
constructor(settings, options) {
|
|
61
60
|
this.mode = options.mode;
|
|
62
61
|
this.runtimeMode = options.runtimeMode;
|
|
63
62
|
this.settings = settings;
|
|
64
63
|
this.logger = options.logger;
|
|
65
|
-
this.teardownCompiler = options.teardownCompiler ?? true;
|
|
66
64
|
this.sync = options.sync ?? true;
|
|
67
65
|
this.origin = settings.config.site ? new URL(settings.config.site).origin : `http://localhost:${settings.config.server.port}`;
|
|
68
66
|
this.routesList = options.routesList ?? { routes: [] };
|
|
@@ -151,7 +149,6 @@ class AstroBuilder {
|
|
|
151
149
|
runtimeMode: this.runtimeMode,
|
|
152
150
|
origin: this.origin,
|
|
153
151
|
pageNames,
|
|
154
|
-
teardownCompiler: this.teardownCompiler,
|
|
155
152
|
viteConfig,
|
|
156
153
|
key: keyPromise
|
|
157
154
|
};
|
|
@@ -92,6 +92,13 @@ export interface BuildInternals {
|
|
|
92
92
|
moduleIds: string[];
|
|
93
93
|
prerender: boolean;
|
|
94
94
|
}>;
|
|
95
|
+
/**
|
|
96
|
+
* Component exports that were rendered during the SSR build.
|
|
97
|
+
* Used by the client build's cssScopeTo recovery to distinguish between
|
|
98
|
+
* CSS that was tree-shaken because the component wasn't rendered in SSR
|
|
99
|
+
* vs CSS that was included in SSR.
|
|
100
|
+
*/
|
|
101
|
+
ssrRenderedExports?: Map<string, Set<string>>;
|
|
95
102
|
}
|
|
96
103
|
/**
|
|
97
104
|
* Creates internal maps used to coordinate the CSS and HTML plugins.
|
|
@@ -6,5 +6,11 @@ import type { StaticBuildOptions } from '../types.js';
|
|
|
6
6
|
* bypass the HTML rendering pipeline and miss skew protection query params.
|
|
7
7
|
*
|
|
8
8
|
* Uses es-module-lexer to reliably parse both static and dynamic imports.
|
|
9
|
+
*
|
|
10
|
+
* This runs in `generateBundle` (not `renderChunk`) so that Vite's CSS plugin
|
|
11
|
+
* can first remove pure-CSS wrapper chunks and replace their imports with
|
|
12
|
+
* `/* empty css * /` comments. If we rewrote imports earlier (in `renderChunk`),
|
|
13
|
+
* the appended query params would break Vite's regex-based CSS chunk cleanup,
|
|
14
|
+
* leaving dangling imports to deleted chunks that 404 at runtime.
|
|
9
15
|
*/
|
|
10
16
|
export declare function pluginChunkImports(options: StaticBuildOptions): VitePlugin | undefined;
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { init, parse } from "es-module-lexer";
|
|
2
2
|
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../../constants.js";
|
|
3
|
+
function getImportSpecifier(code, imp) {
|
|
4
|
+
if (imp.n != null) return imp.n;
|
|
5
|
+
if (imp.d > -1) {
|
|
6
|
+
const raw = code.slice(imp.s, imp.e);
|
|
7
|
+
const quote = raw[0];
|
|
8
|
+
if ((quote === "`" || quote === '"' || quote === "'") && raw.at(-1) === quote) {
|
|
9
|
+
const inner = raw.slice(1, -1);
|
|
10
|
+
if (!inner.includes("${")) return inner;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return void 0;
|
|
14
|
+
}
|
|
3
15
|
function pluginChunkImports(options) {
|
|
4
16
|
const assetQueryParams = options.settings.adapter?.client?.assetQueryParams;
|
|
5
17
|
if (!assetQueryParams || assetQueryParams.toString() === "") {
|
|
@@ -12,25 +24,25 @@ function pluginChunkImports(options) {
|
|
|
12
24
|
applyToEnvironment(environment) {
|
|
13
25
|
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client;
|
|
14
26
|
},
|
|
15
|
-
async
|
|
16
|
-
if (!code.includes("./")) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
27
|
+
async generateBundle(_options, bundle) {
|
|
19
28
|
await init;
|
|
20
|
-
const [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
for (const [, chunk] of Object.entries(bundle)) {
|
|
30
|
+
if (chunk.type !== "chunk") continue;
|
|
31
|
+
if (!chunk.code.includes("./")) continue;
|
|
32
|
+
const [imports] = parse(chunk.code);
|
|
33
|
+
const relativeImports = imports.filter((imp) => {
|
|
34
|
+
const name = getImportSpecifier(chunk.code, imp);
|
|
35
|
+
return name != null && /^\.\.?\//.test(name) && /\.(?:js|mjs)$/.test(name);
|
|
36
|
+
});
|
|
37
|
+
if (relativeImports.length === 0) continue;
|
|
38
|
+
let rewritten = chunk.code;
|
|
39
|
+
for (let i = relativeImports.length - 1; i >= 0; i--) {
|
|
40
|
+
const imp = relativeImports[i];
|
|
41
|
+
const insertAt = imp.d > -1 ? imp.e - 1 : imp.e;
|
|
42
|
+
rewritten = rewritten.slice(0, insertAt) + "?" + queryString + rewritten.slice(insertAt);
|
|
43
|
+
}
|
|
44
|
+
chunk.code = rewritten;
|
|
32
45
|
}
|
|
33
|
-
return { code: rewritten, map: null };
|
|
34
46
|
}
|
|
35
47
|
};
|
|
36
48
|
}
|
|
@@ -46,10 +46,25 @@ function rollupPluginAstroBuildCSS(options) {
|
|
|
46
46
|
internals.cssModuleToChunkIdMap.set(moduleId, chunk.fileName);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
for (const [moduleId, moduleInfo] of Object.entries(chunk.modules || {})) {
|
|
50
|
+
if (moduleInfo.renderedExports.length > 0) {
|
|
51
|
+
const existing = internals.ssrRenderedExports?.get(moduleId);
|
|
52
|
+
if (existing) {
|
|
53
|
+
for (const exp of moduleInfo.renderedExports) {
|
|
54
|
+
existing.add(exp);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
internals.ssrRenderedExports ??= /* @__PURE__ */ new Map();
|
|
58
|
+
internals.ssrRenderedExports.set(moduleId, new Set(moduleInfo.renderedExports));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
49
62
|
}
|
|
50
63
|
}
|
|
51
64
|
const renderedComponentExports = /* @__PURE__ */ new Map();
|
|
52
65
|
const componentToPages = /* @__PURE__ */ new Map();
|
|
66
|
+
const deletedCssAssets = /* @__PURE__ */ new Map();
|
|
67
|
+
const cssScopeToAddedCss = /* @__PURE__ */ new Set();
|
|
53
68
|
if (this.environment?.name === ASTRO_VITE_ENVIRONMENT_NAMES.client) {
|
|
54
69
|
for (const [, item] of Object.entries(bundle)) {
|
|
55
70
|
if (item.type !== "chunk") continue;
|
|
@@ -76,6 +91,9 @@ function rollupPluginAstroBuildCSS(options) {
|
|
|
76
91
|
);
|
|
77
92
|
if (allCssInSSR && shouldDeleteCSSChunk(allModules, internals)) {
|
|
78
93
|
for (const cssId of meta.importedCss) {
|
|
94
|
+
if (bundle[cssId]) {
|
|
95
|
+
deletedCssAssets.set(cssId, bundle[cssId]);
|
|
96
|
+
}
|
|
79
97
|
delete bundle[cssId];
|
|
80
98
|
}
|
|
81
99
|
}
|
|
@@ -157,6 +175,14 @@ function rollupPluginAstroBuildCSS(options) {
|
|
|
157
175
|
}
|
|
158
176
|
}
|
|
159
177
|
}
|
|
178
|
+
const ssrExports = internals.ssrRenderedExports?.get(scopedToModule);
|
|
179
|
+
if (!ssrExports || !ssrExports.has(scopedToExport)) {
|
|
180
|
+
for (const cssId of meta.importedCss) {
|
|
181
|
+
if (deletedCssAssets.has(cssId)) {
|
|
182
|
+
cssScopeToAddedCss.add(cssId);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
160
186
|
}
|
|
161
187
|
}
|
|
162
188
|
}
|
|
@@ -191,6 +217,13 @@ function rollupPluginAstroBuildCSS(options) {
|
|
|
191
217
|
}
|
|
192
218
|
}
|
|
193
219
|
}
|
|
220
|
+
if (cssScopeToAddedCss.size > 0) {
|
|
221
|
+
for (const cssId of cssScopeToAddedCss) {
|
|
222
|
+
if (deletedCssAssets.has(cssId) && !bundle[cssId]) {
|
|
223
|
+
bundle[cssId] = deletedCssAssets.get(cssId);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
194
227
|
}
|
|
195
228
|
};
|
|
196
229
|
const singleCssPlugin = {
|