astro 6.4.3 → 6.4.5
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/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/content/content-layer.js +3 -3
- package/dist/core/app/base.d.ts +9 -0
- package/dist/core/app/base.js +32 -66
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +6 -6
- package/dist/core/fetch/fetch-state.js +44 -7
- package/dist/core/i18n/domain.d.ts +12 -0
- package/dist/core/i18n/domain.js +66 -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/routing/create-manifest.js +1 -1
- package/dist/core/routing/parse-route.js +1 -1
- package/dist/core/routing/rewrite.js +1 -1
- package/dist/runtime/server/render/head.js +1 -5
- package/dist/vite-plugin-hmr-reload/index.js +3 -0
- package/dist/vite-plugin-utils/index.js +7 -1
- package/package.json +1 -1
|
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Content config changed");
|
|
198
198
|
shouldClear = true;
|
|
199
199
|
}
|
|
200
|
-
if (previousAstroVersion && previousAstroVersion !== "6.4.
|
|
200
|
+
if (previousAstroVersion && previousAstroVersion !== "6.4.5") {
|
|
201
201
|
logger.info("Astro version changed");
|
|
202
202
|
shouldClear = true;
|
|
203
203
|
}
|
|
@@ -205,8 +205,8 @@ ${contentConfig.error.message}`
|
|
|
205
205
|
logger.info("Clearing content store");
|
|
206
206
|
this.#store.clearAll();
|
|
207
207
|
}
|
|
208
|
-
if ("6.4.
|
|
209
|
-
this.#store.metaStore().set("astro-version", "6.4.
|
|
208
|
+
if ("6.4.5") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "6.4.5");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
package/dist/core/app/base.d.ts
CHANGED
|
@@ -131,6 +131,15 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
|
131
131
|
abstract createPipeline(streaming: boolean, manifest: SSRManifest, ...args: any[]): P;
|
|
132
132
|
set setManifestData(newManifestData: RoutesList);
|
|
133
133
|
removeBase(pathname: string): string;
|
|
134
|
+
/**
|
|
135
|
+
* Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
|
|
136
|
+
* contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
|
|
137
|
+
* `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
|
|
138
|
+
* `URIError: URI malformed`, and because `match()` runs before `render()` that error
|
|
139
|
+
* escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
|
|
140
|
+
* middleware can't catch.
|
|
141
|
+
*/
|
|
142
|
+
private safeDecodeURI;
|
|
134
143
|
/**
|
|
135
144
|
* Extracts the base-stripped, decoded pathname from a request.
|
|
136
145
|
* Used by adapters to compute the pathname for dev-mode route matching.
|
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";
|
|
@@ -46,11 +44,9 @@ class BaseApp {
|
|
|
46
44
|
return this.pipeline.logger;
|
|
47
45
|
}
|
|
48
46
|
get adapterLogger() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.manifest.adapterName
|
|
53
|
-
);
|
|
47
|
+
const currentOptions = this.logger.options;
|
|
48
|
+
if (!this.#adapterLogger || this.#adapterLogger.options !== currentOptions) {
|
|
49
|
+
this.#adapterLogger = new AstroIntegrationLogger(currentOptions, this.manifest.adapterName);
|
|
54
50
|
}
|
|
55
51
|
return this.#adapterLogger;
|
|
56
52
|
}
|
|
@@ -117,19 +113,30 @@ class BaseApp {
|
|
|
117
113
|
return pathname;
|
|
118
114
|
}
|
|
119
115
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
116
|
+
* Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
|
|
117
|
+
* contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
|
|
118
|
+
* `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
|
|
119
|
+
* `URIError: URI malformed`, and because `match()` runs before `render()` that error
|
|
120
|
+
* escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
|
|
121
|
+
* middleware can't catch.
|
|
122
122
|
*/
|
|
123
|
-
|
|
124
|
-
const url = new URL(request.url);
|
|
125
|
-
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
123
|
+
safeDecodeURI(pathname) {
|
|
126
124
|
try {
|
|
127
125
|
return decodeURI(pathname);
|
|
128
126
|
} catch (e) {
|
|
129
|
-
this.adapterLogger.
|
|
127
|
+
this.adapterLogger.debug(e.toString());
|
|
130
128
|
return pathname;
|
|
131
129
|
}
|
|
132
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Extracts the base-stripped, decoded pathname from a request.
|
|
133
|
+
* Used by adapters to compute the pathname for dev-mode route matching.
|
|
134
|
+
*/
|
|
135
|
+
getPathnameFromRequest(request) {
|
|
136
|
+
const url = new URL(request.url);
|
|
137
|
+
const pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
138
|
+
return this.safeDecodeURI(pathname);
|
|
139
|
+
}
|
|
133
140
|
/**
|
|
134
141
|
* Given a `Request`, it returns the `RouteData` that matches its `pathname`. By default, prerendered
|
|
135
142
|
* routes aren't returned, even if they are matched.
|
|
@@ -145,14 +152,14 @@ class BaseApp {
|
|
|
145
152
|
if (!pathname) {
|
|
146
153
|
pathname = prependForwardSlash(this.removeBase(url.pathname));
|
|
147
154
|
}
|
|
148
|
-
const routeData = this.pipeline.matchRoute(
|
|
155
|
+
const routeData = this.pipeline.matchRoute(this.safeDecodeURI(pathname));
|
|
149
156
|
if (!routeData) return void 0;
|
|
150
157
|
if (allowPrerenderedRoutes) {
|
|
151
158
|
return routeData;
|
|
152
159
|
}
|
|
153
160
|
if (routeData.prerender) {
|
|
154
161
|
if (routeData.params.length > 0) {
|
|
155
|
-
const allMatches = this.pipeline.matchAllRoutes(
|
|
162
|
+
const allMatches = this.pipeline.matchAllRoutes(this.safeDecodeURI(pathname));
|
|
156
163
|
return allMatches.find((r) => !r.prerender);
|
|
157
164
|
}
|
|
158
165
|
return void 0;
|
|
@@ -170,55 +177,14 @@ class BaseApp {
|
|
|
170
177
|
return void 0;
|
|
171
178
|
}
|
|
172
179
|
computePathnameFromDomain(request) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
protocol = url.protocol;
|
|
182
|
-
}
|
|
183
|
-
if (!host) {
|
|
184
|
-
host = request.headers.get("Host");
|
|
185
|
-
}
|
|
186
|
-
if (host && protocol) {
|
|
187
|
-
host = host.split(":")[0];
|
|
188
|
-
try {
|
|
189
|
-
let locale;
|
|
190
|
-
const hostAsUrl = new URL(`${protocol}//${host}`);
|
|
191
|
-
for (const [domainKey, localeValue] of Object.entries(
|
|
192
|
-
this.manifest.i18n.domainLookupTable
|
|
193
|
-
)) {
|
|
194
|
-
const domainKeyAsUrl = new URL(domainKey);
|
|
195
|
-
if (hostAsUrl.host === domainKeyAsUrl.host && hostAsUrl.protocol === domainKeyAsUrl.protocol) {
|
|
196
|
-
locale = localeValue;
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (locale) {
|
|
201
|
-
pathname = prependForwardSlash(
|
|
202
|
-
joinPaths(normalizeTheLocale(locale), this.removeBase(url.pathname))
|
|
203
|
-
);
|
|
204
|
-
if (this.manifest.trailingSlash === "always") {
|
|
205
|
-
pathname = appendForwardSlash(pathname);
|
|
206
|
-
} else if (this.manifest.trailingSlash === "never") {
|
|
207
|
-
pathname = removeTrailingForwardSlash(pathname);
|
|
208
|
-
} else if (url.pathname.endsWith("/")) {
|
|
209
|
-
pathname = appendForwardSlash(pathname);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
} catch (e) {
|
|
213
|
-
this.logger.error(
|
|
214
|
-
"router",
|
|
215
|
-
`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.`
|
|
216
|
-
);
|
|
217
|
-
this.logger.error("router", `Error: ${e}`);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return pathname;
|
|
180
|
+
return computePathnameFromDomain(
|
|
181
|
+
request,
|
|
182
|
+
new URL(request.url),
|
|
183
|
+
this.manifest.i18n,
|
|
184
|
+
this.manifest.base,
|
|
185
|
+
this.manifest.trailingSlash,
|
|
186
|
+
this.logger
|
|
187
|
+
);
|
|
222
188
|
}
|
|
223
189
|
async render(request, {
|
|
224
190
|
addCookieHeader = false,
|
|
@@ -259,7 +225,7 @@ class BaseApp {
|
|
|
259
225
|
if (!routeData) {
|
|
260
226
|
const domainPathname = this.computePathnameFromDomain(request);
|
|
261
227
|
if (domainPathname) {
|
|
262
|
-
routeData = this.pipeline.matchRoute(
|
|
228
|
+
routeData = this.pipeline.matchRoute(this.safeDecodeURI(domainPathname));
|
|
263
229
|
}
|
|
264
230
|
}
|
|
265
231
|
const resolvedOptions = {
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -37,7 +37,7 @@ async function dev(inlineConfig) {
|
|
|
37
37
|
await telemetry.record([]);
|
|
38
38
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
39
39
|
const logger = restart.container.logger;
|
|
40
|
-
const currentVersion = "6.4.
|
|
40
|
+
const currentVersion = "6.4.5";
|
|
41
41
|
const isPrerelease = currentVersion.includes("-");
|
|
42
42
|
if (!isPrerelease) {
|
|
43
43
|
try {
|
|
@@ -185,8 +185,8 @@ export declare const NoClientOnlyHint: {
|
|
|
185
185
|
* ---
|
|
186
186
|
* export async function getStaticPaths() {
|
|
187
187
|
* return [
|
|
188
|
-
* { params: {
|
|
189
|
-
* { params: {
|
|
188
|
+
* { params: { id: "blog" } },
|
|
189
|
+
* { params: { id: "about" } }
|
|
190
190
|
* ];
|
|
191
191
|
*}
|
|
192
192
|
*---
|
|
@@ -208,8 +208,8 @@ export declare const InvalidGetStaticPathParam: {
|
|
|
208
208
|
* ```ts title="pages/blog/[id].astro"
|
|
209
209
|
* export async function getStaticPaths() {
|
|
210
210
|
* return [ // <-- Array
|
|
211
|
-
* { params: {
|
|
212
|
-
* { params: {
|
|
211
|
+
* { params: { id: "blog" } }, // <-- Object
|
|
212
|
+
* { params: { id: "about" } }
|
|
213
213
|
* ];
|
|
214
214
|
*}
|
|
215
215
|
* ```
|
|
@@ -231,8 +231,8 @@ export declare const InvalidGetStaticPathsEntry: {
|
|
|
231
231
|
* ```ts title="pages/blog/[id].astro"
|
|
232
232
|
* export async function getStaticPaths() {
|
|
233
233
|
* return [ // <-- Array
|
|
234
|
-
* { params: {
|
|
235
|
-
* { params: {
|
|
234
|
+
* { params: { id: "blog" } },
|
|
235
|
+
* { params: { id: "about" } }
|
|
236
236
|
* ];
|
|
237
237
|
*}
|
|
238
238
|
* ```
|
|
@@ -9,6 +9,7 @@ import { createCallAction, createGetActionResult, hasActionPayload } from "../..
|
|
|
9
9
|
import { AstroCookies } from "../cookies/index.js";
|
|
10
10
|
import { Slots } from "../render/index.js";
|
|
11
11
|
import {
|
|
12
|
+
appSymbol,
|
|
12
13
|
ASTRO_GENERATOR,
|
|
13
14
|
fetchStateSymbol,
|
|
14
15
|
originPathnameSymbol,
|
|
@@ -29,6 +30,7 @@ import { Rewrites } from "../rewrites/handler.js";
|
|
|
29
30
|
import { isRoute404or500, isRouteServerIsland } from "../routing/match.js";
|
|
30
31
|
import { normalizeUrl } from "../util/normalized-url.js";
|
|
31
32
|
import { getOriginPathname, setOriginPathname } from "../routing/rewrite.js";
|
|
33
|
+
import { computePathnameFromDomain } from "../i18n/domain.js";
|
|
32
34
|
import { getCustom404Route, routeHasHtmlExtension } from "../routing/helpers.js";
|
|
33
35
|
import { getRenderOptions } from "../app/render-options.js";
|
|
34
36
|
import { getFirstForwardedValue, validateForwardedHeaders } from "../app/validate-headers.js";
|
|
@@ -136,6 +138,13 @@ class FetchState {
|
|
|
136
138
|
#rewrites;
|
|
137
139
|
/** Memoized Astro page partial. */
|
|
138
140
|
#astroPagePartial;
|
|
141
|
+
/**
|
|
142
|
+
* Locale-prefixed pathname derived from the Host header for domain-based
|
|
143
|
+
* i18n routing (e.g. `/en/boats/1/foo`), or `undefined` when the request
|
|
144
|
+
* isn't served from a locale-mapped domain. When set, `this.pathname` is
|
|
145
|
+
* derived from it so locale/param resolution match the route pattern.
|
|
146
|
+
*/
|
|
147
|
+
#domainPathname;
|
|
139
148
|
/** Memoized current locale. */
|
|
140
149
|
#currentLocale;
|
|
141
150
|
/** Memoized preferred locale. */
|
|
@@ -158,7 +167,24 @@ class FetchState {
|
|
|
158
167
|
this.componentInstance = void 0;
|
|
159
168
|
this.slots = void 0;
|
|
160
169
|
const url = new URL(request.url);
|
|
161
|
-
|
|
170
|
+
const domainPathname = computePathnameFromDomain(
|
|
171
|
+
request,
|
|
172
|
+
url,
|
|
173
|
+
pipeline.manifest.i18n,
|
|
174
|
+
pipeline.manifest.base,
|
|
175
|
+
pipeline.manifest.trailingSlash,
|
|
176
|
+
pipeline.logger
|
|
177
|
+
);
|
|
178
|
+
if (domainPathname) {
|
|
179
|
+
this.#domainPathname = domainPathname;
|
|
180
|
+
try {
|
|
181
|
+
this.pathname = decodeURI(domainPathname);
|
|
182
|
+
} catch {
|
|
183
|
+
this.pathname = domainPathname;
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
this.pathname = this.#computePathname(url);
|
|
187
|
+
}
|
|
162
188
|
this.timeStart = performance.now();
|
|
163
189
|
this.clientAddress = options?.clientAddress;
|
|
164
190
|
this.locals = options?.locals ?? {};
|
|
@@ -167,9 +193,9 @@ class FetchState {
|
|
|
167
193
|
if (pipeline.manifest.allowedDomains && pipeline.manifest.allowedDomains.length > 0) {
|
|
168
194
|
this.#applyForwardedHeaders();
|
|
169
195
|
}
|
|
170
|
-
if (!Reflect.get(request, originPathnameSymbol)) {
|
|
196
|
+
if (!Reflect.get(this.request, originPathnameSymbol)) {
|
|
171
197
|
setOriginPathname(
|
|
172
|
-
request,
|
|
198
|
+
this.request,
|
|
173
199
|
this.pathname,
|
|
174
200
|
pipeline.manifest.trailingSlash,
|
|
175
201
|
pipeline.manifest.buildFormat
|
|
@@ -462,7 +488,9 @@ class FetchState {
|
|
|
462
488
|
}
|
|
463
489
|
} else {
|
|
464
490
|
let pathname = routeData.pathname;
|
|
465
|
-
if (
|
|
491
|
+
if (this.#domainPathname) {
|
|
492
|
+
pathname = this.pathname;
|
|
493
|
+
} else if (url && !routeData.pattern.test(url.pathname)) {
|
|
466
494
|
for (const fallbackRoute of routeData.fallbackRoutes) {
|
|
467
495
|
if (fallbackRoute.pattern.test(url.pathname)) {
|
|
468
496
|
pathname = fallbackRoute.pathname;
|
|
@@ -589,11 +617,14 @@ class FetchState {
|
|
|
589
617
|
*/
|
|
590
618
|
/**
|
|
591
619
|
* Strip `.html` / `/index.html` suffixes from the pathname so the
|
|
592
|
-
* rendering pipeline sees the canonical route path.
|
|
593
|
-
*
|
|
620
|
+
* rendering pipeline sees the canonical route path. Only applies to
|
|
621
|
+
* page routes where `.html` is framework-injected. Endpoint routes
|
|
622
|
+
* preserve `.html` because any such suffix is user-provided (e.g.
|
|
623
|
+
* from `getStaticPaths` params). Skipped when the matched route
|
|
624
|
+
* itself has an `.html` extension in its definition.
|
|
594
625
|
*/
|
|
595
626
|
#stripHtmlExtension() {
|
|
596
|
-
if (this.routeData && !routeHasHtmlExtension(this.routeData)) {
|
|
627
|
+
if (this.routeData && this.routeData.type === "page" && !routeHasHtmlExtension(this.routeData)) {
|
|
597
628
|
this.pathname = this.pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
|
|
598
629
|
}
|
|
599
630
|
}
|
|
@@ -697,6 +728,12 @@ class FetchState {
|
|
|
697
728
|
this.clientAddress = forwardedFor;
|
|
698
729
|
}
|
|
699
730
|
}
|
|
731
|
+
const oldRequest = this.request;
|
|
732
|
+
this.request = new Request(this.url, oldRequest);
|
|
733
|
+
const app = Reflect.get(oldRequest, appSymbol);
|
|
734
|
+
if (app !== void 0) {
|
|
735
|
+
Reflect.set(this.request, appSymbol, app);
|
|
736
|
+
}
|
|
700
737
|
}
|
|
701
738
|
/**
|
|
702
739
|
* Returns the resolved `props` for this render, computing them lazily
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SSRManifest } from '../app/types.js';
|
|
2
|
+
import type { AstroLogger } from '../logger/core.js';
|
|
3
|
+
/**
|
|
4
|
+
* For domain-based i18n routing strategies, derives the locale-prefixed
|
|
5
|
+
* pathname from the request's `Host` header rather than its URL. For example,
|
|
6
|
+
* a request for `/foo` served from `https://example.fr` resolves to `/fr/foo`.
|
|
7
|
+
*
|
|
8
|
+
* Returns `undefined` when the strategy isn't domain-based or the host isn't
|
|
9
|
+
* mapped to a locale — in which case normal pathname routing applies.
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
export declare function computePathnameFromDomain(request: Request, url: URL, i18n: SSRManifest['i18n'], base: SSRManifest['base'], trailingSlash: SSRManifest['trailingSlash'], logger: AstroLogger): string | undefined;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendForwardSlash,
|
|
3
|
+
collapseDuplicateLeadingSlashes,
|
|
4
|
+
joinPaths,
|
|
5
|
+
prependForwardSlash,
|
|
6
|
+
removeTrailingForwardSlash
|
|
7
|
+
} from "@astrojs/internal-helpers/path";
|
|
8
|
+
import { normalizeTheLocale } from "../../i18n/index.js";
|
|
9
|
+
function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logger) {
|
|
10
|
+
let pathname = void 0;
|
|
11
|
+
if (i18n && (i18n.strategy === "domains-prefix-always" || i18n.strategy === "domains-prefix-other-locales" || i18n.strategy === "domains-prefix-always-no-redirect")) {
|
|
12
|
+
let host = request.headers.get("X-Forwarded-Host");
|
|
13
|
+
let protocol = request.headers.get("X-Forwarded-Proto");
|
|
14
|
+
if (protocol) {
|
|
15
|
+
protocol = protocol + ":";
|
|
16
|
+
} else {
|
|
17
|
+
protocol = url.protocol;
|
|
18
|
+
}
|
|
19
|
+
if (!host) {
|
|
20
|
+
host = request.headers.get("Host");
|
|
21
|
+
}
|
|
22
|
+
if (host && protocol) {
|
|
23
|
+
host = host.split(":")[0];
|
|
24
|
+
try {
|
|
25
|
+
let locale;
|
|
26
|
+
const hostAsUrl = new URL(`${protocol}//${host}`);
|
|
27
|
+
for (const [domainKey, localeValue] of Object.entries(i18n.domainLookupTable)) {
|
|
28
|
+
const domainKeyAsUrl = new URL(domainKey);
|
|
29
|
+
if (hostAsUrl.host === domainKeyAsUrl.host && hostAsUrl.protocol === domainKeyAsUrl.protocol) {
|
|
30
|
+
locale = localeValue;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (locale) {
|
|
35
|
+
pathname = prependForwardSlash(
|
|
36
|
+
joinPaths(normalizeTheLocale(locale), removeBase(url.pathname, base))
|
|
37
|
+
);
|
|
38
|
+
if (trailingSlash === "always") {
|
|
39
|
+
pathname = appendForwardSlash(pathname);
|
|
40
|
+
} else if (trailingSlash === "never") {
|
|
41
|
+
pathname = removeTrailingForwardSlash(pathname);
|
|
42
|
+
} else if (url.pathname.endsWith("/")) {
|
|
43
|
+
pathname = appendForwardSlash(pathname);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch (e) {
|
|
47
|
+
logger.error(
|
|
48
|
+
"router",
|
|
49
|
+
`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.`
|
|
50
|
+
);
|
|
51
|
+
logger.error("router", `Error: ${e}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return pathname;
|
|
56
|
+
}
|
|
57
|
+
function removeBase(pathname, base) {
|
|
58
|
+
pathname = collapseDuplicateLeadingSlashes(pathname);
|
|
59
|
+
if (pathname.startsWith(base)) {
|
|
60
|
+
return pathname.slice(removeTrailingForwardSlash(base).length + 1);
|
|
61
|
+
}
|
|
62
|
+
return pathname;
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
computePathnameFromDomain
|
|
66
|
+
};
|
package/dist/core/logger/core.js
CHANGED
|
@@ -136,7 +136,7 @@ class AstroLogger {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
139
|
-
* It calls the `flush` function of the provided
|
|
139
|
+
* It calls the `flush` function of the provided destination, if it exists.
|
|
140
140
|
*/
|
|
141
141
|
flush() {
|
|
142
142
|
if (this.options.destination.flush) {
|
|
@@ -677,7 +677,7 @@ function joinSegments(segments) {
|
|
|
677
677
|
const arr = segments.map((segment) => {
|
|
678
678
|
return segment.map((rp) => rp.dynamic ? `[${rp.content}]` : rp.content).join("");
|
|
679
679
|
});
|
|
680
|
-
return `/${arr.join("/")}
|
|
680
|
+
return `/${arr.join("/")}`;
|
|
681
681
|
}
|
|
682
682
|
function replaceOrKeep(original, from, to) {
|
|
683
683
|
if (original.startsWith(`/${to}/`) || original === `/${to}`) return original;
|
|
@@ -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
|
|
@@ -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
|
});
|
|
@@ -52,11 +52,7 @@ function renderAllHeadContent(result) {
|
|
|
52
52
|
(link) => renderElement("link", link, false)
|
|
53
53
|
);
|
|
54
54
|
content += styles.join("\n") + links.join("\n") + scripts.join("\n");
|
|
55
|
-
|
|
56
|
-
for (const part of result._metadata.extraHead) {
|
|
57
|
-
content += part;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
55
|
+
content += result._metadata.extraHead.join("");
|
|
60
56
|
return markHTMLString(content);
|
|
61
57
|
}
|
|
62
58
|
function renderHead() {
|
|
@@ -26,12 +26,18 @@ function normalizeFilename(filename, root) {
|
|
|
26
26
|
} else if (filename.startsWith(".")) {
|
|
27
27
|
const url = new URL(filename, root);
|
|
28
28
|
filename = viteID(url);
|
|
29
|
-
} else if (filename.startsWith("/") && !
|
|
29
|
+
} else if (filename.startsWith("/") && !isPathInRoot(filename, fileURLToPath(root))) {
|
|
30
30
|
const url = new URL("." + filename, root);
|
|
31
31
|
filename = viteID(url);
|
|
32
32
|
}
|
|
33
33
|
return removeLeadingForwardSlashWindows(filename);
|
|
34
34
|
}
|
|
35
|
+
function isPathInRoot(filename, rootPath) {
|
|
36
|
+
if (commonAncestorPath(filename, rootPath)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return commonAncestorPath(filename.toLowerCase(), rootPath.toLowerCase()) !== "";
|
|
40
|
+
}
|
|
35
41
|
const postfixRE = /[?#].*$/s;
|
|
36
42
|
function cleanUrl(url) {
|
|
37
43
|
return url.replace(postfixRE, "");
|