astro 7.0.4 → 7.0.6
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/Picture.astro +19 -2
- package/dist/actions/handler.js +7 -0
- package/dist/cli/dev/background.js +4 -2
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/cli/install-package.js +5 -3
- package/dist/container/index.js +4 -2
- package/dist/content/content-layer.js +3 -3
- package/dist/core/app/origin-check.d.ts +32 -0
- package/dist/core/app/origin-check.js +52 -0
- package/dist/core/base-pipeline.js +1 -1
- package/dist/core/build/plugins/index.js +2 -0
- package/dist/core/build/plugins/plugin-css-target-lowering.d.ts +14 -0
- package/dist/core/build/plugins/plugin-css-target-lowering.js +82 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +2 -0
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/fetch/fetch-state.js +2 -0
- package/dist/core/head-propagation/buffer.d.ts +14 -3
- package/dist/core/head-propagation/buffer.js +17 -7
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/pages/handler.js +9 -1
- package/dist/core/routing/generator.js +2 -2
- package/dist/core/util.d.ts +8 -0
- package/dist/core/util.js +23 -0
- package/dist/core/viteUtils.d.ts +3 -0
- package/dist/core/viteUtils.js +8 -2
- package/dist/prefetch/index.js +10 -0
- package/dist/runtime/server/render/astro/instance.js +3 -0
- package/dist/runtime/server/render/common.js +7 -1
- package/dist/runtime/server/render/dom.js +4 -1
- package/dist/runtime/server/render/instruction.d.ts +1 -0
- package/dist/runtime/server/render/instruction.js +5 -1
- package/dist/runtime/server/render/page.js +7 -2
- package/dist/runtime/server/render/server-islands-shared.d.ts +1 -0
- package/dist/runtime/server/render/server-islands-shared.js +4 -0
- package/dist/runtime/server/render/server-islands.js +9 -8
- package/dist/runtime/server/render/slot.d.ts +15 -2
- package/dist/runtime/server/render/slot.js +37 -6
- package/dist/runtime/server/render/util.d.ts +1 -0
- package/dist/runtime/server/render/util.js +1 -0
- package/dist/template/4xx.js +1 -1
- package/dist/transitions/swap-functions.js +9 -2
- package/dist/types/public/internal.d.ts +14 -0
- package/dist/vite-plugin-astro/index.js +3 -1
- package/dist/vite-plugin-astro-server/plugin.js +3 -0
- package/dist/vite-plugin-config-alias/index.d.ts +19 -1
- package/dist/vite-plugin-config-alias/index.js +6 -5
- package/dist/vite-plugin-css/index.js +1 -1
- package/dist/vite-plugin-html/transform/index.js +16 -7
- package/dist/vite-plugin-html/transform/slots.d.ts +10 -7
- package/dist/vite-plugin-html/transform/slots.js +19 -26
- package/dist/vite-plugin-html/transform/utils.d.ts +0 -3
- package/dist/vite-plugin-html/transform/utils.js +1 -20
- package/package.json +5 -10
- package/templates/content/types.d.ts +4 -0
- package/dist/core/app/middlewares.d.ts +0 -8
- package/dist/core/app/middlewares.js +0 -49
- package/dist/vite-plugin-html/transform/escape.d.ts +0 -7
- package/dist/vite-plugin-html/transform/escape.js +0 -30
package/components/Picture.astro
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getImage,
|
|
4
|
+
imageConfig,
|
|
5
|
+
inferRemoteSize,
|
|
6
|
+
type LocalImageProps,
|
|
7
|
+
type RemoteImageProps,
|
|
8
|
+
} from 'astro:assets';
|
|
3
9
|
import * as mime from 'mrmime';
|
|
4
|
-
import { isESMImportedImage, resolveSrc } from '../dist/assets/utils/imageKind.js';
|
|
10
|
+
import { isESMImportedImage, isRemoteImage, resolveSrc } from '../dist/assets/utils/imageKind.js';
|
|
5
11
|
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
|
|
6
12
|
import type {
|
|
7
13
|
GetImageResult,
|
|
@@ -62,6 +68,17 @@ for (const key in props) {
|
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
const originalSrc = await resolveSrc(props.src);
|
|
71
|
+
|
|
72
|
+
// When inferSize is set for a remote image, resolve dimensions once and thread them through
|
|
73
|
+
// to all getImage() calls. This avoids multiple redundant HTTP requests to the same URL,
|
|
74
|
+
// which can trigger rate-limiting (HTTP 429) on servers like Wikimedia.
|
|
75
|
+
if (props.inferSize && isRemoteImage(originalSrc)) {
|
|
76
|
+
const remoteSize = await inferRemoteSize(originalSrc);
|
|
77
|
+
delete props.inferSize;
|
|
78
|
+
props.width ??= remoteSize.width;
|
|
79
|
+
props.height ??= remoteSize.height;
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
const optimizedImages: GetImageResult[] = await Promise.all(
|
|
66
83
|
formats.map(
|
|
67
84
|
async (format) =>
|
package/dist/actions/handler.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCrossOriginForbiddenResponse,
|
|
3
|
+
isForbiddenCrossOriginRequest
|
|
4
|
+
} from "../core/app/origin-check.js";
|
|
1
5
|
import { PipelineFeatures } from "../core/base-pipeline.js";
|
|
2
6
|
import { getActionContext, serializeActionResult } from "./runtime/server.js";
|
|
3
7
|
class ActionHandler {
|
|
@@ -18,6 +22,9 @@ class ActionHandler {
|
|
|
18
22
|
if (!action) {
|
|
19
23
|
return void 0;
|
|
20
24
|
}
|
|
25
|
+
if (state.pipeline.manifest.checkOrigin && isForbiddenCrossOriginRequest(apiContext.request, apiContext.url, apiContext.isPrerendered)) {
|
|
26
|
+
return Promise.resolve(createCrossOriginForbiddenResponse(apiContext.request));
|
|
27
|
+
}
|
|
21
28
|
return this.#executeAction(action, setActionResult);
|
|
22
29
|
}
|
|
23
30
|
async #executeAction(action, setActionResult) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, openSync } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
6
|
import {
|
|
6
7
|
checkExistingServer,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
GRACEFUL_SHUTDOWN_TIMEOUT
|
|
12
13
|
} from "../../core/dev/lockfile.js";
|
|
13
14
|
import { resolveRoot } from "../../core/config/config.js";
|
|
15
|
+
const require2 = createRequire(import.meta.url);
|
|
14
16
|
function formatBackgroundOutput(result) {
|
|
15
17
|
return JSON.stringify(result);
|
|
16
18
|
}
|
|
@@ -76,7 +78,7 @@ async function background({
|
|
|
76
78
|
}
|
|
77
79
|
const logFd = openSync(logFilePath, "w");
|
|
78
80
|
const rootPath = fileURLToPath(root);
|
|
79
|
-
const astroBin = resolve(
|
|
81
|
+
const astroBin = resolve(dirname(require2.resolve("astro/package.json")), "bin", "astro.mjs");
|
|
80
82
|
const child = spawn(process.execPath, [astroBin, ...args], {
|
|
81
83
|
detached: true,
|
|
82
84
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
2
3
|
import * as clack from "@clack/prompts";
|
|
3
4
|
import ci from "ci-info";
|
|
4
5
|
import { detect, resolveCommand } from "package-manager-detector";
|
|
@@ -8,8 +9,8 @@ const require2 = createRequire(import.meta.url);
|
|
|
8
9
|
const { bold, cyan, dim, magenta } = colors;
|
|
9
10
|
async function getPackage(packageName, logger, options, otherDeps = []) {
|
|
10
11
|
try {
|
|
11
|
-
require2.resolve(packageName, { paths: [options.cwd ?? process.cwd()] });
|
|
12
|
-
const packageImport = await import(
|
|
12
|
+
const resolved = require2.resolve(packageName, { paths: [options.cwd ?? process.cwd()] });
|
|
13
|
+
const packageImport = await import(pathToFileURL(resolved).href);
|
|
13
14
|
return packageImport;
|
|
14
15
|
} catch {
|
|
15
16
|
if (options.optional) return void 0;
|
|
@@ -25,7 +26,8 @@ async function getPackage(packageName, logger, options, otherDeps = []) {
|
|
|
25
26
|
}
|
|
26
27
|
const result = await installPackage([packageName, ...otherDeps], options, logger);
|
|
27
28
|
if (result) {
|
|
28
|
-
const
|
|
29
|
+
const resolved = require2.resolve(packageName, { paths: [options.cwd ?? process.cwd()] });
|
|
30
|
+
const packageImport = await import(pathToFileURL(resolved).href);
|
|
29
31
|
return packageImport;
|
|
30
32
|
} else {
|
|
31
33
|
return void 0;
|
package/dist/container/index.js
CHANGED
|
@@ -14,6 +14,8 @@ import { validateSegment } from "../core/routing/segment.js";
|
|
|
14
14
|
import { SlotString } from "../runtime/server/render/slot.js";
|
|
15
15
|
import { ContainerPipeline } from "./pipeline.js";
|
|
16
16
|
import { createConsoleLogger } from "../core/logger/impls/console.js";
|
|
17
|
+
const { gfm: _, smartypants: __, ...containerMarkdownDefaults } = ASTRO_CONFIG_DEFAULTS.markdown;
|
|
18
|
+
const CONTAINER_CONFIG_DEFAULTS = { ...ASTRO_CONFIG_DEFAULTS, markdown: containerMarkdownDefaults };
|
|
17
19
|
function createManifest(manifest, renderers, middleware) {
|
|
18
20
|
function middlewareInstance() {
|
|
19
21
|
return {
|
|
@@ -113,7 +115,7 @@ class experimental_AstroContainer {
|
|
|
113
115
|
*/
|
|
114
116
|
static async create(containerOptions = {}) {
|
|
115
117
|
const { streaming = false, manifest, renderers = [], resolve } = containerOptions;
|
|
116
|
-
const astroConfig = await validateConfig(
|
|
118
|
+
const astroConfig = await validateConfig(CONTAINER_CONFIG_DEFAULTS, process.cwd(), "container");
|
|
117
119
|
return new experimental_AstroContainer({
|
|
118
120
|
streaming,
|
|
119
121
|
manifest,
|
|
@@ -206,7 +208,7 @@ class experimental_AstroContainer {
|
|
|
206
208
|
// NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it.
|
|
207
209
|
// @ts-expect-error @ematipico: I plan to use it for a possible integration that could help people
|
|
208
210
|
static async createFromManifest(manifest) {
|
|
209
|
-
const astroConfig = await validateConfig(
|
|
211
|
+
const astroConfig = await validateConfig(CONTAINER_CONFIG_DEFAULTS, process.cwd(), "container");
|
|
210
212
|
const container = new experimental_AstroContainer({
|
|
211
213
|
manifest,
|
|
212
214
|
astroConfig
|
|
@@ -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.6") {
|
|
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.6") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "7.0.6");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home of the `security.checkOrigin` logic. Exposes the shared predicate and
|
|
3
|
+
* response used to reject cross-site submissions, plus the middleware factory
|
|
4
|
+
* that installs the check in the request pipeline. Consumers (the pipeline
|
|
5
|
+
* middleware and the Astro Actions dispatch) import from here so the check
|
|
6
|
+
* stays consistent regardless of where it runs.
|
|
7
|
+
*/
|
|
8
|
+
import type { MiddlewareHandler } from '../../types/public/common.js';
|
|
9
|
+
/**
|
|
10
|
+
* Determines whether a request should be rejected because it is a cross-site
|
|
11
|
+
* submission for a route rendered on demand.
|
|
12
|
+
*
|
|
13
|
+
* This encapsulates the shared logic used by both the origin-check middleware
|
|
14
|
+
* and the Astro Actions dispatch, so the check is applied consistently
|
|
15
|
+
* regardless of where the request is handled.
|
|
16
|
+
*
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
export declare function isForbiddenCrossOriginRequest(request: Request, url: URL, isPrerendered: boolean): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Builds the 403 response returned when a cross-site submission is rejected.
|
|
22
|
+
*
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCrossOriginForbiddenResponse(request: Request): Response;
|
|
26
|
+
/**
|
|
27
|
+
* Returns a middleware function in charge to check the `origin` header.
|
|
28
|
+
*
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
export declare function createOriginCheckMiddleware(): MiddlewareHandler;
|
|
32
|
+
export declare function hasFormLikeHeader(contentType: string | null): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineMiddleware } from "../middleware/defineMiddleware.js";
|
|
2
|
+
const FORM_CONTENT_TYPES = [
|
|
3
|
+
"application/x-www-form-urlencoded",
|
|
4
|
+
"multipart/form-data",
|
|
5
|
+
"text/plain"
|
|
6
|
+
];
|
|
7
|
+
const SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
8
|
+
function isForbiddenCrossOriginRequest(request, url, isPrerendered) {
|
|
9
|
+
if (isPrerendered) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (SAFE_METHODS.includes(request.method)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const isSameOrigin = request.headers.get("origin") === url.origin;
|
|
16
|
+
const hasContentType = request.headers.has("content-type");
|
|
17
|
+
if (hasContentType) {
|
|
18
|
+
const formLikeHeader = hasFormLikeHeader(request.headers.get("content-type"));
|
|
19
|
+
return formLikeHeader && !isSameOrigin;
|
|
20
|
+
}
|
|
21
|
+
return !isSameOrigin;
|
|
22
|
+
}
|
|
23
|
+
function createCrossOriginForbiddenResponse(request) {
|
|
24
|
+
return new Response(`Cross-site ${request.method} form submissions are forbidden`, {
|
|
25
|
+
status: 403
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function createOriginCheckMiddleware() {
|
|
29
|
+
return defineMiddleware((context, next) => {
|
|
30
|
+
const { request, url, isPrerendered } = context;
|
|
31
|
+
if (isForbiddenCrossOriginRequest(request, url, isPrerendered)) {
|
|
32
|
+
return createCrossOriginForbiddenResponse(request);
|
|
33
|
+
}
|
|
34
|
+
return next();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function hasFormLikeHeader(contentType) {
|
|
38
|
+
if (contentType) {
|
|
39
|
+
for (const FORM_CONTENT_TYPE of FORM_CONTENT_TYPES) {
|
|
40
|
+
if (contentType.toLowerCase().includes(FORM_CONTENT_TYPE)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
createCrossOriginForbiddenResponse,
|
|
49
|
+
createOriginCheckMiddleware,
|
|
50
|
+
hasFormLikeHeader,
|
|
51
|
+
isForbiddenCrossOriginRequest
|
|
52
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NOOP_ACTIONS_MOD } from "../actions/noop-actions.js";
|
|
2
|
-
import { createOriginCheckMiddleware } from "./app/
|
|
2
|
+
import { createOriginCheckMiddleware } from "./app/origin-check.js";
|
|
3
3
|
import { ActionNotFoundError } from "./errors/errors-data.js";
|
|
4
4
|
import { AstroError } from "./errors/index.js";
|
|
5
5
|
import { NOOP_MIDDLEWARE_FN } from "./middleware/noop-middleware.js";
|
|
@@ -3,6 +3,7 @@ import { astroHeadBuildPlugin } from "../../../vite-plugin-head/index.js";
|
|
|
3
3
|
import { pluginAnalyzer } from "./plugin-analyzer.js";
|
|
4
4
|
import { pluginComponentEntry } from "./plugin-component-entry.js";
|
|
5
5
|
import { pluginCSS } from "./plugin-css.js";
|
|
6
|
+
import { pluginCssTargetLowering } from "./plugin-css-target-lowering.js";
|
|
6
7
|
import { pluginInternals } from "./plugin-internals.js";
|
|
7
8
|
import { pluginMiddleware } from "./plugin-middleware.js";
|
|
8
9
|
import { pluginPrerender } from "./plugin-prerender.js";
|
|
@@ -18,6 +19,7 @@ function getAllBuildPlugins(internals, options) {
|
|
|
18
19
|
pluginInternals(options, internals),
|
|
19
20
|
pluginMiddleware(options, internals),
|
|
20
21
|
vitePluginActionsBuild(options, internals),
|
|
22
|
+
pluginCssTargetLowering(),
|
|
21
23
|
...pluginCSS(options, internals),
|
|
22
24
|
astroHeadBuildPlugin(internals),
|
|
23
25
|
pluginPrerender(options, internals),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Plugin as VitePlugin } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite plugin that applies CSS target lowering without minification.
|
|
4
|
+
*
|
|
5
|
+
* Vite's `finalizeCss` only applies CSS target lowering (via lightningcss) when
|
|
6
|
+
* `config.build.cssMinify` is truthy, because target lowering and minification
|
|
7
|
+
* are coupled in `minifyCSS`. When users set `minify: false`, Astro forces
|
|
8
|
+
* `cssMinify: false`, which disables target lowering for all CSS.
|
|
9
|
+
*
|
|
10
|
+
* This plugin fills that gap: when `cssMinify` is falsy and a CSS target is
|
|
11
|
+
* configured, it runs lightningcss with `minify: false` on all CSS assets in
|
|
12
|
+
* `generateBundle`, applying target lowering without minification.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pluginCssTargetLowering(): VitePlugin;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const BROWSER_MAP = {
|
|
3
|
+
chrome: "chrome",
|
|
4
|
+
edge: "edge",
|
|
5
|
+
firefox: "firefox",
|
|
6
|
+
hermes: false,
|
|
7
|
+
ie: "ie",
|
|
8
|
+
ios: "ios_saf",
|
|
9
|
+
node: false,
|
|
10
|
+
opera: "opera",
|
|
11
|
+
rhino: false,
|
|
12
|
+
safari: "safari"
|
|
13
|
+
};
|
|
14
|
+
const VERSION_RE = /\d/;
|
|
15
|
+
function convertTargets(esbuildTarget) {
|
|
16
|
+
if (!esbuildTarget) return {};
|
|
17
|
+
const targets = {};
|
|
18
|
+
const entries = Array.isArray(esbuildTarget) ? esbuildTarget : [esbuildTarget];
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (entry === "esnext") continue;
|
|
21
|
+
const index = entry.search(VERSION_RE);
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
const browserName = entry.slice(0, index);
|
|
24
|
+
const browser = BROWSER_MAP[browserName];
|
|
25
|
+
if (browser === false) continue;
|
|
26
|
+
if (browser) {
|
|
27
|
+
const [major, minor = 0] = entry.slice(index).split(".").map((v) => Number.parseInt(v, 10));
|
|
28
|
+
if (!isNaN(major) && !isNaN(minor)) {
|
|
29
|
+
const version = major << 16 | minor << 8;
|
|
30
|
+
if (!targets[browser] || version < targets[browser]) {
|
|
31
|
+
targets[browser] = version;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return targets;
|
|
38
|
+
}
|
|
39
|
+
function pluginCssTargetLowering() {
|
|
40
|
+
let resolvedConfig;
|
|
41
|
+
return {
|
|
42
|
+
name: "astro:css-target-lowering",
|
|
43
|
+
enforce: "post",
|
|
44
|
+
configResolved(config) {
|
|
45
|
+
resolvedConfig = config;
|
|
46
|
+
},
|
|
47
|
+
async generateBundle(_outputOptions, bundle) {
|
|
48
|
+
if (resolvedConfig.build.cssMinify) return;
|
|
49
|
+
const cssTarget = resolvedConfig.build.cssTarget;
|
|
50
|
+
if (!cssTarget) return;
|
|
51
|
+
const targets = convertTargets(cssTarget);
|
|
52
|
+
if (Object.keys(targets).length === 0) return;
|
|
53
|
+
let lcssTransform;
|
|
54
|
+
try {
|
|
55
|
+
const requireFromVite = createRequire(import.meta.resolve("vite"));
|
|
56
|
+
lcssTransform = requireFromVite("lightningcss").transform;
|
|
57
|
+
} catch {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
for (const [, asset] of Object.entries(bundle)) {
|
|
61
|
+
if (asset.type !== "asset") continue;
|
|
62
|
+
if (!asset.fileName.endsWith(".css")) continue;
|
|
63
|
+
if (typeof asset.source !== "string") continue;
|
|
64
|
+
try {
|
|
65
|
+
const result = lcssTransform({
|
|
66
|
+
...resolvedConfig.css?.lightningcss,
|
|
67
|
+
targets,
|
|
68
|
+
cssModules: void 0,
|
|
69
|
+
filename: asset.fileName,
|
|
70
|
+
code: Buffer.from(asset.source),
|
|
71
|
+
minify: false
|
|
72
|
+
});
|
|
73
|
+
asset.source = new TextDecoder().decode(result.code);
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
pluginCssTargetLowering
|
|
82
|
+
};
|
package/dist/core/constants.js
CHANGED
package/dist/core/create-vite.js
CHANGED
|
@@ -201,6 +201,8 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
|
|
|
201
201
|
}
|
|
202
202
|
},
|
|
203
203
|
resolve: {
|
|
204
|
+
// Vite's native tsconfig path resolution; see configAliasVitePlugin for the deprecated fallback.
|
|
205
|
+
tsconfigPaths: true,
|
|
204
206
|
alias: [
|
|
205
207
|
{
|
|
206
208
|
// This is needed for Deno compatibility, as the non-browser version
|
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.6";
|
|
30
30
|
const isPrerelease = currentVersion.includes("-");
|
|
31
31
|
if (!isPrerelease) {
|
|
32
32
|
try {
|
|
@@ -297,6 +297,8 @@ class FetchState {
|
|
|
297
297
|
extraStyleHashes,
|
|
298
298
|
extraScriptHashes,
|
|
299
299
|
propagators: /* @__PURE__ */ new Set(),
|
|
300
|
+
routeHasPropagation: false,
|
|
301
|
+
pendingSlotEvaluations: [],
|
|
300
302
|
templateDepth: 0
|
|
301
303
|
},
|
|
302
304
|
cspDestination: manifest.csp?.cspDestination ?? (routeData.prerender ? "meta" : "header"),
|
|
@@ -3,10 +3,21 @@ export interface HeadPropagator {
|
|
|
3
3
|
init(result: SSRResult): unknown | Promise<unknown>;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* Runs all registered propagators and collects
|
|
6
|
+
* Runs all registered propagators and collects the head HTML they emit.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Components with head content are discovered as we go. Initializing one
|
|
9
|
+
* propagator can register more of them: a component marked `in-tree` renders
|
|
10
|
+
* its children, and one of those children may be a `self` component that emits
|
|
11
|
+
* styles. Slots add a second way to find them — a slot whose markup contains an
|
|
12
|
+
* `await` only reaches the components after that `await` once it resolves, so
|
|
13
|
+
* we also wait for those pending slot pre-renders. We keep initializing
|
|
14
|
+
* propagators and waiting on slots until no new ones appear.
|
|
15
|
+
*
|
|
16
|
+
* Propagators are tracked in a `seen` set rather than read through a single
|
|
17
|
+
* live `Set` iterator. A propagator can be registered after we have already
|
|
18
|
+
* iterated to the end of the set (e.g. once a slot's `await` resolves), and a
|
|
19
|
+
* `Set` iterator that has reported `done` would never report those late
|
|
20
|
+
* additions.
|
|
10
21
|
*
|
|
11
22
|
* @example
|
|
12
23
|
* If a layout initializes and discovers a nested component that also emits
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
async function collectPropagatedHeadParts(input) {
|
|
2
2
|
const collectedHeadParts = [];
|
|
3
|
-
const
|
|
3
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4
|
+
const pendingSlotEvaluations = input.result._metadata?.pendingSlotEvaluations ?? [];
|
|
4
5
|
while (true) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
if (pendingSlotEvaluations.length > 0) {
|
|
7
|
+
const batch = pendingSlotEvaluations.splice(0, pendingSlotEvaluations.length);
|
|
8
|
+
await Promise.all(batch);
|
|
9
|
+
continue;
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
let progressed = false;
|
|
12
|
+
for (const propagator of input.propagators) {
|
|
13
|
+
if (seen.has(propagator)) continue;
|
|
14
|
+
seen.add(propagator);
|
|
15
|
+
progressed = true;
|
|
16
|
+
const returnValue = await propagator.init(input.result);
|
|
17
|
+
if (input.isHeadAndContent(returnValue) && returnValue.head) {
|
|
18
|
+
collectedHeadParts.push(returnValue.head);
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
12
21
|
}
|
|
22
|
+
if (!progressed) break;
|
|
13
23
|
}
|
|
14
24
|
return collectedHeadParts;
|
|
15
25
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { renderEndpoint } from "../../runtime/server/endpoint.js";
|
|
2
2
|
import { renderPage } from "../../runtime/server/index.js";
|
|
3
3
|
import { ASTRO_ERROR_HEADER } from "../constants.js";
|
|
4
|
+
import {
|
|
5
|
+
createCrossOriginForbiddenResponse,
|
|
6
|
+
isForbiddenCrossOriginRequest
|
|
7
|
+
} from "../app/origin-check.js";
|
|
4
8
|
import { getCookiesFromResponse } from "../cookies/response.js";
|
|
5
9
|
const EMPTY_SLOTS = Object.freeze({});
|
|
6
10
|
class PagesHandler {
|
|
@@ -78,8 +82,12 @@ class PagesHandler {
|
|
|
78
82
|
if (!state.routeData) {
|
|
79
83
|
return new Response(null, { status: 404, headers: { [ASTRO_ERROR_HEADER]: "true" } });
|
|
80
84
|
}
|
|
85
|
+
const ctx = state.getAPIContext();
|
|
86
|
+
if (this.#pipeline.manifest.checkOrigin && isForbiddenCrossOriginRequest(ctx.request, ctx.url, ctx.isPrerendered)) {
|
|
87
|
+
return createCrossOriginForbiddenResponse(ctx.request);
|
|
88
|
+
}
|
|
81
89
|
try {
|
|
82
|
-
return await this.handle(state,
|
|
90
|
+
return await this.handle(state, ctx);
|
|
83
91
|
} catch (err) {
|
|
84
92
|
app.logger.error(null, err.stack || err.message || String(err));
|
|
85
93
|
return app.renderError(state.request, {
|
|
@@ -11,10 +11,10 @@ function sanitizeParams(params) {
|
|
|
11
11
|
}
|
|
12
12
|
function getParameter(part, params) {
|
|
13
13
|
if (part.spread) {
|
|
14
|
-
return params[part.content.slice(3)]
|
|
14
|
+
return params[part.content.slice(3)] ?? "";
|
|
15
15
|
}
|
|
16
16
|
if (part.dynamic) {
|
|
17
|
-
if (
|
|
17
|
+
if (params[part.content] === void 0) {
|
|
18
18
|
throw new TypeError(`Missing parameter: ${part.content}`);
|
|
19
19
|
}
|
|
20
20
|
return params[part.content];
|
package/dist/core/util.d.ts
CHANGED
|
@@ -24,6 +24,14 @@ export declare function resolvePages(config: AstroConfig): URL;
|
|
|
24
24
|
export declare function isPage(file: URL, settings: AstroSettings): boolean;
|
|
25
25
|
export declare function isEndpoint(file: URL, settings: AstroSettings): boolean;
|
|
26
26
|
export declare function resolveJsToTs(filePath: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a path that doesn't name a file on disk (e.g. produced by an
|
|
29
|
+
* extensionless import like `import { Counter } from './Counter'`) to the file
|
|
30
|
+
* Vite would load, by probing Vite's default extension order and directory
|
|
31
|
+
* `index` files. Returns the path unchanged when it already exists as a file
|
|
32
|
+
* or when no candidate is found.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveExtensionlessPath(filePath: string): string;
|
|
27
35
|
/**
|
|
28
36
|
* Set a default NODE_ENV so Vite doesn't set an incorrect default when loading the Astro config
|
|
29
37
|
*/
|
package/dist/core/util.js
CHANGED
|
@@ -94,6 +94,28 @@ function resolveJsToTs(filePath) {
|
|
|
94
94
|
}
|
|
95
95
|
return filePath;
|
|
96
96
|
}
|
|
97
|
+
const VITE_DEFAULT_RESOLVE_EXTENSIONS = [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json"];
|
|
98
|
+
function resolveExtensionlessPath(filePath) {
|
|
99
|
+
const stat = fs.statSync(filePath, { throwIfNoEntry: false });
|
|
100
|
+
if (stat?.isFile()) {
|
|
101
|
+
return filePath;
|
|
102
|
+
}
|
|
103
|
+
for (const ext of VITE_DEFAULT_RESOLVE_EXTENSIONS) {
|
|
104
|
+
const tryPath = filePath + ext;
|
|
105
|
+
if (fs.existsSync(tryPath)) {
|
|
106
|
+
return tryPath;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (stat?.isDirectory()) {
|
|
110
|
+
for (const ext of VITE_DEFAULT_RESOLVE_EXTENSIONS) {
|
|
111
|
+
const tryPath = `${filePath}/index${ext}`;
|
|
112
|
+
if (fs.existsSync(tryPath)) {
|
|
113
|
+
return tryPath;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return filePath;
|
|
118
|
+
}
|
|
97
119
|
function ensureProcessNodeEnv(defaultNodeEnv) {
|
|
98
120
|
if (!process.env.NODE_ENV) {
|
|
99
121
|
process.env.NODE_ENV = defaultNodeEnv;
|
|
@@ -106,6 +128,7 @@ export {
|
|
|
106
128
|
isMarkdownFile,
|
|
107
129
|
isPage,
|
|
108
130
|
parseNpmName,
|
|
131
|
+
resolveExtensionlessPath,
|
|
109
132
|
resolveJsToTs,
|
|
110
133
|
resolvePages,
|
|
111
134
|
unwrapId,
|
package/dist/core/viteUtils.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export declare function normalizePath(id: string): string;
|
|
|
9
9
|
* Examples:
|
|
10
10
|
* - `./components/Button.jsx` from `/app/src/pages/index.astro`
|
|
11
11
|
* -> `/app/src/pages/components/Button.tsx` (when `.tsx` exists)
|
|
12
|
+
* - `../components/Counter` from `/app/src/pages/index.astro`
|
|
13
|
+
* -> `/app/src/components/Counter.tsx` (extensionless imports probe Vite's
|
|
14
|
+
* default extension order, then directory `index` files)
|
|
12
15
|
* - `#components/react/Counter.tsx`
|
|
13
16
|
* -> `/app/src/components/react/Counter.tsx` via package `imports`
|
|
14
17
|
*/
|
package/dist/core/viteUtils.js
CHANGED
|
@@ -2,7 +2,13 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { prependForwardSlash, slash } from "../core/path.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
resolveExtensionlessPath,
|
|
7
|
+
resolveJsToTs,
|
|
8
|
+
unwrapId,
|
|
9
|
+
VALID_ID_PREFIX,
|
|
10
|
+
viteID
|
|
11
|
+
} from "./util.js";
|
|
6
12
|
const isWindows = typeof process !== "undefined" && process.platform === "win32";
|
|
7
13
|
function normalizePath(id) {
|
|
8
14
|
return path.posix.normalize(isWindows ? slash(id) : id);
|
|
@@ -10,7 +16,7 @@ function normalizePath(id) {
|
|
|
10
16
|
function resolvePath(specifier, importer) {
|
|
11
17
|
if (specifier.startsWith(".")) {
|
|
12
18
|
const absoluteSpecifier = path.resolve(path.dirname(importer), specifier);
|
|
13
|
-
return resolveJsToTs(normalizePath(absoluteSpecifier));
|
|
19
|
+
return resolveExtensionlessPath(resolveJsToTs(normalizePath(absoluteSpecifier)));
|
|
14
20
|
} else if (specifier.startsWith("#")) {
|
|
15
21
|
try {
|
|
16
22
|
const resolved = createRequire(pathToFileURL(importer)).resolve(specifier);
|
package/dist/prefetch/index.js
CHANGED
|
@@ -191,6 +191,16 @@ function onPageLoad(cb) {
|
|
|
191
191
|
}
|
|
192
192
|
cb();
|
|
193
193
|
});
|
|
194
|
+
new MutationObserver((mutations) => {
|
|
195
|
+
for (const mutation of mutations) {
|
|
196
|
+
for (const node of mutation.addedNodes) {
|
|
197
|
+
if (node instanceof Element && (node.tagName === "A" || node.querySelector?.("a"))) {
|
|
198
|
+
cb();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}).observe(document.body, { childList: true, subtree: true });
|
|
194
204
|
}
|
|
195
205
|
function appendSpeculationRules(url, eagerness) {
|
|
196
206
|
const script = document.createElement("script");
|
|
@@ -18,6 +18,9 @@ class AstroComponentInstance {
|
|
|
18
18
|
for (const name in slots) {
|
|
19
19
|
let didRender = false;
|
|
20
20
|
let value = slots[name](result);
|
|
21
|
+
if (result._metadata.routeHasPropagation && isPromise(value)) {
|
|
22
|
+
result._metadata.pendingSlotEvaluations.push(value);
|
|
23
|
+
}
|
|
21
24
|
this.slotValues[name] = () => {
|
|
22
25
|
if (!didRender) {
|
|
23
26
|
didRender = true;
|
|
@@ -103,7 +103,13 @@ function stringifyChunk(result, chunk) {
|
|
|
103
103
|
out += stringifyChunk(result, instr);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
|
|
106
|
+
if (c.chunks.length) {
|
|
107
|
+
for (const part of c.chunks) {
|
|
108
|
+
out += typeof part === "string" ? part : stringifyChunk(result, part);
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
out += chunk.toString();
|
|
112
|
+
}
|
|
107
113
|
return out;
|
|
108
114
|
}
|
|
109
115
|
return chunk.toString();
|