astro 5.0.0-alpha.1 → 5.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.d.ts +8 -0
- package/dist/actions/integration.d.ts +9 -0
- package/dist/actions/integration.js +45 -0
- package/dist/actions/{index.d.ts → plugins.d.ts} +5 -6
- package/dist/actions/plugins.js +80 -0
- package/dist/actions/runtime/middleware.js +9 -41
- package/dist/actions/runtime/route.js +7 -3
- package/dist/actions/runtime/utils.d.ts +1 -1
- package/dist/actions/runtime/virtual/client.d.ts +0 -1
- package/dist/actions/runtime/virtual/client.js +1 -10
- package/dist/actions/runtime/virtual/get-action.d.ts +1 -1
- package/dist/actions/runtime/virtual/get-action.js +14 -2
- package/dist/actions/runtime/virtual/server.d.ts +2 -4
- package/dist/actions/runtime/virtual/server.js +18 -6
- package/dist/actions/runtime/virtual/shared.d.ts +2 -12
- package/dist/actions/runtime/virtual/shared.js +35 -19
- package/dist/actions/utils.d.ts +5 -0
- package/dist/actions/utils.js +40 -1
- package/dist/assets/utils/resolveImports.d.ts +1 -1
- package/dist/assets/utils/resolveImports.js +3 -1
- package/dist/cli/add/index.d.ts +8 -0
- package/dist/cli/add/index.js +60 -140
- package/dist/cli/docs/index.d.ts +1 -1
- package/dist/cli/docs/open.d.ts +2 -2
- package/dist/cli/docs/open.js +2 -2
- package/dist/cli/install-package.js +5 -5
- package/dist/container/pipeline.d.ts +2 -2
- package/dist/container/pipeline.js +3 -3
- package/dist/content/consts.d.ts +0 -1
- package/dist/content/consts.js +0 -2
- package/dist/content/content-layer.d.ts +6 -5
- package/dist/content/content-layer.js +36 -32
- package/dist/content/loaders/file.js +9 -12
- package/dist/content/loaders/glob.js +7 -11
- package/dist/content/loaders/types.d.ts +6 -2
- package/dist/content/runtime.js +4 -6
- package/dist/content/utils.d.ts +33 -17
- package/dist/content/utils.js +3 -2
- package/dist/content/vite-plugin-content-assets.js +13 -54
- package/dist/content/vite-plugin-content-virtual-mod.js +10 -3
- package/dist/core/app/pipeline.d.ts +2 -2
- package/dist/core/app/pipeline.js +3 -3
- package/dist/core/app/types.d.ts +1 -0
- package/dist/core/base-pipeline.d.ts +7 -1
- package/dist/core/build/generate.js +6 -5
- package/dist/core/build/internal.d.ts +5 -18
- package/dist/core/build/internal.js +0 -25
- package/dist/core/build/page-data.js +2 -4
- package/dist/core/build/pipeline.d.ts +2 -1
- package/dist/core/build/pipeline.js +5 -13
- package/dist/core/build/plugins/index.js +2 -7
- package/dist/core/build/plugins/plugin-analyzer.d.ts +2 -3
- package/dist/core/build/plugins/plugin-analyzer.js +5 -88
- package/dist/core/build/plugins/plugin-content.d.ts +1 -1
- package/dist/core/build/plugins/plugin-content.js +0 -1
- package/dist/core/build/plugins/plugin-css.js +5 -17
- package/dist/core/build/plugins/plugin-manifest.js +2 -11
- package/dist/core/build/plugins/plugin-pages.d.ts +1 -1
- package/dist/core/build/plugins/plugin-pages.js +0 -1
- package/dist/core/build/plugins/plugin-scripts.d.ts +1 -1
- package/dist/core/build/types.d.ts +0 -5
- package/dist/core/compile/compile.js +1 -1
- package/dist/core/config/schema.d.ts +28 -34
- package/dist/core/config/schema.js +2 -5
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/constants.js +3 -1
- package/dist/core/create-vite.js +8 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/dev/restart.js +1 -3
- package/dist/core/errors/errors-data.d.ts +8 -8
- package/dist/core/errors/errors-data.js +15 -15
- package/dist/core/messages.js +2 -2
- package/dist/core/middleware/index.js +1 -0
- package/dist/core/render/paginate.d.ts +2 -1
- package/dist/core/render/paginate.js +15 -13
- package/dist/core/render/params-and-props.d.ts +1 -0
- package/dist/core/render/params-and-props.js +3 -2
- package/dist/core/render/route-cache.d.ts +3 -2
- package/dist/core/render/route-cache.js +3 -2
- package/dist/core/render/ssr-element.d.ts +0 -4
- package/dist/core/render/ssr-element.js +0 -6
- package/dist/core/render-context.d.ts +1 -1
- package/dist/core/render-context.js +23 -14
- package/dist/core/routing/rewrite.d.ts +11 -1
- package/dist/core/routing/rewrite.js +16 -8
- package/dist/core/sync/index.js +1 -1
- package/dist/core/viteUtils.d.ts +4 -0
- package/dist/core/viteUtils.js +6 -2
- package/dist/i18n/index.d.ts +3 -2
- package/dist/i18n/index.js +8 -3
- package/dist/i18n/utils.d.ts +1 -0
- package/dist/i18n/utils.js +7 -0
- package/dist/integrations/hooks.d.ts +1 -1
- package/dist/integrations/hooks.js +4 -3
- package/dist/prefetch/index.js +1 -0
- package/dist/runtime/client/dev-toolbar/toolbar.d.ts +1 -1
- package/dist/runtime/client/dev-toolbar/toolbar.js +0 -1
- package/dist/runtime/client/idle.js +7 -3
- package/dist/runtime/client/idle.prebuilt.d.ts +1 -1
- package/dist/runtime/client/idle.prebuilt.js +1 -1
- package/dist/runtime/server/astro-global.js +2 -0
- package/dist/transitions/swap-functions.d.ts +7 -0
- package/dist/transitions/swap-functions.js +8 -0
- package/dist/transitions/vite-plugin-transitions.js +1 -0
- package/dist/types/public/config.d.ts +46 -131
- package/dist/types/public/content.d.ts +4 -0
- package/dist/types/public/context.d.ts +23 -3
- package/dist/types/public/elements.d.ts +1 -1
- package/dist/types/public/integrations.d.ts +1 -1
- package/dist/virtual-modules/i18n.d.ts +1 -1
- package/dist/virtual-modules/i18n.js +11 -5
- package/dist/virtual-modules/transitions-swap-functions.d.ts +1 -0
- package/dist/virtual-modules/transitions-swap-functions.js +1 -0
- package/dist/vite-plugin-astro/index.js +10 -10
- package/dist/vite-plugin-astro/types.d.ts +1 -1
- package/dist/vite-plugin-astro-server/pipeline.d.ts +2 -2
- package/dist/vite-plugin-astro-server/pipeline.js +4 -6
- package/dist/vite-plugin-astro-server/plugin.js +3 -2
- package/dist/vite-plugin-astro-server/route.js +2 -1
- package/dist/vite-plugin-fileurl/index.d.ts +1 -1
- package/dist/vite-plugin-fileurl/index.js +2 -1
- package/dist/vite-plugin-scanner/index.d.ts +1 -1
- package/dist/vite-plugin-scanner/index.js +0 -1
- package/package.json +15 -16
- package/templates/actions.mjs +3 -1
- package/dist/actions/index.js +0 -112
- package/dist/cli/add/babel.d.ts +0 -19
- package/dist/cli/add/babel.js +0 -17
- package/dist/cli/add/imports.d.ts +0 -2
- package/dist/cli/add/imports.js +0 -30
- package/dist/cli/add/wrapper.d.ts +0 -2
- package/dist/cli/add/wrapper.js +0 -14
- package/dist/core/build/plugins/plugin-hoisted-scripts.d.ts +0 -7
- package/dist/core/build/plugins/plugin-hoisted-scripts.js +0 -89
- package/dist/vite-plugin-astro-server/scripts.d.ts +0 -6
- package/dist/vite-plugin-astro-server/scripts.js +0 -38
package/client.d.ts
CHANGED
|
@@ -145,6 +145,9 @@ declare module 'astro:transitions/client' {
|
|
|
145
145
|
import('./dist/virtual-modules/transitions-events.js').TransitionBeforeSwapEvent;
|
|
146
146
|
export const isTransitionBeforePreparationEvent: EventModule['isTransitionBeforePreparationEvent'];
|
|
147
147
|
export const isTransitionBeforeSwapEvent: EventModule['isTransitionBeforeSwapEvent'];
|
|
148
|
+
type TransitionSwapFunctionModule =
|
|
149
|
+
typeof import('./dist/virtual-modules/transitions-swap-functions.js');
|
|
150
|
+
export const swapFunctions: TransitionSwapFunctionModule['swapFunctions'];
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
declare module 'astro:prefetch' {
|
|
@@ -167,7 +170,12 @@ declare module 'astro:components' {
|
|
|
167
170
|
export * from 'astro/components';
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
declare module 'astro:schema' {
|
|
174
|
+
export * from 'astro/zod';
|
|
175
|
+
}
|
|
176
|
+
|
|
170
177
|
type MD = import('./dist/types/public/content.js').MarkdownInstance<Record<string, any>>;
|
|
178
|
+
|
|
171
179
|
interface ExportedMarkdownModuleEntities {
|
|
172
180
|
frontmatter: MD['frontmatter'];
|
|
173
181
|
file: MD['file'];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AstroSettings } from '../types/astro.js';
|
|
2
|
+
import type { AstroIntegration } from '../types/public/integrations.js';
|
|
3
|
+
/**
|
|
4
|
+
* This integration is applied when the user is using Actions in their project.
|
|
5
|
+
* It will inject the necessary routes and middlewares to handle actions.
|
|
6
|
+
*/
|
|
7
|
+
export default function astroIntegrationActionsRouteHandler({ settings, }: {
|
|
8
|
+
settings: AstroSettings;
|
|
9
|
+
}): AstroIntegration;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ActionsWithoutServerOutputError } from "../core/errors/errors-data.js";
|
|
2
|
+
import { AstroError } from "../core/errors/errors.js";
|
|
3
|
+
import { isServerLikeOutput, viteID } from "../core/util.js";
|
|
4
|
+
import { ACTIONS_TYPES_FILE, VIRTUAL_MODULE_ID } from "./consts.js";
|
|
5
|
+
function astroIntegrationActionsRouteHandler({
|
|
6
|
+
settings
|
|
7
|
+
}) {
|
|
8
|
+
return {
|
|
9
|
+
name: VIRTUAL_MODULE_ID,
|
|
10
|
+
hooks: {
|
|
11
|
+
async "astro:config:setup"(params) {
|
|
12
|
+
params.injectRoute({
|
|
13
|
+
pattern: "/_actions/[...path]",
|
|
14
|
+
entrypoint: "astro/actions/runtime/route.js",
|
|
15
|
+
prerender: false
|
|
16
|
+
});
|
|
17
|
+
params.addMiddleware({
|
|
18
|
+
entrypoint: "astro/actions/runtime/middleware.js",
|
|
19
|
+
order: "post"
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
"astro:config:done": async (params) => {
|
|
23
|
+
if (!isServerLikeOutput(params.config)) {
|
|
24
|
+
const error = new AstroError(ActionsWithoutServerOutputError);
|
|
25
|
+
error.stack = void 0;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
const stringifiedActionsImport = JSON.stringify(
|
|
29
|
+
viteID(new URL("./actions", params.config.srcDir))
|
|
30
|
+
);
|
|
31
|
+
settings.injectedTypes.push({
|
|
32
|
+
filename: ACTIONS_TYPES_FILE,
|
|
33
|
+
content: `declare module "astro:actions" {
|
|
34
|
+
type Actions = typeof import(${stringifiedActionsImport})["server"];
|
|
35
|
+
|
|
36
|
+
export const actions: Actions;
|
|
37
|
+
}`
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
astroIntegrationActionsRouteHandler as default
|
|
45
|
+
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import fsMod from 'node:fs';
|
|
1
|
+
import type fsMod from 'node:fs';
|
|
2
2
|
import type { Plugin as VitePlugin } from 'vite';
|
|
3
3
|
import type { AstroSettings } from '../types/astro.js';
|
|
4
|
-
import type { AstroIntegration } from '../types/public/integrations.js';
|
|
5
|
-
export default function astroActions({ fs, settings, }: {
|
|
6
|
-
fs?: typeof fsMod;
|
|
7
|
-
settings: AstroSettings;
|
|
8
|
-
}): AstroIntegration;
|
|
9
4
|
/**
|
|
10
5
|
* This plugin is responsible to load the known file `actions/index.js` / `actions.js`
|
|
11
6
|
* If the file doesn't exist, it returns an empty object.
|
|
@@ -14,3 +9,7 @@ export default function astroActions({ fs, settings, }: {
|
|
|
14
9
|
export declare function vitePluginUserActions({ settings }: {
|
|
15
10
|
settings: AstroSettings;
|
|
16
11
|
}): VitePlugin;
|
|
12
|
+
export declare function vitePluginActions({ fs, settings, }: {
|
|
13
|
+
fs: typeof fsMod;
|
|
14
|
+
settings: AstroSettings;
|
|
15
|
+
}): VitePlugin;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NOOP_ACTIONS,
|
|
3
|
+
RESOLVED_VIRTUAL_INTERNAL_MODULE_ID,
|
|
4
|
+
RESOLVED_VIRTUAL_MODULE_ID,
|
|
5
|
+
VIRTUAL_INTERNAL_MODULE_ID,
|
|
6
|
+
VIRTUAL_MODULE_ID
|
|
7
|
+
} from "./consts.js";
|
|
8
|
+
import { isActionsFilePresent } from "./utils.js";
|
|
9
|
+
function vitePluginUserActions({ settings }) {
|
|
10
|
+
let resolvedActionsId;
|
|
11
|
+
return {
|
|
12
|
+
name: "@astro/plugin-actions",
|
|
13
|
+
async resolveId(id) {
|
|
14
|
+
if (id === NOOP_ACTIONS) {
|
|
15
|
+
return NOOP_ACTIONS;
|
|
16
|
+
}
|
|
17
|
+
if (id === VIRTUAL_INTERNAL_MODULE_ID) {
|
|
18
|
+
const resolvedModule = await this.resolve(
|
|
19
|
+
`${decodeURI(new URL("actions", settings.config.srcDir).pathname)}`
|
|
20
|
+
);
|
|
21
|
+
if (!resolvedModule) {
|
|
22
|
+
return NOOP_ACTIONS;
|
|
23
|
+
}
|
|
24
|
+
resolvedActionsId = resolvedModule.id;
|
|
25
|
+
return RESOLVED_VIRTUAL_INTERNAL_MODULE_ID;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
load(id) {
|
|
29
|
+
if (id === NOOP_ACTIONS) {
|
|
30
|
+
return "export const server = {}";
|
|
31
|
+
} else if (id === RESOLVED_VIRTUAL_INTERNAL_MODULE_ID) {
|
|
32
|
+
return `export { server } from '${resolvedActionsId}';`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function vitePluginActions({
|
|
38
|
+
fs,
|
|
39
|
+
settings
|
|
40
|
+
}) {
|
|
41
|
+
return {
|
|
42
|
+
name: VIRTUAL_MODULE_ID,
|
|
43
|
+
enforce: "pre",
|
|
44
|
+
resolveId(id) {
|
|
45
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
46
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
async configureServer(server) {
|
|
50
|
+
const filePresentOnStartup = await isActionsFilePresent(fs, settings.config.srcDir);
|
|
51
|
+
async function watcherCallback() {
|
|
52
|
+
const filePresent = await isActionsFilePresent(fs, settings.config.srcDir);
|
|
53
|
+
if (filePresentOnStartup !== filePresent) {
|
|
54
|
+
server.restart();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
server.watcher.on("add", watcherCallback);
|
|
58
|
+
server.watcher.on("change", watcherCallback);
|
|
59
|
+
},
|
|
60
|
+
async load(id, opts) {
|
|
61
|
+
if (id !== RESOLVED_VIRTUAL_MODULE_ID) return;
|
|
62
|
+
let code = await fs.promises.readFile(
|
|
63
|
+
new URL("../../templates/actions.mjs", import.meta.url),
|
|
64
|
+
"utf-8"
|
|
65
|
+
);
|
|
66
|
+
if (opts?.ssr) {
|
|
67
|
+
code += `
|
|
68
|
+
export * from 'astro/actions/runtime/virtual/server.js';`;
|
|
69
|
+
} else {
|
|
70
|
+
code += `
|
|
71
|
+
export * from 'astro/actions/runtime/virtual/client.js';`;
|
|
72
|
+
}
|
|
73
|
+
return code;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
vitePluginActions,
|
|
79
|
+
vitePluginUserActions
|
|
80
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { yellow } from "kleur/colors";
|
|
2
|
-
import { ActionQueryStringInvalidError } from "../../core/errors/errors-data.js";
|
|
3
|
-
import { AstroError } from "../../core/errors/errors.js";
|
|
4
2
|
import { defineMiddleware } from "../../core/middleware/index.js";
|
|
5
3
|
import { ACTION_QUERY_PARAMS } from "../consts.js";
|
|
6
4
|
import { formContentTypes, hasContentType } from "./utils.js";
|
|
@@ -9,8 +7,16 @@ import {
|
|
|
9
7
|
serializeActionResult
|
|
10
8
|
} from "./virtual/shared.js";
|
|
11
9
|
const onRequest = defineMiddleware(async (context, next) => {
|
|
10
|
+
if (context._isPrerendered) {
|
|
11
|
+
if (context.request.method === "POST") {
|
|
12
|
+
console.warn(
|
|
13
|
+
yellow("[astro:actions]"),
|
|
14
|
+
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".'
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return next();
|
|
18
|
+
}
|
|
12
19
|
const locals = context.locals;
|
|
13
|
-
const { request } = context;
|
|
14
20
|
if (locals._actionPayload) return next();
|
|
15
21
|
const actionPayload = context.cookies.get(ACTION_QUERY_PARAMS.actionPayload)?.json();
|
|
16
22
|
if (actionPayload) {
|
|
@@ -19,20 +25,10 @@ const onRequest = defineMiddleware(async (context, next) => {
|
|
|
19
25
|
}
|
|
20
26
|
return renderResult({ context, next, ...actionPayload });
|
|
21
27
|
}
|
|
22
|
-
if (import.meta.env.DEV && request.method === "POST" && request.body === null) {
|
|
23
|
-
console.warn(
|
|
24
|
-
yellow("[astro:actions]"),
|
|
25
|
-
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".'
|
|
26
|
-
);
|
|
27
|
-
return next();
|
|
28
|
-
}
|
|
29
28
|
const actionName = context.url.searchParams.get(ACTION_QUERY_PARAMS.actionName);
|
|
30
29
|
if (context.request.method === "POST" && actionName) {
|
|
31
30
|
return handlePost({ context, next, actionName });
|
|
32
31
|
}
|
|
33
|
-
if (context.request.method === "POST") {
|
|
34
|
-
return handlePostLegacy({ context, next });
|
|
35
|
-
}
|
|
36
32
|
return next();
|
|
37
33
|
});
|
|
38
34
|
async function renderResult({
|
|
@@ -61,12 +57,6 @@ async function handlePost({
|
|
|
61
57
|
}) {
|
|
62
58
|
const { request } = context;
|
|
63
59
|
const baseAction = await getAction(actionName);
|
|
64
|
-
if (!baseAction) {
|
|
65
|
-
throw new AstroError({
|
|
66
|
-
...ActionQueryStringInvalidError,
|
|
67
|
-
message: ActionQueryStringInvalidError.message(actionName)
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
60
|
const contentType = request.headers.get("content-type");
|
|
71
61
|
let formData;
|
|
72
62
|
if (contentType && hasContentType(contentType, formContentTypes)) {
|
|
@@ -102,28 +92,6 @@ async function redirectWithResult({
|
|
|
102
92
|
}
|
|
103
93
|
return context.redirect(context.url.pathname);
|
|
104
94
|
}
|
|
105
|
-
async function handlePostLegacy({ context, next }) {
|
|
106
|
-
const { request } = context;
|
|
107
|
-
if (context.url.pathname.startsWith("/_actions")) return next();
|
|
108
|
-
const contentType = request.headers.get("content-type");
|
|
109
|
-
let formData;
|
|
110
|
-
if (contentType && hasContentType(contentType, formContentTypes)) {
|
|
111
|
-
formData = await request.clone().formData();
|
|
112
|
-
}
|
|
113
|
-
if (!formData) return next();
|
|
114
|
-
const actionName = formData.get(ACTION_QUERY_PARAMS.actionName);
|
|
115
|
-
if (!actionName) return next();
|
|
116
|
-
const baseAction = await getAction(actionName);
|
|
117
|
-
if (!baseAction) {
|
|
118
|
-
throw new AstroError({
|
|
119
|
-
...ActionQueryStringInvalidError,
|
|
120
|
-
message: ActionQueryStringInvalidError.message(actionName)
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
const action = baseAction.bind(context);
|
|
124
|
-
const actionResult = await action(formData);
|
|
125
|
-
return redirectWithResult({ context, actionName, actionResult });
|
|
126
|
-
}
|
|
127
95
|
function isActionPayload(json) {
|
|
128
96
|
if (typeof json !== "object" || json == null) return false;
|
|
129
97
|
if (!("actionResult" in json) || typeof json.actionResult !== "object") return false;
|
|
@@ -3,9 +3,13 @@ import { getAction } from "./virtual/get-action.js";
|
|
|
3
3
|
import { serializeActionResult } from "./virtual/shared.js";
|
|
4
4
|
const POST = async (context) => {
|
|
5
5
|
const { request, url } = context;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
let baseAction;
|
|
7
|
+
try {
|
|
8
|
+
baseAction = await getAction(url.pathname);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
if (import.meta.env.DEV) throw e;
|
|
11
|
+
console.error(e);
|
|
12
|
+
return new Response(e instanceof Error ? e.message : null, { status: 404 });
|
|
9
13
|
}
|
|
10
14
|
const contentType = request.headers.get("Content-Type");
|
|
11
15
|
const contentLength = request.headers.get("Content-Length");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { APIContext } from '../../types/public/context.js';
|
|
2
2
|
export declare const formContentTypes: string[];
|
|
3
3
|
export declare function hasContentType(contentType: string, expected: string[]): boolean;
|
|
4
|
-
export type ActionAPIContext = Omit<APIContext, 'getActionResult' | 'callAction' | 'props'>;
|
|
4
|
+
export type ActionAPIContext = Omit<APIContext, 'getActionResult' | 'callAction' | 'props' | 'redirect'>;
|
|
5
5
|
export type MaybePromise<T> = T | Promise<T>;
|
|
6
6
|
/**
|
|
7
7
|
* Used to preserve the input schema type in the error object.
|
|
@@ -2,15 +2,6 @@ export * from "./shared.js";
|
|
|
2
2
|
function defineAction() {
|
|
3
3
|
throw new Error("[astro:action] `defineAction()` unexpectedly used on the client.");
|
|
4
4
|
}
|
|
5
|
-
const z = new Proxy(
|
|
6
|
-
{},
|
|
7
|
-
{
|
|
8
|
-
get() {
|
|
9
|
-
throw new Error("[astro:action] `z` unexpectedly used on the client.");
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
);
|
|
13
5
|
export {
|
|
14
|
-
defineAction
|
|
15
|
-
z
|
|
6
|
+
defineAction
|
|
16
7
|
};
|
|
@@ -5,4 +5,4 @@ import type { ActionAccept, ActionClient } from './server.js';
|
|
|
5
5
|
* Imports from the virtual module `astro:internal-actions`, which maps to
|
|
6
6
|
* the user's `src/actions/index.ts` file at build-time.
|
|
7
7
|
*/
|
|
8
|
-
export declare function getAction(path: string): Promise<ActionClient<unknown, ActionAccept, ZodType
|
|
8
|
+
export declare function getAction(path: string): Promise<ActionClient<unknown, ActionAccept, ZodType>>;
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { ActionNotFoundError } from "../../../core/errors/errors-data.js";
|
|
2
|
+
import { AstroError } from "../../../core/errors/errors.js";
|
|
1
3
|
async function getAction(path) {
|
|
2
4
|
const pathKeys = path.replace("/_actions/", "").split(".");
|
|
3
5
|
let { server: actionLookup } = await import("astro:internal-actions");
|
|
6
|
+
if (actionLookup == null || !(typeof actionLookup === "object")) {
|
|
7
|
+
throw new TypeError(
|
|
8
|
+
`Expected \`server\` export in actions file to be an object. Received ${typeof actionLookup}.`
|
|
9
|
+
);
|
|
10
|
+
}
|
|
4
11
|
for (const key of pathKeys) {
|
|
5
12
|
if (!(key in actionLookup)) {
|
|
6
|
-
|
|
13
|
+
throw new AstroError({
|
|
14
|
+
...ActionNotFoundError,
|
|
15
|
+
message: ActionNotFoundError.message(pathKeys.join("."))
|
|
16
|
+
});
|
|
7
17
|
}
|
|
8
18
|
actionLookup = actionLookup[key];
|
|
9
19
|
}
|
|
10
20
|
if (typeof actionLookup !== "function") {
|
|
11
|
-
|
|
21
|
+
throw new TypeError(
|
|
22
|
+
`Expected handler for action ${pathKeys.join(".")} to be a function. Received ${typeof actionLookup}.`
|
|
23
|
+
);
|
|
12
24
|
}
|
|
13
25
|
return actionLookup;
|
|
14
26
|
}
|
|
@@ -2,18 +2,16 @@ import { z } from 'zod';
|
|
|
2
2
|
import type { ActionAPIContext, ErrorInferenceObject, MaybePromise } from '../utils.js';
|
|
3
3
|
import { type SafeResult } from './shared.js';
|
|
4
4
|
export * from './shared.js';
|
|
5
|
-
export { z } from 'zod';
|
|
6
5
|
export type ActionAccept = 'form' | 'json';
|
|
7
|
-
export type ActionInputSchema<T extends ActionAccept | undefined> = T extends 'form' ? z.AnyZodObject | z.ZodType<FormData> : z.ZodType;
|
|
8
6
|
export type ActionHandler<TInputSchema, TOutput> = TInputSchema extends z.ZodType ? (input: z.infer<TInputSchema>, context: ActionAPIContext) => MaybePromise<TOutput> : (input: any, context: ActionAPIContext) => MaybePromise<TOutput>;
|
|
9
7
|
export type ActionReturnType<T extends ActionHandler<any, any>> = Awaited<ReturnType<T>>;
|
|
10
|
-
export type ActionClient<TOutput, TAccept extends ActionAccept | undefined, TInputSchema extends
|
|
8
|
+
export type ActionClient<TOutput, TAccept extends ActionAccept | undefined, TInputSchema extends z.ZodType | 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
9
|
queryString: string;
|
|
12
10
|
orThrow: (input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<Awaited<TOutput>>;
|
|
13
11
|
} : ((input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>) & {
|
|
14
12
|
orThrow: (input?: any) => Promise<Awaited<TOutput>>;
|
|
15
13
|
};
|
|
16
|
-
export declare function defineAction<TOutput, TAccept extends ActionAccept | undefined = undefined, TInputSchema extends
|
|
14
|
+
export declare function defineAction<TOutput, TAccept extends ActionAccept | undefined = undefined, TInputSchema extends z.ZodType | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
|
|
17
15
|
input?: TInputSchema;
|
|
18
16
|
accept?: TAccept;
|
|
19
17
|
handler: ActionHandler<TInputSchema, TOutput>;
|
|
@@ -3,7 +3,6 @@ import { ActionCalledFromServerError } from "../../../core/errors/errors-data.js
|
|
|
3
3
|
import { AstroError } from "../../../core/errors/errors.js";
|
|
4
4
|
import { ActionError, ActionInputError, callSafely } from "./shared.js";
|
|
5
5
|
export * from "./shared.js";
|
|
6
|
-
import { z as z2 } from "zod";
|
|
7
6
|
function defineAction({
|
|
8
7
|
accept,
|
|
9
8
|
input: inputSchema,
|
|
@@ -34,8 +33,11 @@ function getFormServerHandler(handler, inputSchema) {
|
|
|
34
33
|
message: "This action only accepts FormData."
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
|
-
if (!
|
|
38
|
-
const
|
|
36
|
+
if (!inputSchema) return await handler(unparsedInput, context);
|
|
37
|
+
const baseSchema = unwrapSchemaEffects(inputSchema);
|
|
38
|
+
const parsed = await inputSchema.safeParseAsync(
|
|
39
|
+
baseSchema instanceof z.ZodObject ? formDataToObject(unparsedInput, baseSchema) : unparsedInput
|
|
40
|
+
);
|
|
39
41
|
if (!parsed.success) {
|
|
40
42
|
throw new ActionInputError(parsed.error.issues);
|
|
41
43
|
}
|
|
@@ -59,7 +61,7 @@ function getJsonServerHandler(handler, inputSchema) {
|
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
63
|
function formDataToObject(formData, schema) {
|
|
62
|
-
const obj = {};
|
|
64
|
+
const obj = schema._def.unknownKeys === "passthrough" ? Object.fromEntries(formData.entries()) : {};
|
|
63
65
|
for (const [key, baseValidator] of Object.entries(schema.shape)) {
|
|
64
66
|
let validator = baseValidator;
|
|
65
67
|
while (validator instanceof z.ZodOptional || validator instanceof z.ZodNullable || validator instanceof z.ZodDefault) {
|
|
@@ -98,8 +100,18 @@ function handleFormDataGet(key, formData, validator, baseValidator) {
|
|
|
98
100
|
}
|
|
99
101
|
return validator instanceof z.ZodNumber ? Number(value) : value;
|
|
100
102
|
}
|
|
103
|
+
function unwrapSchemaEffects(schema) {
|
|
104
|
+
while (schema instanceof z.ZodEffects || schema instanceof z.ZodPipeline) {
|
|
105
|
+
if (schema instanceof z.ZodEffects) {
|
|
106
|
+
schema = schema._def.schema;
|
|
107
|
+
}
|
|
108
|
+
if (schema instanceof z.ZodPipeline) {
|
|
109
|
+
schema = schema._def.in;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return schema;
|
|
113
|
+
}
|
|
101
114
|
export {
|
|
102
115
|
defineAction,
|
|
103
|
-
formDataToObject
|
|
104
|
-
z2 as z
|
|
116
|
+
formDataToObject
|
|
105
117
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
|
-
import type { ErrorInferenceObject, MaybePromise } from '../utils.js';
|
|
2
|
+
import type { ErrorInferenceObject, MaybePromise, ActionAPIContext as _ActionAPIContext } from '../utils.js';
|
|
3
|
+
export type ActionAPIContext = _ActionAPIContext;
|
|
3
4
|
export declare const ACTION_QUERY_PARAMS: {
|
|
4
5
|
actionName: string;
|
|
5
6
|
actionPayload: string;
|
|
@@ -38,17 +39,6 @@ export declare class ActionInputError<T extends ErrorInferenceObject> extends Ac
|
|
|
38
39
|
}
|
|
39
40
|
export declare function callSafely<TOutput>(handler: () => MaybePromise<TOutput>): Promise<SafeResult<z.ZodType, TOutput>>;
|
|
40
41
|
export declare function getActionQueryString(name: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* @deprecated You can now pass action functions
|
|
43
|
-
* directly to the `action` attribute on a form.
|
|
44
|
-
*
|
|
45
|
-
* Example: `<form action={actions.like} />`
|
|
46
|
-
*/
|
|
47
|
-
export declare function getActionProps<T extends (args: FormData) => MaybePromise<unknown>>(action: T): {
|
|
48
|
-
readonly type: "hidden";
|
|
49
|
-
readonly name: "_astroAction";
|
|
50
|
-
readonly value: string;
|
|
51
|
-
};
|
|
52
42
|
export type SerializedActionResult = {
|
|
53
43
|
type: 'data';
|
|
54
44
|
contentType: 'application/json+devalue';
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { parse as devalueParse, stringify as devalueStringify } from "devalue";
|
|
2
|
+
import { REDIRECT_STATUS_CODES } from "../../../core/constants.js";
|
|
3
|
+
import { ActionsReturnedInvalidDataError } from "../../../core/errors/errors-data.js";
|
|
4
|
+
import { AstroError } from "../../../core/errors/errors.js";
|
|
2
5
|
import { ACTION_QUERY_PARAMS as _ACTION_QUERY_PARAMS } from "../../consts.js";
|
|
3
6
|
const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
|
|
4
7
|
const ACTION_ERROR_CODES = [
|
|
@@ -118,18 +121,6 @@ function getActionQueryString(name) {
|
|
|
118
121
|
const searchParams = new URLSearchParams({ [_ACTION_QUERY_PARAMS.actionName]: name });
|
|
119
122
|
return `?${searchParams.toString()}`;
|
|
120
123
|
}
|
|
121
|
-
function getActionProps(action) {
|
|
122
|
-
const params = new URLSearchParams(action.toString());
|
|
123
|
-
const actionName = params.get("_astroAction");
|
|
124
|
-
if (!actionName) {
|
|
125
|
-
throw new Error("Invalid actions function was passed to getActionProps()");
|
|
126
|
-
}
|
|
127
|
-
return {
|
|
128
|
-
type: "hidden",
|
|
129
|
-
name: "_astroAction",
|
|
130
|
-
value: actionName
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
124
|
function serializeActionResult(res) {
|
|
134
125
|
if (res.error) {
|
|
135
126
|
if (import.meta.env?.DEV) {
|
|
@@ -151,22 +142,48 @@ function serializeActionResult(res) {
|
|
|
151
142
|
status: 204
|
|
152
143
|
};
|
|
153
144
|
}
|
|
145
|
+
let body;
|
|
146
|
+
try {
|
|
147
|
+
body = devalueStringify(res.data, {
|
|
148
|
+
// Add support for URL objects
|
|
149
|
+
URL: (value) => value instanceof URL && value.href
|
|
150
|
+
});
|
|
151
|
+
} catch (e) {
|
|
152
|
+
let hint = ActionsReturnedInvalidDataError.hint;
|
|
153
|
+
if (res.data instanceof Response) {
|
|
154
|
+
hint = REDIRECT_STATUS_CODES.includes(res.data.status) ? "If you need to redirect when the action succeeds, trigger a redirect where the action is called. See the Actions guide for server and client redirect examples: https://docs.astro.build/en/guides/actions." : "If you need to return a Response object, try using a server endpoint instead. See https://docs.astro.build/en/guides/endpoints/#server-endpoints-api-routes";
|
|
155
|
+
}
|
|
156
|
+
throw new AstroError({
|
|
157
|
+
...ActionsReturnedInvalidDataError,
|
|
158
|
+
message: ActionsReturnedInvalidDataError.message(String(e)),
|
|
159
|
+
hint
|
|
160
|
+
});
|
|
161
|
+
}
|
|
154
162
|
return {
|
|
155
163
|
type: "data",
|
|
156
164
|
status: 200,
|
|
157
165
|
contentType: "application/json+devalue",
|
|
158
|
-
body
|
|
159
|
-
// Add support for URL objects
|
|
160
|
-
URL: (value) => value instanceof URL && value.href
|
|
161
|
-
})
|
|
166
|
+
body
|
|
162
167
|
};
|
|
163
168
|
}
|
|
164
169
|
function deserializeActionResult(res) {
|
|
165
170
|
if (res.type === "error") {
|
|
171
|
+
let json;
|
|
172
|
+
try {
|
|
173
|
+
json = JSON.parse(res.body);
|
|
174
|
+
} catch {
|
|
175
|
+
return {
|
|
176
|
+
data: void 0,
|
|
177
|
+
error: new ActionError({
|
|
178
|
+
message: res.body,
|
|
179
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
180
|
+
})
|
|
181
|
+
};
|
|
182
|
+
}
|
|
166
183
|
if (import.meta.env?.PROD) {
|
|
167
|
-
return { error: ActionError.fromJson(
|
|
184
|
+
return { error: ActionError.fromJson(json), data: void 0 };
|
|
168
185
|
} else {
|
|
169
|
-
const error = ActionError.fromJson(
|
|
186
|
+
const error = ActionError.fromJson(json);
|
|
170
187
|
error.stack = actionResultErrorStack.get();
|
|
171
188
|
return {
|
|
172
189
|
error,
|
|
@@ -202,7 +219,6 @@ export {
|
|
|
202
219
|
ActionInputError,
|
|
203
220
|
callSafely,
|
|
204
221
|
deserializeActionResult,
|
|
205
|
-
getActionProps,
|
|
206
222
|
getActionQueryString,
|
|
207
223
|
isActionError,
|
|
208
224
|
isInputError,
|
package/dist/actions/utils.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import type fsMod from 'node:fs';
|
|
1
2
|
import type { APIContext } from '../types/public/context.js';
|
|
2
3
|
import type { Locals } from './runtime/middleware.js';
|
|
3
4
|
import type { ActionAPIContext } from './runtime/utils.js';
|
|
4
5
|
export declare function hasActionPayload(locals: APIContext['locals']): locals is Locals;
|
|
5
6
|
export declare function createGetActionResult(locals: APIContext['locals']): APIContext['getActionResult'];
|
|
6
7
|
export declare function createCallAction(context: ActionAPIContext): APIContext['callAction'];
|
|
8
|
+
/**
|
|
9
|
+
* Check whether the Actions config file is present.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isActionsFilePresent(fs: typeof fsMod, srcDir: URL): Promise<boolean>;
|
package/dist/actions/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as eslexer from "es-module-lexer";
|
|
1
2
|
import { deserializeActionResult, getActionQueryString } from "./runtime/virtual/shared.js";
|
|
2
3
|
function hasActionPayload(locals) {
|
|
3
4
|
return "_actionPayload" in locals;
|
|
@@ -16,8 +17,46 @@ function createCallAction(context) {
|
|
|
16
17
|
return action(input);
|
|
17
18
|
};
|
|
18
19
|
}
|
|
20
|
+
let didInitLexer = false;
|
|
21
|
+
async function isActionsFilePresent(fs, srcDir) {
|
|
22
|
+
if (!didInitLexer) await eslexer.init;
|
|
23
|
+
const actionsFile = search(fs, srcDir);
|
|
24
|
+
if (!actionsFile) return false;
|
|
25
|
+
let contents;
|
|
26
|
+
try {
|
|
27
|
+
contents = fs.readFileSync(actionsFile, "utf-8");
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const [, exports] = eslexer.parse(contents, actionsFile.pathname);
|
|
32
|
+
for (const exp of exports) {
|
|
33
|
+
if (exp.n === "server") {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
function search(fs, srcDir) {
|
|
40
|
+
const paths = [
|
|
41
|
+
"actions.mjs",
|
|
42
|
+
"actions.js",
|
|
43
|
+
"actions.mts",
|
|
44
|
+
"actions.ts",
|
|
45
|
+
"actions/index.mjs",
|
|
46
|
+
"actions/index.js",
|
|
47
|
+
"actions/index.mts",
|
|
48
|
+
"actions/index.ts"
|
|
49
|
+
].map((p) => new URL(p, srcDir));
|
|
50
|
+
for (const file of paths) {
|
|
51
|
+
if (fs.existsSync(file)) {
|
|
52
|
+
return file;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
19
57
|
export {
|
|
20
58
|
createCallAction,
|
|
21
59
|
createGetActionResult,
|
|
22
|
-
hasActionPayload
|
|
60
|
+
hasActionPayload,
|
|
61
|
+
isActionsFilePresent
|
|
23
62
|
};
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* @param filePath The path to the file that contains the imagem relative to the site root
|
|
6
6
|
* @returns A module id of the image that can be rsolved by Vite, or undefined if it is not a local image
|
|
7
7
|
*/
|
|
8
|
-
export declare function imageSrcToImportId(imageSrc: string, filePath
|
|
8
|
+
export declare function imageSrcToImportId(imageSrc: string, filePath?: string): string | undefined;
|
|
9
9
|
export declare const importIdToSymbolName: (importId: string) => string;
|
|
@@ -12,7 +12,9 @@ function imageSrcToImportId(imageSrc, filePath) {
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
const params = new URLSearchParams(CONTENT_IMAGE_FLAG);
|
|
15
|
-
|
|
15
|
+
if (filePath) {
|
|
16
|
+
params.set("importer", filePath);
|
|
17
|
+
}
|
|
16
18
|
return `${imageSrc}?${params.toString()}`;
|
|
17
19
|
}
|
|
18
20
|
const importIdToSymbolName = (importId) => `__ASTRO_IMAGE_IMPORT_${shorthash(importId)}`;
|
package/dist/cli/add/index.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import { type ProxifiedModule } from 'magicast';
|
|
1
2
|
import { type Flags } from '../flags.js';
|
|
2
3
|
interface AddOptions {
|
|
3
4
|
flags: Flags;
|
|
4
5
|
}
|
|
6
|
+
interface IntegrationInfo {
|
|
7
|
+
id: string;
|
|
8
|
+
packageName: string;
|
|
9
|
+
dependencies: [name: string, version: string][];
|
|
10
|
+
type: 'integration' | 'adapter';
|
|
11
|
+
}
|
|
5
12
|
export declare function add(names: string[], { flags }: AddOptions): Promise<void>;
|
|
13
|
+
export declare function setAdapter(mod: ProxifiedModule<any>, adapter: IntegrationInfo): void;
|
|
6
14
|
export {};
|