astro 7.0.1 → 7.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/vite-plugin-actions.d.ts +1 -1
- package/dist/actions/vite-plugin-actions.js +27 -1
- 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 +1 -1
- package/dist/core/app/base.js +9 -2
- package/dist/core/app/dev/app.d.ts +5 -0
- package/dist/core/app/dev/app.js +7 -0
- package/dist/core/app/dev/pipeline.d.ts +1 -0
- package/dist/core/app/dev/pipeline.js +4 -0
- package/dist/core/app/entrypoints/virtual/dev.js +4 -0
- package/dist/core/build/generate.js +1 -1
- package/dist/core/build/plugins/plugin-manifest.js +1 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/default-handler.js +14 -3
- package/dist/core/i18n/domain.js +1 -1
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/output-filename.d.ts +3 -0
- package/dist/core/output-filename.js +20 -0
- package/dist/core/routing/dev.js +15 -2
- package/dist/core/util.d.ts +0 -7
- package/dist/core/util.js +1 -19
- package/dist/i18n/error-routes.d.ts +4 -0
- package/dist/i18n/error-routes.js +26 -0
- package/dist/i18n/index.d.ts +0 -14
- package/dist/i18n/index.js +1 -24
- package/dist/i18n/path.d.ts +15 -0
- package/dist/i18n/path.js +26 -0
- package/dist/i18n/router.js +1 -1
- package/dist/i18n/utils.js +2 -1
- package/dist/runtime/server/render/page.js +3 -2
- package/dist/virtual-modules/i18n.d.ts +2 -1
- package/dist/virtual-modules/i18n.js +6 -2
- package/dist/vite-plugin-app/app.d.ts +5 -0
- package/dist/vite-plugin-app/app.js +21 -1
- package/dist/vite-plugin-app/createAstroServerApp.js +4 -0
- package/dist/vite-plugin-app/pipeline.d.ts +1 -0
- package/dist/vite-plugin-app/pipeline.js +4 -0
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type fsMod from 'node:fs';
|
|
2
|
-
import type
|
|
2
|
+
import { type Plugin as VitePlugin } from 'vite';
|
|
3
3
|
import type { BuildInternals } from '../core/build/internal.js';
|
|
4
4
|
import type { StaticBuildOptions } from '../core/build/types.js';
|
|
5
5
|
import type { AstroSettings } from '../types/astro.js';
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import {
|
|
3
|
+
normalizePath as viteNormalizePath
|
|
4
|
+
} from "vite";
|
|
1
5
|
import { shouldAppendForwardSlash } from "../core/build/util.js";
|
|
2
6
|
import { getServerOutputDirectory } from "../prerender/utils.js";
|
|
3
7
|
import {
|
|
@@ -27,11 +31,13 @@ function vitePluginActionsBuild(opts, internals) {
|
|
|
27
31
|
}
|
|
28
32
|
};
|
|
29
33
|
}
|
|
34
|
+
const ACTIONS_DIR_NAME = "actions";
|
|
30
35
|
function vitePluginActions({
|
|
31
36
|
fs,
|
|
32
37
|
settings
|
|
33
38
|
}) {
|
|
34
39
|
let resolvedActionsId;
|
|
40
|
+
const normalizedSrcDir = viteNormalizePath(fileURLToPath(settings.config.srcDir));
|
|
35
41
|
return {
|
|
36
42
|
name: VIRTUAL_MODULE_ID,
|
|
37
43
|
enforce: "pre",
|
|
@@ -69,7 +75,27 @@ function vitePluginActions({
|
|
|
69
75
|
}
|
|
70
76
|
}
|
|
71
77
|
server.watcher.on("add", watcherCallback);
|
|
72
|
-
server.watcher.on("change",
|
|
78
|
+
server.watcher.on("change", (path) => {
|
|
79
|
+
watcherCallback();
|
|
80
|
+
const normalizedPath = viteNormalizePath(path);
|
|
81
|
+
if (!normalizedPath.startsWith(normalizedSrcDir)) return;
|
|
82
|
+
const relativePath = normalizedPath.slice(normalizedSrcDir.length);
|
|
83
|
+
if (!relativePath.startsWith(`${ACTIONS_DIR_NAME}/`)) return;
|
|
84
|
+
for (const name of [
|
|
85
|
+
ASTRO_VITE_ENVIRONMENT_NAMES.ssr,
|
|
86
|
+
ASTRO_VITE_ENVIRONMENT_NAMES.astro
|
|
87
|
+
]) {
|
|
88
|
+
const environment = server.environments[name];
|
|
89
|
+
if (!environment) continue;
|
|
90
|
+
const virtualMod = environment.moduleGraph.getModuleById(
|
|
91
|
+
ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID
|
|
92
|
+
);
|
|
93
|
+
if (virtualMod) {
|
|
94
|
+
environment.moduleGraph.invalidateModule(virtualMod);
|
|
95
|
+
}
|
|
96
|
+
environment.hot.send("astro:actions-updated", {});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
73
99
|
},
|
|
74
100
|
load: {
|
|
75
101
|
filter: {
|
|
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Content config changed");
|
|
198
198
|
shouldClear = true;
|
|
199
199
|
}
|
|
200
|
-
if (previousAstroVersion && previousAstroVersion !== "7.0.
|
|
200
|
+
if (previousAstroVersion && previousAstroVersion !== "7.0.3") {
|
|
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 ("7.0.
|
|
209
|
-
this.#store.metaStore().set("astro-version", "7.0.
|
|
208
|
+
if ("7.0.3") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "7.0.3");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
package/dist/core/app/base.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ export interface RenderErrorOptions extends ResolvedRenderOptions {
|
|
|
86
86
|
*/
|
|
87
87
|
pathname?: string;
|
|
88
88
|
}
|
|
89
|
-
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
|
|
89
|
+
type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}/404/index.html` | `${string}/500/index.html` | `${string}404.html` | `${string}500.html`;
|
|
90
90
|
export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
|
|
91
91
|
#private;
|
|
92
92
|
manifest: SSRManifest;
|
package/dist/core/app/base.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "@astrojs/internal-helpers/path";
|
|
6
6
|
import { matchPattern } from "@astrojs/internal-helpers/remote";
|
|
7
7
|
import { computePathnameFromDomain } from "../i18n/domain.js";
|
|
8
|
+
import { isLocalizedErrorRoute } from "../../i18n/error-routes.js";
|
|
8
9
|
import { PipelineFeatures } from "../base-pipeline.js";
|
|
9
10
|
import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
|
|
10
11
|
import { getSetCookiesFromResponse } from "../cookies/index.js";
|
|
@@ -13,6 +14,7 @@ import { AstroIntegrationLogger } from "../logger/core.js";
|
|
|
13
14
|
import { DefaultFetchHandler } from "../fetch/default-handler.js";
|
|
14
15
|
import { appSymbol } from "../constants.js";
|
|
15
16
|
import { DefaultErrorHandler } from "../errors/default-handler.js";
|
|
17
|
+
import { isRoute404, isRoute500 } from "../routing/internal/route-errors.js";
|
|
16
18
|
import { setRenderOptions } from "./render-options.js";
|
|
17
19
|
class BaseApp {
|
|
18
20
|
manifest;
|
|
@@ -332,8 +334,13 @@ class BaseApp {
|
|
|
332
334
|
}
|
|
333
335
|
}
|
|
334
336
|
const route = removeTrailingForwardSlash(routeData.route);
|
|
335
|
-
|
|
336
|
-
if (route
|
|
337
|
+
const locales = this.manifest.i18n?.locales;
|
|
338
|
+
if (isRoute404(route) || isLocalizedErrorRoute(route, 404, locales)) {
|
|
339
|
+
return 404;
|
|
340
|
+
}
|
|
341
|
+
if (isRoute500(route) || isLocalizedErrorRoute(route, 500, locales)) {
|
|
342
|
+
return 500;
|
|
343
|
+
}
|
|
337
344
|
return 200;
|
|
338
345
|
}
|
|
339
346
|
getManifest() {
|
|
@@ -14,6 +14,11 @@ export declare class DevApp extends BaseApp<NonRunnablePipeline> {
|
|
|
14
14
|
* Called via HMR when middleware files change.
|
|
15
15
|
*/
|
|
16
16
|
clearMiddleware(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Clears the cached actions so they are re-resolved on the next request.
|
|
19
|
+
* Called via HMR when action files change.
|
|
20
|
+
*/
|
|
21
|
+
clearActions(): void;
|
|
17
22
|
/**
|
|
18
23
|
* Updates the routes list when files change during development.
|
|
19
24
|
* Called via HMR when new pages are added/removed.
|
package/dist/core/app/dev/app.js
CHANGED
|
@@ -25,6 +25,13 @@ class DevApp extends BaseApp {
|
|
|
25
25
|
clearMiddleware() {
|
|
26
26
|
this.pipeline.clearMiddleware();
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Clears the cached actions so they are re-resolved on the next request.
|
|
30
|
+
* Called via HMR when action files change.
|
|
31
|
+
*/
|
|
32
|
+
clearActions() {
|
|
33
|
+
this.pipeline.clearActions();
|
|
34
|
+
}
|
|
28
35
|
/**
|
|
29
36
|
* Updates the routes list when files change during development.
|
|
30
37
|
* Called via HMR when new pages are added/removed.
|
|
@@ -9,6 +9,7 @@ export declare class NonRunnablePipeline extends Pipeline {
|
|
|
9
9
|
getName(): string;
|
|
10
10
|
static create({ logger, manifest, streaming }: DevPipelineCreate): NonRunnablePipeline;
|
|
11
11
|
headElements(routeData: RouteData): Promise<HeadElements>;
|
|
12
|
+
clearActions(): void;
|
|
12
13
|
componentMetadata(): void;
|
|
13
14
|
getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
|
14
15
|
tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
|
|
@@ -94,6 +94,10 @@ class NonRunnablePipeline extends Pipeline {
|
|
|
94
94
|
}
|
|
95
95
|
return { scripts, styles, links };
|
|
96
96
|
}
|
|
97
|
+
// Called via HMR when action files change. Not available on production environment.
|
|
98
|
+
clearActions() {
|
|
99
|
+
this.resolvedActions = void 0;
|
|
100
|
+
}
|
|
97
101
|
componentMetadata() {
|
|
98
102
|
}
|
|
99
103
|
async getComponentByRoute(routeData) {
|
|
@@ -29,6 +29,10 @@ const createApp = ({ streaming } = {}) => {
|
|
|
29
29
|
if (!currentDevApp) return;
|
|
30
30
|
currentDevApp.clearMiddleware();
|
|
31
31
|
});
|
|
32
|
+
import.meta.hot.on("astro:actions-updated", () => {
|
|
33
|
+
if (!currentDevApp) return;
|
|
34
|
+
currentDevApp.clearActions();
|
|
35
|
+
});
|
|
32
36
|
}
|
|
33
37
|
return currentDevApp;
|
|
34
38
|
};
|
|
@@ -24,7 +24,7 @@ import { createRequest } from "../request.js";
|
|
|
24
24
|
import { redirectTemplate } from "../routing/3xx.js";
|
|
25
25
|
import { routeIsRedirect } from "../routing/helpers.js";
|
|
26
26
|
import { matchRoute } from "../routing/match.js";
|
|
27
|
-
import { getOutputFilename } from "../
|
|
27
|
+
import { getOutputFilename } from "../output-filename.js";
|
|
28
28
|
import { getOutFile, getOutFolder } from "./common.js";
|
|
29
29
|
import { createDefaultPrerenderer } from "./default-prerenderer.js";
|
|
30
30
|
import { hasPrerenderedPages } from "./internal.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { glob } from "tinyglobby";
|
|
3
3
|
import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
|
|
4
|
-
import { normalizeTheLocale } from "../../../i18n/
|
|
4
|
+
import { normalizeTheLocale } from "../../../i18n/path.js";
|
|
5
5
|
import { resolveMiddlewareMode } from "../../../integrations/adapter-utils.js";
|
|
6
6
|
import { runHookBuildSsr } from "../../../integrations/hooks.js";
|
|
7
7
|
import { SERIALIZED_MANIFEST_RESOLVED_ID } from "../../../manifest/serialized.js";
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
|
|
|
26
26
|
await telemetry.record([]);
|
|
27
27
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
28
28
|
const logger = restart.container.logger;
|
|
29
|
-
const currentVersion = "7.0.
|
|
29
|
+
const currentVersion = "7.0.3";
|
|
30
30
|
const isPrerelease = currentVersion.includes("-");
|
|
31
31
|
if (!isPrerelease) {
|
|
32
32
|
try {
|
|
@@ -7,6 +7,8 @@ import { PagesHandler } from "../pages/handler.js";
|
|
|
7
7
|
import { matchRoute } from "../routing/match.js";
|
|
8
8
|
import { provideSession } from "../session/handler.js";
|
|
9
9
|
import { validateHost } from "../app/validate-headers.js";
|
|
10
|
+
import { getErrorRoutePath } from "../../i18n/error-routes.js";
|
|
11
|
+
import { getOutputFilename } from "../output-filename.js";
|
|
10
12
|
class DefaultErrorHandler {
|
|
11
13
|
#app;
|
|
12
14
|
#astroMiddleware;
|
|
@@ -26,17 +28,26 @@ class DefaultErrorHandler {
|
|
|
26
28
|
}) {
|
|
27
29
|
const app = this.#app;
|
|
28
30
|
const resolvedPathname = pathname ?? new FetchState(app.pipeline, request).pathname;
|
|
29
|
-
const errorRoutePath =
|
|
31
|
+
const errorRoutePath = getErrorRoutePath(
|
|
32
|
+
resolvedPathname,
|
|
33
|
+
status,
|
|
34
|
+
app.manifestData.routes,
|
|
35
|
+
app.manifest.i18n?.locales,
|
|
36
|
+
app.manifest.trailingSlash === "always"
|
|
37
|
+
);
|
|
30
38
|
const errorRouteData = matchRoute(errorRoutePath, app.manifestData);
|
|
31
39
|
const url = new URL(request.url);
|
|
32
40
|
if (errorRouteData) {
|
|
33
41
|
if (errorRouteData.prerender) {
|
|
34
|
-
const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : "";
|
|
35
42
|
const allowedDomains = app.manifest.allowedDomains;
|
|
36
43
|
const validatedHost = validateHost(url.host, url.protocol.replace(":", ""), allowedDomains);
|
|
37
44
|
const safeOrigin = validatedHost ? url.origin : `${url.protocol}//localhost`;
|
|
38
45
|
const statusURL = new URL(
|
|
39
|
-
`${app.baseWithoutTrailingSlash}
|
|
46
|
+
`${app.baseWithoutTrailingSlash}${getOutputFilename(
|
|
47
|
+
app.manifest.buildFormat,
|
|
48
|
+
errorRouteData.route,
|
|
49
|
+
errorRouteData
|
|
50
|
+
)}`,
|
|
40
51
|
safeOrigin
|
|
41
52
|
);
|
|
42
53
|
if (statusURL.toString() !== request.url && resolvedRenderOptions.prerenderedErrorPageFetch) {
|
package/dist/core/i18n/domain.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
prependForwardSlash,
|
|
6
6
|
removeTrailingForwardSlash
|
|
7
7
|
} from "@astrojs/internal-helpers/path";
|
|
8
|
-
import { normalizeTheLocale } from "../../i18n/
|
|
8
|
+
import { normalizeTheLocale } from "../../i18n/path.js";
|
|
9
9
|
function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logger) {
|
|
10
10
|
let pathname = void 0;
|
|
11
11
|
if (i18n && (i18n.strategy === "domains-prefix-always" || i18n.strategy === "domains-prefix-other-locales" || i18n.strategy === "domains-prefix-always-no-redirect")) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { removeTrailingForwardSlash } from "./path.js";
|
|
2
|
+
const STATUS_CODE_PAGES = /* @__PURE__ */ new Set(["/404", "/500"]);
|
|
3
|
+
function getOutputFilename(buildFormat, name, routeData) {
|
|
4
|
+
if (routeData.type === "endpoint") {
|
|
5
|
+
return name;
|
|
6
|
+
}
|
|
7
|
+
if (name === "/" || name === "") {
|
|
8
|
+
return name === "" ? "index.html" : "/index.html";
|
|
9
|
+
}
|
|
10
|
+
if (buildFormat === "file" || STATUS_CODE_PAGES.has(name)) {
|
|
11
|
+
return `${removeTrailingForwardSlash(name || "index")}.html`;
|
|
12
|
+
}
|
|
13
|
+
if (buildFormat === "preserve" && !routeData.isIndex) {
|
|
14
|
+
return `${removeTrailingForwardSlash(name || "index")}.html`;
|
|
15
|
+
}
|
|
16
|
+
return `${removeTrailingForwardSlash(name)}/index.html`;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
getOutputFilename
|
|
20
|
+
};
|
package/dist/core/routing/dev.js
CHANGED
|
@@ -4,6 +4,7 @@ import { getProps } from "../render/index.js";
|
|
|
4
4
|
import { getCustom404Route } from "./helpers.js";
|
|
5
5
|
import { NoMatchingStaticPathFound } from "../errors/errors-data.js";
|
|
6
6
|
import { isAstroError } from "../errors/errors.js";
|
|
7
|
+
import { getErrorRoutePath } from "../../i18n/error-routes.js";
|
|
7
8
|
async function matchRoute(pathname, routesList, pipeline, manifest) {
|
|
8
9
|
const { logger, routeCache } = pipeline;
|
|
9
10
|
const matches = matchAllRoutes(pathname, routesList);
|
|
@@ -11,6 +12,7 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
|
|
|
11
12
|
matches,
|
|
12
13
|
manifest
|
|
13
14
|
});
|
|
15
|
+
let firstError = null;
|
|
14
16
|
for await (const { route: maybeRoute, filePath } of preloadedMatches) {
|
|
15
17
|
try {
|
|
16
18
|
await getProps({
|
|
@@ -32,9 +34,13 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
|
|
|
32
34
|
if (isAstroError(e) && e.title === NoMatchingStaticPathFound.title) {
|
|
33
35
|
continue;
|
|
34
36
|
}
|
|
35
|
-
|
|
37
|
+
firstError ??= e;
|
|
38
|
+
continue;
|
|
36
39
|
}
|
|
37
40
|
}
|
|
41
|
+
if (firstError) {
|
|
42
|
+
throw firstError;
|
|
43
|
+
}
|
|
38
44
|
const altPathname = pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
|
|
39
45
|
if (altPathname !== pathname) {
|
|
40
46
|
return await matchRoute(altPathname, routesList, pipeline, manifest);
|
|
@@ -50,7 +56,14 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
|
|
|
50
56
|
${NoMatchingStaticPathFound.hint(possibleRoutes)}`
|
|
51
57
|
);
|
|
52
58
|
}
|
|
53
|
-
const
|
|
59
|
+
const errorRoutePath = getErrorRoutePath(
|
|
60
|
+
pathname,
|
|
61
|
+
404,
|
|
62
|
+
routesList.routes,
|
|
63
|
+
manifest.i18n?.locales,
|
|
64
|
+
manifest.trailingSlash === "always"
|
|
65
|
+
);
|
|
66
|
+
const custom404 = routesList.routes.find((route) => route.route === errorRoutePath) ?? getCustom404Route(routesList);
|
|
54
67
|
if (custom404) {
|
|
55
68
|
const filePath = new URL(`./${custom404.component}`, manifest.rootDir);
|
|
56
69
|
return {
|
package/dist/core/util.d.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import type { AstroSettings } from '../types/astro.js';
|
|
2
2
|
import type { AstroConfig } from '../types/public/config.js';
|
|
3
|
-
import type { RouteData } from '../types/public/internal.js';
|
|
4
3
|
/** Check if a file is a markdown file based on its extension */
|
|
5
4
|
export declare function isMarkdownFile(fileId: string, option?: {
|
|
6
5
|
suffix?: string;
|
|
7
6
|
}): boolean;
|
|
8
|
-
/**
|
|
9
|
-
* Get the correct output filename for a route, based on your config.
|
|
10
|
-
* Handles both "/foo" and "foo" `name` formats.
|
|
11
|
-
* Handles `/404` and `/` correctly.
|
|
12
|
-
*/
|
|
13
|
-
export declare function getOutputFilename(buildFormat: NonNullable<AstroConfig['build']>['format'], name: string, routeData: RouteData): string;
|
|
14
7
|
/** is a specifier an npm package? */
|
|
15
8
|
export declare function parseNpmName(spec: string): {
|
|
16
9
|
scope?: string;
|
package/dist/core/util.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
4
3
|
import { hasSpecialQueries } from "../vite-plugin-utils/index.js";
|
|
5
4
|
import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from "./constants.js";
|
|
6
|
-
import { removeQueryString,
|
|
5
|
+
import { removeQueryString, slash } from "./path.js";
|
|
7
6
|
function isMarkdownFile(fileId, option) {
|
|
8
7
|
if (hasSpecialQueries(fileId)) {
|
|
9
8
|
return false;
|
|
@@ -15,22 +14,6 @@ function isMarkdownFile(fileId, option) {
|
|
|
15
14
|
}
|
|
16
15
|
return false;
|
|
17
16
|
}
|
|
18
|
-
const STATUS_CODE_PAGES = /* @__PURE__ */ new Set(["/404", "/500"]);
|
|
19
|
-
function getOutputFilename(buildFormat, name, routeData) {
|
|
20
|
-
if (routeData.type === "endpoint") {
|
|
21
|
-
return name;
|
|
22
|
-
}
|
|
23
|
-
if (name === "/" || name === "") {
|
|
24
|
-
return path.posix.join(name, "index.html");
|
|
25
|
-
}
|
|
26
|
-
if (buildFormat === "file" || STATUS_CODE_PAGES.has(name)) {
|
|
27
|
-
return `${removeTrailingForwardSlash(name || "index")}.html`;
|
|
28
|
-
}
|
|
29
|
-
if (buildFormat === "preserve" && !routeData.isIndex) {
|
|
30
|
-
return `${removeTrailingForwardSlash(name || "index")}.html`;
|
|
31
|
-
}
|
|
32
|
-
return path.posix.join(name, "index.html");
|
|
33
|
-
}
|
|
34
17
|
function parseNpmName(spec) {
|
|
35
18
|
if (!spec || spec[0] === "." || spec[0] === "/") return void 0;
|
|
36
19
|
let scope;
|
|
@@ -119,7 +102,6 @@ function ensureProcessNodeEnv(defaultNodeEnv) {
|
|
|
119
102
|
export {
|
|
120
103
|
VALID_ID_PREFIX,
|
|
121
104
|
ensureProcessNodeEnv,
|
|
122
|
-
getOutputFilename,
|
|
123
105
|
isEndpoint,
|
|
124
106
|
isMarkdownFile,
|
|
125
107
|
isPage,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SSRManifest } from '../core/app/types.js';
|
|
2
|
+
import type { Locales } from '../types/public/config.js';
|
|
3
|
+
export declare function isLocalizedErrorRoute(route: string, status: 404 | 500, locales: Locales | undefined): boolean;
|
|
4
|
+
export declare function getErrorRoutePath(pathname: string, status: 404 | 500, routes: Pick<SSRManifest['routes'][number]['routeData'], 'route'>[], locales: Locales | undefined, appendTrailingSlash?: boolean): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { pathHasLocale } from "./path.js";
|
|
2
|
+
function isLocalizedErrorRoute(route, status, locales) {
|
|
3
|
+
if (!locales) return false;
|
|
4
|
+
const suffix = `/${status}`;
|
|
5
|
+
if (!route.endsWith(suffix)) return false;
|
|
6
|
+
const localeSegment = route.slice(0, -suffix.length);
|
|
7
|
+
if (!localeSegment || localeSegment.includes("/", 1)) return false;
|
|
8
|
+
return pathHasLocale(localeSegment, locales);
|
|
9
|
+
}
|
|
10
|
+
function getErrorRoutePath(pathname, status, routes, locales, appendTrailingSlash = false) {
|
|
11
|
+
const suffix = appendTrailingSlash ? "/" : "";
|
|
12
|
+
if (locales) {
|
|
13
|
+
const firstSegment = pathname.split("/").find(Boolean);
|
|
14
|
+
if (firstSegment && pathHasLocale(`/${firstSegment}`, locales)) {
|
|
15
|
+
const localized = `/${firstSegment}/${status}`;
|
|
16
|
+
if (routes.some((route) => route.route === localized)) {
|
|
17
|
+
return `${localized}${suffix}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return `/${status}${suffix}`;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
getErrorRoutePath,
|
|
25
|
+
isLocalizedErrorRoute
|
|
26
|
+
};
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type { SSRManifest } from '../core/app/types.js';
|
|
|
3
3
|
import type { AstroConfig, Locales, ValidRedirectStatus } from '../types/public/config.js';
|
|
4
4
|
import type { APIContext } from '../types/public/context.js';
|
|
5
5
|
export declare function requestHasLocale(locales: Locales): (context: APIContext) => boolean;
|
|
6
|
-
export declare function pathHasLocale(path: string, locales: Locales): boolean;
|
|
7
6
|
type GetLocaleRelativeUrl = GetLocaleOptions & {
|
|
8
7
|
locale: string;
|
|
9
8
|
base: string;
|
|
@@ -67,19 +66,6 @@ export declare function getPathByLocale(locale: string, locales: Locales): strin
|
|
|
67
66
|
* @param locales
|
|
68
67
|
*/
|
|
69
68
|
export declare function getLocaleByPath(path: string, locales: Locales): string;
|
|
70
|
-
/**
|
|
71
|
-
*
|
|
72
|
-
* Given a locale, this function:
|
|
73
|
-
* - replaces the `_` with a `-`;
|
|
74
|
-
* - transforms all letters to be lowercase;
|
|
75
|
-
*/
|
|
76
|
-
export declare function normalizeTheLocale(locale: string): string;
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
* Given a path or path segment, this function:
|
|
80
|
-
* - removes the `.html` extension if it exists
|
|
81
|
-
*/
|
|
82
|
-
export declare function normalizeThePath(path: string): string;
|
|
83
69
|
/**
|
|
84
70
|
* Returns an array of only locales, by picking the `code`
|
|
85
71
|
* @param locales
|
package/dist/i18n/index.js
CHANGED
|
@@ -8,26 +8,12 @@ import { getFetchStateFromAPIContext } from "../core/fetch/fetch-state.js";
|
|
|
8
8
|
import { i18nNoLocaleFoundInPath, MissingLocale } from "../core/errors/errors-data.js";
|
|
9
9
|
import { AstroError } from "../core/errors/index.js";
|
|
10
10
|
import { createI18nMiddleware } from "./middleware.js";
|
|
11
|
+
import { normalizeTheLocale, pathHasLocale } from "./path.js";
|
|
11
12
|
function requestHasLocale(locales) {
|
|
12
13
|
return function(context) {
|
|
13
14
|
return pathHasLocale(context.url.pathname, locales);
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
|
-
function pathHasLocale(path, locales) {
|
|
17
|
-
const segments = path.split("/").map(normalizeThePath);
|
|
18
|
-
for (const segment of segments) {
|
|
19
|
-
for (const locale of locales) {
|
|
20
|
-
if (typeof locale === "string") {
|
|
21
|
-
if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
} else if (segment === locale.path) {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
17
|
function getLocaleRelativeUrl({
|
|
32
18
|
locale,
|
|
33
19
|
base,
|
|
@@ -133,12 +119,6 @@ function getLocaleByPath(path, locales) {
|
|
|
133
119
|
}
|
|
134
120
|
throw new AstroError(i18nNoLocaleFoundInPath);
|
|
135
121
|
}
|
|
136
|
-
function normalizeTheLocale(locale) {
|
|
137
|
-
return locale.replaceAll("_", "-").toLowerCase();
|
|
138
|
-
}
|
|
139
|
-
function normalizeThePath(path) {
|
|
140
|
-
return path.endsWith(".html") ? path.slice(0, -5) : path;
|
|
141
|
-
}
|
|
142
122
|
function getAllCodes(locales) {
|
|
143
123
|
const result = [];
|
|
144
124
|
for (const loopLocale of locales) {
|
|
@@ -281,10 +261,7 @@ export {
|
|
|
281
261
|
getLocaleRelativeUrl,
|
|
282
262
|
getLocaleRelativeUrlList,
|
|
283
263
|
getPathByLocale,
|
|
284
|
-
normalizeTheLocale,
|
|
285
|
-
normalizeThePath,
|
|
286
264
|
notFound,
|
|
287
|
-
pathHasLocale,
|
|
288
265
|
redirectToDefaultLocale,
|
|
289
266
|
redirectToFallback,
|
|
290
267
|
requestHasLocale,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Locales } from '../types/public/config.js';
|
|
2
|
+
export declare function pathHasLocale(path: string, locales: Locales): boolean;
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Given a locale, this function:
|
|
6
|
+
* - replaces the `_` with a `-`;
|
|
7
|
+
* - transforms all letters to be lowercase;
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeTheLocale(locale: string): string;
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* Given a path or path segment, this function:
|
|
13
|
+
* - removes the `.html` extension if it exists
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalizeThePath(path: string): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function pathHasLocale(path, locales) {
|
|
2
|
+
const segments = path.split("/").map(normalizeThePath);
|
|
3
|
+
for (const segment of segments) {
|
|
4
|
+
for (const locale of locales) {
|
|
5
|
+
if (typeof locale === "string") {
|
|
6
|
+
if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
} else if (segment === locale.path) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
function normalizeTheLocale(locale) {
|
|
17
|
+
return locale.replaceAll("_", "-").toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
function normalizeThePath(path) {
|
|
20
|
+
return path.endsWith(".html") ? path.slice(0, -5) : path;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
normalizeTheLocale,
|
|
24
|
+
normalizeThePath,
|
|
25
|
+
pathHasLocale
|
|
26
|
+
};
|
package/dist/i18n/router.js
CHANGED
package/dist/i18n/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getAllCodes
|
|
1
|
+
import { getAllCodes } from "./index.js";
|
|
2
|
+
import { normalizeTheLocale, normalizeThePath } from "./path.js";
|
|
2
3
|
function parseLocale(header) {
|
|
3
4
|
if (header === "*") {
|
|
4
5
|
return [{ locale: header, qualityValue: void 0 }];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRoute404, isRoute500 } from "../../../core/routing/internal/route-errors.js";
|
|
1
2
|
import { renderToAsyncIterable, renderToReadableStream, renderToString } from "./astro/render.js";
|
|
2
3
|
import { encoder } from "./common.js";
|
|
3
4
|
import { renderComponentToString } from "./component.js";
|
|
@@ -61,12 +62,12 @@ async function renderPage(result, componentFactory, props, children, streaming,
|
|
|
61
62
|
}
|
|
62
63
|
let status = init.status;
|
|
63
64
|
let statusText = init.statusText;
|
|
64
|
-
if (route?.route
|
|
65
|
+
if (route?.route && isRoute404(route.route)) {
|
|
65
66
|
status = 404;
|
|
66
67
|
if (statusText === "OK") {
|
|
67
68
|
statusText = "Not Found";
|
|
68
69
|
}
|
|
69
|
-
} else if (route?.route
|
|
70
|
+
} else if (route?.route && isRoute500(route.route)) {
|
|
70
71
|
status = 500;
|
|
71
72
|
if (statusText === "OK") {
|
|
72
73
|
statusText = "Internal Server Error";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RedirectToFallback } from '../i18n/index.js';
|
|
2
2
|
import * as I18nInternals from '../i18n/index.js';
|
|
3
|
+
import { normalizeTheLocale as normalizeTheLocaleInternal } from '../i18n/path.js';
|
|
3
4
|
import type { MiddlewareHandler } from '../types/public/common.js';
|
|
4
5
|
import type { AstroConfig, ValidRedirectStatus } from '../types/public/config.js';
|
|
5
6
|
import type { APIContext } from '../types/public/context.js';
|
|
@@ -249,7 +250,7 @@ export declare let middleware: (customOptions: I18nMiddlewareOptions) => Middlew
|
|
|
249
250
|
* normalizeTheLocale("it_VT") // returns `it-vt`
|
|
250
251
|
* ```
|
|
251
252
|
*/
|
|
252
|
-
export declare const normalizeTheLocale: typeof
|
|
253
|
+
export declare const normalizeTheLocale: typeof normalizeTheLocaleInternal;
|
|
253
254
|
/**
|
|
254
255
|
* Retrieves the configured locale codes for each locale defined in your
|
|
255
256
|
* configuration. When multiple codes are associated to a locale, only the
|
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
} from "../core/errors/errors-data.js";
|
|
8
8
|
import { AstroError } from "../core/errors/index.js";
|
|
9
9
|
import * as I18nInternals from "../i18n/index.js";
|
|
10
|
+
import {
|
|
11
|
+
normalizeTheLocale as normalizeTheLocaleInternal,
|
|
12
|
+
pathHasLocale as pathHasLocaleInternal
|
|
13
|
+
} from "../i18n/path.js";
|
|
10
14
|
const { trailingSlash, site, i18n, build } = config;
|
|
11
15
|
const { format } = build;
|
|
12
16
|
const isBuild = import.meta.env.PROD;
|
|
@@ -72,7 +76,7 @@ const getAbsoluteLocaleUrlList = (path, options) => I18nInternals.getLocaleAbsol
|
|
|
72
76
|
});
|
|
73
77
|
const getPathByLocale = (locale) => I18nInternals.getPathByLocale(locale, locales);
|
|
74
78
|
const getLocaleByPath = (path) => I18nInternals.getLocaleByPath(path, locales);
|
|
75
|
-
const pathHasLocale = (path) =>
|
|
79
|
+
const pathHasLocale = (path) => pathHasLocaleInternal(path, locales);
|
|
76
80
|
let redirectToDefaultLocale;
|
|
77
81
|
if (i18n?.routing === "manual") {
|
|
78
82
|
redirectToDefaultLocale = I18nInternals.redirectToDefaultLocale({
|
|
@@ -149,7 +153,7 @@ if (i18n?.routing === "manual") {
|
|
|
149
153
|
} else {
|
|
150
154
|
middleware = noop("middleware");
|
|
151
155
|
}
|
|
152
|
-
const normalizeTheLocale =
|
|
156
|
+
const normalizeTheLocale = normalizeTheLocaleInternal;
|
|
153
157
|
const toCodes = I18nInternals.toCodes;
|
|
154
158
|
const toPaths = I18nInternals.toPaths;
|
|
155
159
|
export {
|
|
@@ -30,6 +30,11 @@ export declare class AstroServerApp extends BaseApp<RunnablePipeline> {
|
|
|
30
30
|
* Called via HMR when middleware files change.
|
|
31
31
|
*/
|
|
32
32
|
clearMiddleware(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Clears the cached actions so they are re-resolved on the next request.
|
|
35
|
+
* Called via HMR when action files change.
|
|
36
|
+
*/
|
|
37
|
+
clearActions(): void;
|
|
33
38
|
devMatch(pathname: string): Promise<DevMatch | undefined>;
|
|
34
39
|
static create(manifest: SSRManifest, routesList: RoutesList, logger: AstroLogger, loader: ModuleLoader, settings: AstroSettings, getDebugInfo: () => Promise<string>): Promise<AstroServerApp>;
|
|
35
40
|
createPipeline(_streaming: boolean, manifest: SSRManifest, settings: AstroSettings, logger: AstroLogger, loader: ModuleLoader, manifestData: RoutesList, getDebugInfo: () => Promise<string>): RunnablePipeline;
|
|
@@ -63,6 +63,13 @@ class AstroServerApp extends BaseApp {
|
|
|
63
63
|
clearMiddleware() {
|
|
64
64
|
this.pipeline.clearMiddleware();
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Clears the cached actions so they are re-resolved on the next request.
|
|
68
|
+
* Called via HMR when action files change.
|
|
69
|
+
*/
|
|
70
|
+
clearActions() {
|
|
71
|
+
this.pipeline.clearActions();
|
|
72
|
+
}
|
|
66
73
|
async devMatch(pathname) {
|
|
67
74
|
const matchedRoute = await matchRoute(
|
|
68
75
|
pathname,
|
|
@@ -148,6 +155,18 @@ class AstroServerApp extends BaseApp {
|
|
|
148
155
|
});
|
|
149
156
|
body = Buffer.concat(bytes);
|
|
150
157
|
}
|
|
158
|
+
const abortController = new AbortController();
|
|
159
|
+
const socket = incomingRequest.socket;
|
|
160
|
+
const onSocketClose = () => {
|
|
161
|
+
if (!abortController.signal.aborted) {
|
|
162
|
+
abortController.abort();
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
if (socket.destroyed) {
|
|
166
|
+
onSocketClose();
|
|
167
|
+
} else {
|
|
168
|
+
socket.on("close", onSocketClose);
|
|
169
|
+
}
|
|
151
170
|
const request = createRequest({
|
|
152
171
|
url,
|
|
153
172
|
headers: incomingRequest.headers,
|
|
@@ -155,7 +174,8 @@ class AstroServerApp extends BaseApp {
|
|
|
155
174
|
body,
|
|
156
175
|
logger: self.logger,
|
|
157
176
|
isPrerendered: matchedRoute.routeData.prerender,
|
|
158
|
-
routePattern: matchedRoute.routeData.component
|
|
177
|
+
routePattern: matchedRoute.routeData.component,
|
|
178
|
+
init: { signal: abortController.signal }
|
|
159
179
|
});
|
|
160
180
|
const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
|
|
161
181
|
for (const [name, value] of Object.entries(self.settings.config.server.headers ?? {})) {
|
|
@@ -58,6 +58,10 @@ async function createAstroServerApp(controller, settings, loader, logger) {
|
|
|
58
58
|
app.clearMiddleware();
|
|
59
59
|
actualLogger.debug("router", "Middleware cache cleared due to file change");
|
|
60
60
|
});
|
|
61
|
+
import.meta.hot.on("astro:actions-updated", () => {
|
|
62
|
+
app.clearActions();
|
|
63
|
+
actualLogger.debug("router", "Actions cache cleared due to file change");
|
|
64
|
+
});
|
|
61
65
|
}
|
|
62
66
|
return {
|
|
63
67
|
handler(incomingRequest, incomingResponse, options) {
|
|
@@ -14,6 +14,7 @@ export declare class RunnablePipeline extends Pipeline {
|
|
|
14
14
|
readonly getDebugInfo: () => Promise<string>;
|
|
15
15
|
private constructor();
|
|
16
16
|
static create(manifestData: RoutesList, { loader, logger, manifest, settings, getDebugInfo, }: Pick<RunnablePipeline, 'loader' | 'logger' | 'manifest' | 'settings' | 'getDebugInfo'>): RunnablePipeline;
|
|
17
|
+
clearActions(): void;
|
|
17
18
|
headElements(routeData: RouteData): Promise<HeadElements>;
|
|
18
19
|
componentMetadata(routeData: RouteData): Promise<Map<string, import("../types/public/internal.js").SSRComponentMetadata>>;
|
|
19
20
|
preload(routeData: RouteData, filePath: URL): Promise<ComponentInstance>;
|
|
@@ -57,6 +57,10 @@ class RunnablePipeline extends Pipeline {
|
|
|
57
57
|
pipeline.routesList = manifestData;
|
|
58
58
|
return pipeline;
|
|
59
59
|
}
|
|
60
|
+
// Called via HMR when action files change. Not available on production.
|
|
61
|
+
clearActions() {
|
|
62
|
+
this.resolvedActions = void 0;
|
|
63
|
+
}
|
|
60
64
|
async headElements(routeData) {
|
|
61
65
|
const { manifest, runtimeMode, settings } = this;
|
|
62
66
|
const filePath = new URL(`${routeData.component}`, manifest.rootDir);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.3",
|
|
4
4
|
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "withastro",
|
|
@@ -136,8 +136,8 @@
|
|
|
136
136
|
"github-slugger": "^2.0.0",
|
|
137
137
|
"html-escaper": "3.0.3",
|
|
138
138
|
"http-cache-semantics": "^4.2.0",
|
|
139
|
-
"jsonc-parser": "^3.3.1",
|
|
140
139
|
"js-yaml": "^4.1.1",
|
|
140
|
+
"jsonc-parser": "^3.3.1",
|
|
141
141
|
"magic-string": "^0.30.21",
|
|
142
142
|
"magicast": "^0.5.2",
|
|
143
143
|
"mrmime": "^2.0.1",
|
|
@@ -166,8 +166,8 @@
|
|
|
166
166
|
"xxhash-wasm": "^1.1.0",
|
|
167
167
|
"yargs-parser": "^22.0.0",
|
|
168
168
|
"zod": "^4.3.6",
|
|
169
|
+
"@astrojs/markdown-satteri": "0.3.2",
|
|
169
170
|
"@astrojs/internal-helpers": "0.10.0",
|
|
170
|
-
"@astrojs/markdown-satteri": "0.3.1",
|
|
171
171
|
"@astrojs/telemetry": "3.3.2"
|
|
172
172
|
},
|
|
173
173
|
"optionalDependencies": {
|