astro 4.13.2 → 4.13.4
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/@types/astro.d.ts +14 -9
- package/dist/actions/consts.d.ts +5 -0
- package/dist/actions/consts.js +6 -0
- package/dist/actions/runtime/middleware.d.ts +5 -4
- package/dist/actions/runtime/middleware.js +55 -17
- package/dist/actions/runtime/virtual/server.d.ts +1 -1
- package/dist/actions/runtime/virtual/server.js +9 -3
- package/dist/actions/runtime/virtual/shared.d.ts +5 -0
- package/dist/actions/runtime/virtual/shared.js +29 -4
- package/dist/actions/utils.d.ts +1 -1
- package/dist/actions/utils.js +5 -5
- package/dist/container/index.js +3 -1
- package/dist/core/app/common.js +4 -1
- package/dist/core/app/index.js +5 -3
- package/dist/core/app/types.d.ts +3 -1
- package/dist/core/build/generate.js +4 -2
- package/dist/core/build/index.js +3 -1
- package/dist/core/build/plugins/plugin-manifest.js +5 -2
- package/dist/core/build/plugins/plugin-ssr.js +5 -1
- package/dist/core/build/static-build.js +2 -0
- package/dist/core/build/types.d.ts +1 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/encryption.d.ts +24 -0
- package/dist/core/encryption.js +64 -0
- package/dist/core/messages.js +2 -2
- package/dist/core/render-context.js +3 -2
- package/dist/core/server-islands/endpoint.js +5 -1
- package/dist/runtime/server/render/server-islands.js +7 -4
- package/dist/vite-plugin-astro-server/plugin.js +2 -0
- package/dist/vite-plugin-scanner/scan.js +1 -1
- package/package.json +10 -9
- package/templates/actions.mjs +12 -2
package/dist/@types/astro.d.ts
CHANGED
|
@@ -1842,25 +1842,29 @@ export interface AstroUserConfig {
|
|
|
1842
1842
|
* @version 4.10.0
|
|
1843
1843
|
* @description
|
|
1844
1844
|
*
|
|
1845
|
-
* Enables experimental `astro:env` features
|
|
1845
|
+
* Enables experimental `astro:env` features.
|
|
1846
1846
|
*
|
|
1847
1847
|
* The `astro:env` API lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client. Import and use your defined variables from the appropriate `/client` or `/server` module:
|
|
1848
1848
|
*
|
|
1849
1849
|
* ```astro
|
|
1850
1850
|
* ---
|
|
1851
|
-
* import {
|
|
1852
|
-
* import {
|
|
1853
|
-
* const NODE_ENV = getSecret("NODE_ENV")
|
|
1851
|
+
* import { API_URL } from "astro:env/client"
|
|
1852
|
+
* import { API_SECRET_TOKEN } from "astro:env/server"
|
|
1854
1853
|
*
|
|
1855
1854
|
* const data = await fetch(`${API_URL}/users`, {
|
|
1856
|
-
* method: "
|
|
1855
|
+
* method: "GET",
|
|
1857
1856
|
* headers: {
|
|
1858
1857
|
* "Content-Type": "application/json",
|
|
1859
|
-
* "Authorization": `Bearer ${
|
|
1858
|
+
* "Authorization": `Bearer ${API_SECRET_TOKEN}`
|
|
1860
1859
|
* },
|
|
1861
|
-
* body: JSON.stringify({ appId: APP_ID, nodeEnv: NODE_ENV })
|
|
1862
1860
|
* })
|
|
1863
1861
|
* ---
|
|
1862
|
+
*
|
|
1863
|
+
* <script>
|
|
1864
|
+
* import { API_URL } from "astro:env/client"
|
|
1865
|
+
*
|
|
1866
|
+
* fetch(`${API_URL}/ping`)
|
|
1867
|
+
* </script>
|
|
1864
1868
|
* ```
|
|
1865
1869
|
*
|
|
1866
1870
|
* To define the data type and properties of your environment variables, declare a schema in your Astro config in `experimental.env.schema`. The `envField` helper allows you define your variable as a string, number, or boolean and pass properties in an object:
|
|
@@ -1898,7 +1902,7 @@ export interface AstroUserConfig {
|
|
|
1898
1902
|
* import { PORT } from "astro:env/server"
|
|
1899
1903
|
* ```
|
|
1900
1904
|
*
|
|
1901
|
-
* - **Secret server variables**: These variables are not part of your final bundle and can be accessed on the server through the `astro:env/server` module. The `getSecret()` helper function can be used to retrieve secrets not specified in the schema
|
|
1905
|
+
* - **Secret server variables**: These variables are not part of your final bundle and can be accessed on the server through the `astro:env/server` module. The `getSecret()` helper function can be used to retrieve secrets not specified in the schema. Its implementation is provided by your adapter and defaults to `process.env`:
|
|
1902
1906
|
*
|
|
1903
1907
|
* ```js
|
|
1904
1908
|
* import { API_SECRET, getSecret } from "astro:env/server"
|
|
@@ -2163,7 +2167,7 @@ export type GetDataEntryInfoReturnType = {
|
|
|
2163
2167
|
};
|
|
2164
2168
|
export interface AstroAdapterFeatures {
|
|
2165
2169
|
/**
|
|
2166
|
-
* Creates
|
|
2170
|
+
* Creates an edge function that will communiate with the Astro middleware
|
|
2167
2171
|
*/
|
|
2168
2172
|
edgeMiddleware: boolean;
|
|
2169
2173
|
/**
|
|
@@ -2956,6 +2960,7 @@ export interface SSRResult {
|
|
|
2956
2960
|
cookies: AstroCookies | undefined;
|
|
2957
2961
|
serverIslandNameMap: Map<string, string>;
|
|
2958
2962
|
trailingSlash: AstroConfig['trailingSlash'];
|
|
2963
|
+
key: Promise<CryptoKey>;
|
|
2959
2964
|
_metadata: SSRMetadata;
|
|
2960
2965
|
}
|
|
2961
2966
|
/**
|
package/dist/actions/consts.d.ts
CHANGED
|
@@ -4,3 +4,8 @@ export declare const ACTIONS_TYPES_FILE = "actions.d.ts";
|
|
|
4
4
|
export declare const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
|
|
5
5
|
export declare const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
|
|
6
6
|
export declare const NOOP_ACTIONS = "\0noop-actions";
|
|
7
|
+
export declare const ACTION_QUERY_PARAMS: {
|
|
8
|
+
actionName: string;
|
|
9
|
+
actionPayload: string;
|
|
10
|
+
actionRedirect: string;
|
|
11
|
+
};
|
package/dist/actions/consts.js
CHANGED
|
@@ -4,8 +4,14 @@ const ACTIONS_TYPES_FILE = "actions.d.ts";
|
|
|
4
4
|
const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
|
|
5
5
|
const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
|
|
6
6
|
const NOOP_ACTIONS = "\0noop-actions";
|
|
7
|
+
const ACTION_QUERY_PARAMS = {
|
|
8
|
+
actionName: "_astroAction",
|
|
9
|
+
actionPayload: "_astroActionPayload",
|
|
10
|
+
actionRedirect: "_astroActionRedirect"
|
|
11
|
+
};
|
|
7
12
|
export {
|
|
8
13
|
ACTIONS_TYPES_FILE,
|
|
14
|
+
ACTION_QUERY_PARAMS,
|
|
9
15
|
NOOP_ACTIONS,
|
|
10
16
|
RESOLVED_VIRTUAL_INTERNAL_MODULE_ID,
|
|
11
17
|
RESOLVED_VIRTUAL_MODULE_ID,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type SerializedActionResult } from './virtual/shared.js';
|
|
2
|
+
export type ActionPayload = {
|
|
3
|
+
actionResult: SerializedActionResult;
|
|
4
|
+
actionName: string;
|
|
5
|
+
};
|
|
2
6
|
export type Locals = {
|
|
3
|
-
|
|
4
|
-
actionResult: SerializedActionResult;
|
|
5
|
-
actionName: string;
|
|
6
|
-
};
|
|
7
|
+
_actionPayload: ActionPayload;
|
|
7
8
|
};
|
|
8
9
|
export declare const onRequest: import("../../@types/astro.js").MiddlewareHandler;
|
|
@@ -2,6 +2,7 @@ import { yellow } from "kleur/colors";
|
|
|
2
2
|
import { ActionQueryStringInvalidError } from "../../core/errors/errors-data.js";
|
|
3
3
|
import { AstroError } from "../../core/errors/errors.js";
|
|
4
4
|
import { defineMiddleware } from "../../core/middleware/index.js";
|
|
5
|
+
import { ACTION_QUERY_PARAMS } from "../consts.js";
|
|
5
6
|
import { formContentTypes, hasContentType } from "./utils.js";
|
|
6
7
|
import { getAction } from "./virtual/get-action.js";
|
|
7
8
|
import {
|
|
@@ -10,7 +11,14 @@ import {
|
|
|
10
11
|
const onRequest = defineMiddleware(async (context, next) => {
|
|
11
12
|
const locals = context.locals;
|
|
12
13
|
const { request } = context;
|
|
13
|
-
if (locals.
|
|
14
|
+
if (locals._actionPayload) return next();
|
|
15
|
+
const actionPayload = context.cookies.get(ACTION_QUERY_PARAMS.actionPayload)?.json();
|
|
16
|
+
if (actionPayload) {
|
|
17
|
+
if (!isActionPayload(actionPayload)) {
|
|
18
|
+
throw new Error("Internal: Invalid action payload in cookie.");
|
|
19
|
+
}
|
|
20
|
+
return renderResult({ context, next, ...actionPayload });
|
|
21
|
+
}
|
|
14
22
|
if (import.meta.env.DEV && request.method === "POST" && request.body === null) {
|
|
15
23
|
console.warn(
|
|
16
24
|
yellow("[astro:actions]"),
|
|
@@ -18,7 +26,7 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
18
26
|
);
|
|
19
27
|
return next();
|
|
20
28
|
}
|
|
21
|
-
const actionName = context.url.searchParams.get(
|
|
29
|
+
const actionName = context.url.searchParams.get(ACTION_QUERY_PARAMS.actionName);
|
|
22
30
|
if (context.request.method === "POST" && actionName) {
|
|
23
31
|
return handlePost({ context, next, actionName });
|
|
24
32
|
}
|
|
@@ -27,6 +35,25 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
27
35
|
}
|
|
28
36
|
return next();
|
|
29
37
|
});
|
|
38
|
+
async function renderResult({
|
|
39
|
+
context,
|
|
40
|
+
next,
|
|
41
|
+
actionResult,
|
|
42
|
+
actionName
|
|
43
|
+
}) {
|
|
44
|
+
const locals = context.locals;
|
|
45
|
+
locals._actionPayload = { actionResult, actionName };
|
|
46
|
+
const response = await next();
|
|
47
|
+
context.cookies.delete(ACTION_QUERY_PARAMS.actionPayload);
|
|
48
|
+
if (actionResult.type === "error") {
|
|
49
|
+
return new Response(response.body, {
|
|
50
|
+
status: actionResult.status,
|
|
51
|
+
statusText: actionResult.type,
|
|
52
|
+
headers: response.headers
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return response;
|
|
56
|
+
}
|
|
30
57
|
async function handlePost({
|
|
31
58
|
context,
|
|
32
59
|
next,
|
|
@@ -47,28 +74,33 @@ async function handlePost({
|
|
|
47
74
|
}
|
|
48
75
|
const action = baseAction.bind(context);
|
|
49
76
|
const actionResult = await action(formData);
|
|
50
|
-
|
|
77
|
+
if (context.url.searchParams.get(ACTION_QUERY_PARAMS.actionRedirect) === "false") {
|
|
78
|
+
return renderResult({
|
|
79
|
+
context,
|
|
80
|
+
next,
|
|
81
|
+
actionName,
|
|
82
|
+
actionResult: serializeActionResult(actionResult)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return redirectWithResult({ context, actionName, actionResult });
|
|
51
86
|
}
|
|
52
|
-
async function
|
|
87
|
+
async function redirectWithResult({
|
|
53
88
|
context,
|
|
54
|
-
next,
|
|
55
89
|
actionName,
|
|
56
90
|
actionResult
|
|
57
91
|
}) {
|
|
58
|
-
|
|
59
|
-
locals._actionsInternal = {
|
|
92
|
+
context.cookies.set(ACTION_QUERY_PARAMS.actionPayload, {
|
|
60
93
|
actionName,
|
|
61
94
|
actionResult: serializeActionResult(actionResult)
|
|
62
|
-
};
|
|
63
|
-
const response = await next();
|
|
95
|
+
});
|
|
64
96
|
if (actionResult.error) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
97
|
+
const referer = context.request.headers.get("Referer");
|
|
98
|
+
if (!referer) {
|
|
99
|
+
throw new Error("Internal: Referer unexpectedly missing from Action POST request.");
|
|
100
|
+
}
|
|
101
|
+
return context.redirect(referer);
|
|
70
102
|
}
|
|
71
|
-
return
|
|
103
|
+
return context.redirect(context.url.pathname);
|
|
72
104
|
}
|
|
73
105
|
async function handlePostLegacy({ context, next }) {
|
|
74
106
|
const { request } = context;
|
|
@@ -79,7 +111,7 @@ async function handlePostLegacy({ context, next }) {
|
|
|
79
111
|
formData = await request.clone().formData();
|
|
80
112
|
}
|
|
81
113
|
if (!formData) return next();
|
|
82
|
-
const actionName = formData.get(
|
|
114
|
+
const actionName = formData.get(ACTION_QUERY_PARAMS.actionName);
|
|
83
115
|
if (!actionName) return next();
|
|
84
116
|
const baseAction = await getAction(actionName);
|
|
85
117
|
if (!baseAction) {
|
|
@@ -90,7 +122,13 @@ async function handlePostLegacy({ context, next }) {
|
|
|
90
122
|
}
|
|
91
123
|
const action = baseAction.bind(context);
|
|
92
124
|
const actionResult = await action(formData);
|
|
93
|
-
return
|
|
125
|
+
return redirectWithResult({ context, actionName, actionResult });
|
|
126
|
+
}
|
|
127
|
+
function isActionPayload(json) {
|
|
128
|
+
if (typeof json !== "object" || json == null) return false;
|
|
129
|
+
if (!("actionResult" in json) || typeof json.actionResult !== "object") return false;
|
|
130
|
+
if (!("actionName" in json) || typeof json.actionName !== "string") return false;
|
|
131
|
+
return true;
|
|
94
132
|
}
|
|
95
133
|
export {
|
|
96
134
|
onRequest
|
|
@@ -10,7 +10,7 @@ export type ActionReturnType<T extends ActionHandler<any, any>> = Awaited<Return
|
|
|
10
10
|
export type ActionClient<TOutput, TAccept extends ActionAccept | undefined, TInputSchema extends ActionInputSchema<TAccept> | undefined> = TInputSchema extends z.ZodType ? ((input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<SafeResult<z.input<TInputSchema> extends ErrorInferenceObject ? z.input<TInputSchema> : ErrorInferenceObject, Awaited<TOutput>>>) & {
|
|
11
11
|
queryString: string;
|
|
12
12
|
orThrow: (input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<Awaited<TOutput>>;
|
|
13
|
-
} : (input?: any) => Promise<SafeResult<never, Awaited<TOutput>>> & {
|
|
13
|
+
} : ((input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>) & {
|
|
14
14
|
orThrow: (input?: any) => Promise<Awaited<TOutput>>;
|
|
15
15
|
};
|
|
16
16
|
export declare function defineAction<TOutput, TAccept extends ActionAccept | undefined = undefined, TInputSchema extends ActionInputSchema<ActionAccept> | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
|
|
@@ -62,11 +62,17 @@ function formDataToObject(formData, schema) {
|
|
|
62
62
|
const obj = {};
|
|
63
63
|
for (const [key, baseValidator] of Object.entries(schema.shape)) {
|
|
64
64
|
let validator = baseValidator;
|
|
65
|
-
while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable) {
|
|
65
|
+
while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable || validator instanceof z.ZodDefault) {
|
|
66
|
+
if (validator instanceof z.ZodDefault && !formData.has(key)) {
|
|
67
|
+
obj[key] = validator._def.defaultValue();
|
|
68
|
+
}
|
|
66
69
|
validator = validator._def.innerType;
|
|
67
70
|
}
|
|
68
|
-
if (
|
|
69
|
-
|
|
71
|
+
if (!formData.has(key) && key in obj) {
|
|
72
|
+
continue;
|
|
73
|
+
} else if (validator instanceof z.ZodBoolean) {
|
|
74
|
+
const val = formData.get(key);
|
|
75
|
+
obj[key] = val === "true" ? true : val === "false" ? false : formData.has(key);
|
|
70
76
|
} else if (validator instanceof z.ZodArray) {
|
|
71
77
|
obj[key] = handleFormDataGetAll(key, formData, validator);
|
|
72
78
|
} else {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
2
|
import type { ErrorInferenceObject, MaybePromise } from '../utils.js';
|
|
3
|
+
export declare const ACTION_QUERY_PARAMS: {
|
|
4
|
+
actionName: string;
|
|
5
|
+
actionPayload: string;
|
|
6
|
+
actionRedirect: string;
|
|
7
|
+
};
|
|
3
8
|
export declare const ACTION_ERROR_CODES: readonly ["BAD_REQUEST", "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "TIMEOUT", "CONFLICT", "PRECONDITION_FAILED", "PAYLOAD_TOO_LARGE", "UNSUPPORTED_MEDIA_TYPE", "UNPROCESSABLE_CONTENT", "TOO_MANY_REQUESTS", "CLIENT_CLOSED_REQUEST", "INTERNAL_SERVER_ERROR"];
|
|
4
9
|
export type ActionErrorCode = (typeof ACTION_ERROR_CODES)[number];
|
|
5
10
|
export declare class ActionError<T extends ErrorInferenceObject = ErrorInferenceObject> extends Error {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { parse as devalueParse, stringify as devalueStringify } from "devalue";
|
|
2
|
+
import { ACTION_QUERY_PARAMS as _ACTION_QUERY_PARAMS } from "../../consts.js";
|
|
3
|
+
const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
|
|
2
4
|
const ACTION_ERROR_CODES = [
|
|
3
5
|
"BAD_REQUEST",
|
|
4
6
|
"UNAUTHORIZED",
|
|
@@ -113,7 +115,7 @@ async function callSafely(handler) {
|
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
function getActionQueryString(name) {
|
|
116
|
-
const searchParams = new URLSearchParams({
|
|
118
|
+
const searchParams = new URLSearchParams({ [_ACTION_QUERY_PARAMS.actionName]: name });
|
|
117
119
|
return `?${searchParams.toString()}`;
|
|
118
120
|
}
|
|
119
121
|
function getActionProps(action) {
|
|
@@ -130,14 +132,16 @@ function getActionProps(action) {
|
|
|
130
132
|
}
|
|
131
133
|
function serializeActionResult(res) {
|
|
132
134
|
if (res.error) {
|
|
135
|
+
if (import.meta.env?.DEV) {
|
|
136
|
+
actionResultErrorStack.set(res.error.stack);
|
|
137
|
+
}
|
|
133
138
|
return {
|
|
134
139
|
type: "error",
|
|
135
140
|
status: res.error.status,
|
|
136
141
|
contentType: "application/json",
|
|
137
142
|
body: JSON.stringify({
|
|
138
143
|
...res.error,
|
|
139
|
-
message: res.error.message
|
|
140
|
-
stack: import.meta.env.PROD ? void 0 : res.error.stack
|
|
144
|
+
message: res.error.message
|
|
141
145
|
})
|
|
142
146
|
};
|
|
143
147
|
}
|
|
@@ -159,7 +163,16 @@ function serializeActionResult(res) {
|
|
|
159
163
|
}
|
|
160
164
|
function deserializeActionResult(res) {
|
|
161
165
|
if (res.type === "error") {
|
|
162
|
-
|
|
166
|
+
if (import.meta.env?.PROD) {
|
|
167
|
+
return { error: ActionError.fromJson(JSON.parse(res.body)), data: void 0 };
|
|
168
|
+
} else {
|
|
169
|
+
const error = ActionError.fromJson(JSON.parse(res.body));
|
|
170
|
+
error.stack = actionResultErrorStack.get();
|
|
171
|
+
return {
|
|
172
|
+
error,
|
|
173
|
+
data: void 0
|
|
174
|
+
};
|
|
175
|
+
}
|
|
163
176
|
}
|
|
164
177
|
if (res.type === "empty") {
|
|
165
178
|
return { data: void 0, error: void 0 };
|
|
@@ -171,8 +184,20 @@ function deserializeActionResult(res) {
|
|
|
171
184
|
error: void 0
|
|
172
185
|
};
|
|
173
186
|
}
|
|
187
|
+
const actionResultErrorStack = /* @__PURE__ */ function actionResultErrorStackFn() {
|
|
188
|
+
let errorStack;
|
|
189
|
+
return {
|
|
190
|
+
set(stack) {
|
|
191
|
+
errorStack = stack;
|
|
192
|
+
},
|
|
193
|
+
get() {
|
|
194
|
+
return errorStack;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}();
|
|
174
198
|
export {
|
|
175
199
|
ACTION_ERROR_CODES,
|
|
200
|
+
ACTION_QUERY_PARAMS,
|
|
176
201
|
ActionError,
|
|
177
202
|
ActionInputError,
|
|
178
203
|
callSafely,
|
package/dist/actions/utils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { APIContext } from '../@types/astro.js';
|
|
2
2
|
import type { Locals } from './runtime/middleware.js';
|
|
3
3
|
import { type ActionAPIContext } from './runtime/utils.js';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function hasActionPayload(locals: APIContext['locals']): locals is Locals;
|
|
5
5
|
export declare function createGetActionResult(locals: APIContext['locals']): APIContext['getActionResult'];
|
|
6
6
|
export declare function createCallAction(context: ActionAPIContext): APIContext['callAction'];
|
package/dist/actions/utils.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {} from "./runtime/utils.js";
|
|
2
2
|
import { deserializeActionResult, getActionQueryString } from "./runtime/virtual/shared.js";
|
|
3
|
-
function
|
|
4
|
-
return "
|
|
3
|
+
function hasActionPayload(locals) {
|
|
4
|
+
return "_actionPayload" in locals;
|
|
5
5
|
}
|
|
6
6
|
function createGetActionResult(locals) {
|
|
7
7
|
return (actionFn) => {
|
|
8
|
-
if (!
|
|
8
|
+
if (!hasActionPayload(locals) || actionFn.toString() !== getActionQueryString(locals._actionPayload.actionName)) {
|
|
9
9
|
return void 0;
|
|
10
10
|
}
|
|
11
|
-
return deserializeActionResult(locals.
|
|
11
|
+
return deserializeActionResult(locals._actionPayload.actionResult);
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
function createCallAction(context) {
|
|
@@ -20,5 +20,5 @@ function createCallAction(context) {
|
|
|
20
20
|
export {
|
|
21
21
|
createCallAction,
|
|
22
22
|
createGetActionResult,
|
|
23
|
-
|
|
23
|
+
hasActionPayload
|
|
24
24
|
};
|
package/dist/container/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { posix } from "node:path";
|
|
|
2
2
|
import { getDefaultClientDirectives } from "../core/client-directive/index.js";
|
|
3
3
|
import { ASTRO_CONFIG_DEFAULTS } from "../core/config/schema.js";
|
|
4
4
|
import { validateConfig } from "../core/config/validate.js";
|
|
5
|
+
import { createKey } from "../core/encryption.js";
|
|
5
6
|
import { Logger } from "../core/logger/core.js";
|
|
6
7
|
import { nodeLogDestination } from "../core/logger/node.js";
|
|
7
8
|
import { removeLeadingForwardSlash } from "../core/path.js";
|
|
@@ -31,7 +32,8 @@ function createManifest(manifest, renderers, middleware) {
|
|
|
31
32
|
i18n: manifest?.i18n,
|
|
32
33
|
checkOrigin: false,
|
|
33
34
|
middleware: manifest?.middleware ?? middleware ?? defaultMiddleware,
|
|
34
|
-
experimentalEnvGetSecretEnabled: false
|
|
35
|
+
experimentalEnvGetSecretEnabled: false,
|
|
36
|
+
key: createKey()
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
class experimental_AstroContainer {
|
package/dist/core/app/common.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decodeKey } from "../encryption.js";
|
|
1
2
|
import { deserializeRouteData } from "../routing/manifest/serialization.js";
|
|
2
3
|
function deserializeManifest(serializedManifest) {
|
|
3
4
|
const routes = [];
|
|
@@ -14,6 +15,7 @@ function deserializeManifest(serializedManifest) {
|
|
|
14
15
|
const inlinedScripts = new Map(serializedManifest.inlinedScripts);
|
|
15
16
|
const clientDirectives = new Map(serializedManifest.clientDirectives);
|
|
16
17
|
const serverIslandNameMap = new Map(serializedManifest.serverIslandNameMap);
|
|
18
|
+
const key = decodeKey(serializedManifest.key);
|
|
17
19
|
return {
|
|
18
20
|
// in case user middleware exists, this no-op middleware will be reassigned (see plugin-ssr.ts)
|
|
19
21
|
middleware(_, next) {
|
|
@@ -25,7 +27,8 @@ function deserializeManifest(serializedManifest) {
|
|
|
25
27
|
inlinedScripts,
|
|
26
28
|
clientDirectives,
|
|
27
29
|
routes,
|
|
28
|
-
serverIslandNameMap
|
|
30
|
+
serverIslandNameMap,
|
|
31
|
+
key
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
export {
|
package/dist/core/app/index.js
CHANGED
|
@@ -298,9 +298,11 @@ class App {
|
|
|
298
298
|
`${this.#baseWithoutTrailingSlash}/${status}${maybeDotHtml}`,
|
|
299
299
|
url
|
|
300
300
|
);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
301
|
+
if (statusURL.toString() !== request.url) {
|
|
302
|
+
const response2 = await fetch(statusURL.toString());
|
|
303
|
+
const override = { status };
|
|
304
|
+
return this.#mergeResponses(response2, originalResponse, override);
|
|
305
|
+
}
|
|
304
306
|
}
|
|
305
307
|
const mod = await this.#pipeline.getModuleForRoute(errorRouteData);
|
|
306
308
|
try {
|
package/dist/core/app/types.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export type SSRManifest = {
|
|
|
52
52
|
pageMap?: Map<ComponentPath, ImportComponentInstance>;
|
|
53
53
|
serverIslandMap?: Map<string, () => Promise<ComponentInstance>>;
|
|
54
54
|
serverIslandNameMap?: Map<string, string>;
|
|
55
|
+
key: Promise<CryptoKey>;
|
|
55
56
|
i18n: SSRManifestI18n | undefined;
|
|
56
57
|
middleware: MiddlewareHandler;
|
|
57
58
|
checkOrigin: boolean;
|
|
@@ -64,11 +65,12 @@ export type SSRManifestI18n = {
|
|
|
64
65
|
defaultLocale: string;
|
|
65
66
|
domainLookupTable: Record<string, string>;
|
|
66
67
|
};
|
|
67
|
-
export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap'> & {
|
|
68
|
+
export type SerializedSSRManifest = Omit<SSRManifest, 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap' | 'key'> & {
|
|
68
69
|
routes: SerializedRouteInfo[];
|
|
69
70
|
assets: string[];
|
|
70
71
|
componentMetadata: [string, SSRComponentMetadata][];
|
|
71
72
|
inlinedScripts: [string, string][];
|
|
72
73
|
clientDirectives: [string, string][];
|
|
73
74
|
serverIslandNameMap: [string, string][];
|
|
75
|
+
key: string;
|
|
74
76
|
};
|
|
@@ -54,7 +54,8 @@ async function generatePages(options, internals) {
|
|
|
54
54
|
options.settings,
|
|
55
55
|
internals,
|
|
56
56
|
renderers.renderers,
|
|
57
|
-
middleware
|
|
57
|
+
middleware,
|
|
58
|
+
options.key
|
|
58
59
|
);
|
|
59
60
|
}
|
|
60
61
|
const pipeline = BuildPipeline.create({ internals, manifest, options });
|
|
@@ -358,7 +359,7 @@ function getPrettyRouteName(route) {
|
|
|
358
359
|
return route.component;
|
|
359
360
|
}
|
|
360
361
|
}
|
|
361
|
-
function createBuildManifest(settings, internals, renderers, middleware) {
|
|
362
|
+
function createBuildManifest(settings, internals, renderers, middleware, key) {
|
|
362
363
|
let i18nManifest = void 0;
|
|
363
364
|
if (settings.config.i18n) {
|
|
364
365
|
i18nManifest = {
|
|
@@ -388,6 +389,7 @@ function createBuildManifest(settings, internals, renderers, middleware) {
|
|
|
388
389
|
buildFormat: settings.config.build.format,
|
|
389
390
|
middleware,
|
|
390
391
|
checkOrigin: settings.config.security?.checkOrigin ?? false,
|
|
392
|
+
key,
|
|
391
393
|
experimentalEnvGetSecretEnabled: false
|
|
392
394
|
};
|
|
393
395
|
}
|
package/dist/core/build/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { resolveConfig } from "../config/config.js";
|
|
|
15
15
|
import { createNodeLogger } from "../config/logging.js";
|
|
16
16
|
import { createSettings } from "../config/settings.js";
|
|
17
17
|
import { createVite } from "../create-vite.js";
|
|
18
|
+
import { createKey } from "../encryption.js";
|
|
18
19
|
import { levels, timerMessage } from "../logger/core.js";
|
|
19
20
|
import { apply as applyPolyfill } from "../polyfill.js";
|
|
20
21
|
import { createRouteManifest } from "../routing/index.js";
|
|
@@ -135,7 +136,8 @@ class AstroBuilder {
|
|
|
135
136
|
origin: this.origin,
|
|
136
137
|
pageNames,
|
|
137
138
|
teardownCompiler: this.teardownCompiler,
|
|
138
|
-
viteConfig
|
|
139
|
+
viteConfig,
|
|
140
|
+
key: createKey()
|
|
139
141
|
};
|
|
140
142
|
const { internals, ssrOutputChunkNames, contentFileNames } = await viteBuild(opts);
|
|
141
143
|
await staticBuild(opts, internals, ssrOutputChunkNames, contentFileNames);
|
|
@@ -5,6 +5,7 @@ import { normalizeTheLocale } from "../../../i18n/index.js";
|
|
|
5
5
|
import { toRoutingStrategy } from "../../../i18n/utils.js";
|
|
6
6
|
import { runHookBuildSsr } from "../../../integrations/hooks.js";
|
|
7
7
|
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../../vite-plugin-scripts/index.js";
|
|
8
|
+
import { encodeKey } from "../../encryption.js";
|
|
8
9
|
import { fileExtension, joinPaths, prependForwardSlash } from "../../path.js";
|
|
9
10
|
import { serializeRouteData } from "../../routing/index.js";
|
|
10
11
|
import { addRollupInput } from "../add-rollup-input.js";
|
|
@@ -103,7 +104,8 @@ async function createManifest(buildOpts, internals) {
|
|
|
103
104
|
internals.staticFiles.add(file);
|
|
104
105
|
}
|
|
105
106
|
const staticFiles = internals.staticFiles;
|
|
106
|
-
|
|
107
|
+
const encodedKey = await encodeKey(await buildOpts.key);
|
|
108
|
+
return buildManifest(buildOpts, internals, Array.from(staticFiles), encodedKey);
|
|
107
109
|
}
|
|
108
110
|
function injectManifest(manifest, chunk) {
|
|
109
111
|
const code = chunk.code;
|
|
@@ -111,7 +113,7 @@ function injectManifest(manifest, chunk) {
|
|
|
111
113
|
return JSON.stringify(manifest);
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
|
-
function buildManifest(opts, internals, staticFiles) {
|
|
116
|
+
function buildManifest(opts, internals, staticFiles, encodedKey) {
|
|
115
117
|
const { settings } = opts;
|
|
116
118
|
const routes = [];
|
|
117
119
|
const domainLookupTable = {};
|
|
@@ -214,6 +216,7 @@ function buildManifest(opts, internals, staticFiles) {
|
|
|
214
216
|
buildFormat: settings.config.build.format,
|
|
215
217
|
checkOrigin: settings.config.security?.checkOrigin ?? false,
|
|
216
218
|
serverIslandNameMap: Array.from(settings.serverIslandNameMap),
|
|
219
|
+
key: encodedKey,
|
|
217
220
|
experimentalEnvGetSecretEnabled: settings.config.experimental.env !== void 0 && (settings.adapter?.supportedAstroFeatures.envGetSecret ?? "unsupported") !== "unsupported"
|
|
218
221
|
};
|
|
219
222
|
}
|
|
@@ -24,6 +24,10 @@ function vitePluginSSR(internals, adapter, options) {
|
|
|
24
24
|
}
|
|
25
25
|
inputs.add(getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component));
|
|
26
26
|
}
|
|
27
|
+
const adapterServerEntrypoint = options.settings.adapter?.serverEntrypoint;
|
|
28
|
+
if (adapterServerEntrypoint) {
|
|
29
|
+
inputs.add(adapterServerEntrypoint);
|
|
30
|
+
}
|
|
27
31
|
inputs.add(SSR_VIRTUAL_MODULE_ID);
|
|
28
32
|
return addRollupInput(opts, Array.from(inputs));
|
|
29
33
|
},
|
|
@@ -195,8 +199,8 @@ function generateSSRCode(settings, adapter, middlewareId) {
|
|
|
195
199
|
const pageMap = isFunctionPerRouteEnabled(adapter) ? "pageModule" : "pageMap";
|
|
196
200
|
const imports = [
|
|
197
201
|
`import { renderers } from '${RENDERERS_MODULE_ID}';`,
|
|
198
|
-
`import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
|
|
199
202
|
`import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`,
|
|
203
|
+
`import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
|
|
200
204
|
edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`,
|
|
201
205
|
settings.config.experimental.serverIslands ? `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';` : ""
|
|
202
206
|
];
|
|
@@ -199,6 +199,8 @@ async function ssrBuild(opts, internals, input, container, logger) {
|
|
|
199
199
|
return "renderers.mjs";
|
|
200
200
|
} else if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
|
|
201
201
|
return "manifest_[hash].mjs";
|
|
202
|
+
} else if (chunkInfo.facadeModuleId === settings.adapter?.serverEntrypoint) {
|
|
203
|
+
return "adapter_[hash].mjs";
|
|
202
204
|
} else if (settings.config.experimental.contentCollectionCache && chunkInfo.facadeModuleId && hasAnyContentFlag(chunkInfo.facadeModuleId)) {
|
|
203
205
|
const moduleId = reverseSymlink({
|
|
204
206
|
symlinks,
|
|
@@ -39,6 +39,7 @@ export interface StaticBuildOptions {
|
|
|
39
39
|
pageNames: string[];
|
|
40
40
|
viteConfig: InlineConfig;
|
|
41
41
|
teardownCompiler: boolean;
|
|
42
|
+
key: Promise<CryptoKey>;
|
|
42
43
|
}
|
|
43
44
|
type ImportComponentInstance = () => Promise<ComponentInstance>;
|
|
44
45
|
export interface SinglePageBuiltModule {
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -19,7 +19,7 @@ async function dev(inlineConfig) {
|
|
|
19
19
|
await telemetry.record([]);
|
|
20
20
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
21
21
|
const logger = restart.container.logger;
|
|
22
|
-
const currentVersion = "4.13.
|
|
22
|
+
const currentVersion = "4.13.4";
|
|
23
23
|
const isPrerelease = currentVersion.includes("-");
|
|
24
24
|
if (!isPrerelease) {
|
|
25
25
|
try {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a CryptoKey object that can be used to encrypt any string.
|
|
3
|
+
*/
|
|
4
|
+
export declare function createKey(): Promise<CryptoKey>;
|
|
5
|
+
/**
|
|
6
|
+
* Takes a key that has been serialized to an array of bytes and returns a CryptoKey
|
|
7
|
+
*/
|
|
8
|
+
export declare function importKey(bytes: Uint8Array): Promise<CryptoKey>;
|
|
9
|
+
/**
|
|
10
|
+
* Encodes a CryptoKey to base64 string, so that it can be embedded in JSON / JavaScript
|
|
11
|
+
*/
|
|
12
|
+
export declare function encodeKey(key: CryptoKey): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Decodes a base64 string into bytes and then imports the key.
|
|
15
|
+
*/
|
|
16
|
+
export declare function decodeKey(encoded: string): Promise<CryptoKey>;
|
|
17
|
+
/**
|
|
18
|
+
* Using a CryptoKey, encrypt a string into a base64 string.
|
|
19
|
+
*/
|
|
20
|
+
export declare function encryptString(key: CryptoKey, raw: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Takes a base64 encoded string, decodes it and returns the decrypted text.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decryptString(key: CryptoKey, encoded: string): Promise<string>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { decodeBase64, decodeHex, encodeBase64, encodeHexUpperCase } from "@oslojs/encoding";
|
|
2
|
+
const ALGORITHM = "AES-GCM";
|
|
3
|
+
async function createKey() {
|
|
4
|
+
const key = await crypto.subtle.generateKey(
|
|
5
|
+
{
|
|
6
|
+
name: ALGORITHM,
|
|
7
|
+
length: 256
|
|
8
|
+
},
|
|
9
|
+
true,
|
|
10
|
+
["encrypt", "decrypt"]
|
|
11
|
+
);
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
14
|
+
async function importKey(bytes) {
|
|
15
|
+
const key = await crypto.subtle.importKey("raw", bytes, ALGORITHM, true, ["encrypt", "decrypt"]);
|
|
16
|
+
return key;
|
|
17
|
+
}
|
|
18
|
+
async function encodeKey(key) {
|
|
19
|
+
const exported = await crypto.subtle.exportKey("raw", key);
|
|
20
|
+
const encodedKey = encodeBase64(new Uint8Array(exported));
|
|
21
|
+
return encodedKey;
|
|
22
|
+
}
|
|
23
|
+
async function decodeKey(encoded) {
|
|
24
|
+
const bytes = decodeBase64(encoded);
|
|
25
|
+
return crypto.subtle.importKey("raw", bytes, ALGORITHM, true, ["encrypt", "decrypt"]);
|
|
26
|
+
}
|
|
27
|
+
const encoder = new TextEncoder();
|
|
28
|
+
const decoder = new TextDecoder();
|
|
29
|
+
const IV_LENGTH = 24;
|
|
30
|
+
async function encryptString(key, raw) {
|
|
31
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH / 2));
|
|
32
|
+
const data = encoder.encode(raw);
|
|
33
|
+
const buffer = await crypto.subtle.encrypt(
|
|
34
|
+
{
|
|
35
|
+
name: ALGORITHM,
|
|
36
|
+
iv
|
|
37
|
+
},
|
|
38
|
+
key,
|
|
39
|
+
data
|
|
40
|
+
);
|
|
41
|
+
return encodeHexUpperCase(iv) + encodeBase64(new Uint8Array(buffer));
|
|
42
|
+
}
|
|
43
|
+
async function decryptString(key, encoded) {
|
|
44
|
+
const iv = decodeHex(encoded.slice(0, IV_LENGTH));
|
|
45
|
+
const dataArray = decodeBase64(encoded.slice(IV_LENGTH));
|
|
46
|
+
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
47
|
+
{
|
|
48
|
+
name: ALGORITHM,
|
|
49
|
+
iv
|
|
50
|
+
},
|
|
51
|
+
key,
|
|
52
|
+
dataArray
|
|
53
|
+
);
|
|
54
|
+
const decryptedString = decoder.decode(decryptedBuffer);
|
|
55
|
+
return decryptedString;
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
createKey,
|
|
59
|
+
decodeKey,
|
|
60
|
+
decryptString,
|
|
61
|
+
encodeKey,
|
|
62
|
+
encryptString,
|
|
63
|
+
importKey
|
|
64
|
+
};
|
package/dist/core/messages.js
CHANGED
|
@@ -38,7 +38,7 @@ function serverStart({
|
|
|
38
38
|
host,
|
|
39
39
|
base
|
|
40
40
|
}) {
|
|
41
|
-
const version = "4.13.
|
|
41
|
+
const version = "4.13.4";
|
|
42
42
|
const localPrefix = `${dim("\u2503")} Local `;
|
|
43
43
|
const networkPrefix = `${dim("\u2503")} Network `;
|
|
44
44
|
const emptyPrefix = " ".repeat(11);
|
|
@@ -270,7 +270,7 @@ function printHelp({
|
|
|
270
270
|
message.push(
|
|
271
271
|
linebreak(),
|
|
272
272
|
` ${bgGreen(black(` ${commandName} `))} ${green(
|
|
273
|
-
`v${"4.13.
|
|
273
|
+
`v${"4.13.4"}`
|
|
274
274
|
)} ${headline}`
|
|
275
275
|
);
|
|
276
276
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { deserializeActionResult } from "../actions/runtime/virtual/shared.js";
|
|
2
|
-
import { createCallAction, createGetActionResult,
|
|
2
|
+
import { createCallAction, createGetActionResult, hasActionPayload } from "../actions/utils.js";
|
|
3
3
|
import {
|
|
4
4
|
computeCurrentLocale,
|
|
5
5
|
computePreferredLocale,
|
|
@@ -256,7 +256,7 @@ class RenderContext {
|
|
|
256
256
|
throw new AstroError(AstroErrorData.AstroResponseHeadersReassigned);
|
|
257
257
|
}
|
|
258
258
|
};
|
|
259
|
-
const actionResult =
|
|
259
|
+
const actionResult = hasActionPayload(this.locals) ? deserializeActionResult(this.locals._actionPayload.actionResult) : void 0;
|
|
260
260
|
const result = {
|
|
261
261
|
base: manifest.base,
|
|
262
262
|
cancelled: false,
|
|
@@ -279,6 +279,7 @@ class RenderContext {
|
|
|
279
279
|
styles,
|
|
280
280
|
actionResult,
|
|
281
281
|
serverIslandNameMap: manifest.serverIslandNameMap ?? /* @__PURE__ */ new Map(),
|
|
282
|
+
key: manifest.key,
|
|
282
283
|
trailingSlash: manifest.trailingSlash,
|
|
283
284
|
_metadata: {
|
|
284
285
|
hasHydrationScript: false,
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
renderTemplate
|
|
4
4
|
} from "../../runtime/server/index.js";
|
|
5
5
|
import { createSlotValueFromString } from "../../runtime/server/render/slot.js";
|
|
6
|
+
import { decryptString } from "../encryption.js";
|
|
6
7
|
import { getPattern } from "../routing/manifest/pattern.js";
|
|
7
8
|
const SERVER_ISLAND_ROUTE = "/_server-islands/[name]";
|
|
8
9
|
const SERVER_ISLAND_COMPONENT = "_server-islands.astro";
|
|
@@ -51,7 +52,10 @@ function createEndpoint(manifest) {
|
|
|
51
52
|
statusText: "Not found"
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
|
-
const
|
|
55
|
+
const key = await manifest.key;
|
|
56
|
+
const encryptedProps = data.encryptedProps;
|
|
57
|
+
const propString = await decryptString(key, encryptedProps);
|
|
58
|
+
const props = JSON.parse(propString);
|
|
55
59
|
const componentModule = await imp();
|
|
56
60
|
const Component = componentModule[data.componentExport];
|
|
57
61
|
const slots = {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encryptString } from "../../../core/encryption.js";
|
|
1
2
|
import { renderChild } from "./any.js";
|
|
2
3
|
import { renderSlotToString } from "./slot.js";
|
|
3
4
|
const internalProps = /* @__PURE__ */ new Set([
|
|
@@ -21,9 +22,9 @@ function renderServerIsland(result, _displayName, props, slots) {
|
|
|
21
22
|
if (!componentId) {
|
|
22
23
|
throw new Error(`Could not find server component name`);
|
|
23
24
|
}
|
|
24
|
-
for (const
|
|
25
|
-
if (internalProps.has(
|
|
26
|
-
delete props[
|
|
25
|
+
for (const key2 of Object.keys(props)) {
|
|
26
|
+
if (internalProps.has(key2)) {
|
|
27
|
+
delete props[key2];
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
destination.write("<!--server-island-start-->");
|
|
@@ -36,6 +37,8 @@ function renderServerIsland(result, _displayName, props, slots) {
|
|
|
36
37
|
await renderChild(destination, slots.fallback(result));
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
const key = await result.key;
|
|
41
|
+
const propsEncrypted = await encryptString(key, JSON.stringify(props));
|
|
39
42
|
const hostId = crypto.randomUUID();
|
|
40
43
|
const serverIslandUrl = `${result.base}_server-islands/${componentId}${result.trailingSlash === "always" ? "/" : ""}`;
|
|
41
44
|
destination.write(`<script async type="module" data-island-id="${hostId}">
|
|
@@ -44,7 +47,7 @@ let componentExport = ${safeJsonStringify(componentExport)};
|
|
|
44
47
|
let script = document.querySelector('script[data-island-id="${hostId}"]');
|
|
45
48
|
let data = {
|
|
46
49
|
componentExport,
|
|
47
|
-
|
|
50
|
+
encryptedProps: ${safeJsonStringify(propsEncrypted)},
|
|
48
51
|
slots: ${safeJsonStringify(renderedSlots)},
|
|
49
52
|
};
|
|
50
53
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { IncomingMessage } from "node:http";
|
|
3
|
+
import { createKey } from "../core/encryption.js";
|
|
3
4
|
import { getViteErrorPayload } from "../core/errors/dev/index.js";
|
|
4
5
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
5
6
|
import { patchOverlay } from "../core/errors/overlay.js";
|
|
@@ -117,6 +118,7 @@ function createDevelopmentManifest(settings) {
|
|
|
117
118
|
i18n: i18nManifest,
|
|
118
119
|
checkOrigin: settings.config.security?.checkOrigin ?? false,
|
|
119
120
|
experimentalEnvGetSecretEnabled: false,
|
|
121
|
+
key: createKey(),
|
|
120
122
|
middleware(_, next) {
|
|
121
123
|
return next();
|
|
122
124
|
}
|
|
@@ -35,7 +35,7 @@ async function scan(code, id, settings) {
|
|
|
35
35
|
const { n: name, le: endOfLocalName } = _export;
|
|
36
36
|
if (BOOLEAN_EXPORTS.has(name)) {
|
|
37
37
|
const prefix = code.slice(0, endOfLocalName).split("export").pop().trim().replace("prerender", "").trim();
|
|
38
|
-
const suffix = code.slice(endOfLocalName).trim().replace(/=/, "").trim().split(/[;\n]/)[0];
|
|
38
|
+
const suffix = code.slice(endOfLocalName).trim().replace(/=/, "").trim().split(/[;\n\r]/)[0].trim();
|
|
39
39
|
if (prefix !== "const" || !(isTruthy(suffix) || isFalsy(suffix))) {
|
|
40
40
|
throw new AstroError({
|
|
41
41
|
...AstroErrorData.InvalidPrerenderExport,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.4",
|
|
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",
|
|
@@ -107,13 +107,14 @@
|
|
|
107
107
|
"vendor"
|
|
108
108
|
],
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@astrojs/compiler": "^2.10.
|
|
110
|
+
"@astrojs/compiler": "^2.10.2",
|
|
111
111
|
"@babel/core": "^7.25.2",
|
|
112
112
|
"@babel/generator": "^7.25.0",
|
|
113
113
|
"@babel/parser": "^7.25.3",
|
|
114
114
|
"@babel/plugin-transform-react-jsx": "^7.25.2",
|
|
115
115
|
"@babel/traverse": "^7.25.3",
|
|
116
116
|
"@babel/types": "^7.25.2",
|
|
117
|
+
"@oslojs/encoding": "^0.4.1",
|
|
117
118
|
"@types/babel__core": "^7.20.5",
|
|
118
119
|
"@types/cookie": "^0.6.0",
|
|
119
120
|
"acorn": "^8.12.1",
|
|
@@ -159,22 +160,22 @@
|
|
|
159
160
|
"tsconfck": "^3.1.1",
|
|
160
161
|
"unist-util-visit": "^5.0.0",
|
|
161
162
|
"vfile": "^6.0.2",
|
|
162
|
-
"vite": "^5.
|
|
163
|
+
"vite": "^5.4.0",
|
|
163
164
|
"vitefu": "^0.2.5",
|
|
164
165
|
"which-pm": "^3.0.0",
|
|
165
166
|
"yargs-parser": "^21.1.1",
|
|
166
167
|
"zod": "^3.23.8",
|
|
167
168
|
"zod-to-json-schema": "^3.23.2",
|
|
169
|
+
"@astrojs/markdown-remark": "5.2.0",
|
|
168
170
|
"@astrojs/internal-helpers": "0.4.1",
|
|
169
|
-
"@astrojs/telemetry": "3.1.0"
|
|
170
|
-
"@astrojs/markdown-remark": "5.2.0"
|
|
171
|
+
"@astrojs/telemetry": "3.1.0"
|
|
171
172
|
},
|
|
172
173
|
"optionalDependencies": {
|
|
173
174
|
"sharp": "^0.33.3"
|
|
174
175
|
},
|
|
175
176
|
"devDependencies": {
|
|
176
|
-
"@astrojs/check": "^0.9.
|
|
177
|
-
"@playwright/test": "^1.
|
|
177
|
+
"@astrojs/check": "^0.9.2",
|
|
178
|
+
"@playwright/test": "^1.46.0",
|
|
178
179
|
"@types/aria-query": "^5.0.4",
|
|
179
180
|
"@types/babel__generator": "^7.6.8",
|
|
180
181
|
"@types/babel__traverse": "^7.20.6",
|
|
@@ -191,7 +192,7 @@
|
|
|
191
192
|
"@types/prompts": "^2.4.9",
|
|
192
193
|
"@types/semver": "^7.5.8",
|
|
193
194
|
"@types/yargs-parser": "^21.0.3",
|
|
194
|
-
"cheerio": "1.0.0
|
|
195
|
+
"cheerio": "1.0.0",
|
|
195
196
|
"eol": "^0.9.1",
|
|
196
197
|
"expect-type": "^0.19.0",
|
|
197
198
|
"mdast-util-mdx": "^3.0.0",
|
|
@@ -205,7 +206,7 @@
|
|
|
205
206
|
"remark-code-titles": "^0.1.2",
|
|
206
207
|
"rollup": "^4.20.0",
|
|
207
208
|
"sass": "^1.77.8",
|
|
208
|
-
"undici": "^6.19.
|
|
209
|
+
"undici": "^6.19.7",
|
|
209
210
|
"unified": "^11.0.5",
|
|
210
211
|
"astro-scripts": "0.0.14"
|
|
211
212
|
},
|
package/templates/actions.mjs
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ACTION_QUERY_PARAMS,
|
|
3
|
+
ActionError,
|
|
4
|
+
deserializeActionResult,
|
|
5
|
+
getActionQueryString,
|
|
6
|
+
} from 'astro:actions';
|
|
2
7
|
|
|
3
8
|
function toActionProxy(actionCallback = {}, aggregatedPath = '') {
|
|
4
9
|
return new Proxy(actionCallback, {
|
|
@@ -16,13 +21,18 @@ function toActionProxy(actionCallback = {}, aggregatedPath = '') {
|
|
|
16
21
|
toString: () => action.queryString,
|
|
17
22
|
// Progressive enhancement info for React.
|
|
18
23
|
$$FORM_ACTION: function () {
|
|
24
|
+
const searchParams = new URLSearchParams(action.toString());
|
|
25
|
+
// Astro will redirect with a GET request by default.
|
|
26
|
+
// Disable this behavior to preserve form state
|
|
27
|
+
// for React's progressive enhancement.
|
|
28
|
+
searchParams.set(ACTION_QUERY_PARAMS.actionRedirect, 'false');
|
|
19
29
|
return {
|
|
20
30
|
method: 'POST',
|
|
21
31
|
// `name` creates a hidden input.
|
|
22
32
|
// It's unused by Astro, but we can't turn this off.
|
|
23
33
|
// At least use a name that won't conflict with a user's formData.
|
|
24
34
|
name: '_astroAction',
|
|
25
|
-
action:
|
|
35
|
+
action: '?' + searchParams.toString(),
|
|
26
36
|
};
|
|
27
37
|
},
|
|
28
38
|
// Note: `orThrow` does not have progressive enhancement info.
|