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.
Files changed (136) hide show
  1. package/client.d.ts +8 -0
  2. package/dist/actions/integration.d.ts +9 -0
  3. package/dist/actions/integration.js +45 -0
  4. package/dist/actions/{index.d.ts → plugins.d.ts} +5 -6
  5. package/dist/actions/plugins.js +80 -0
  6. package/dist/actions/runtime/middleware.js +9 -41
  7. package/dist/actions/runtime/route.js +7 -3
  8. package/dist/actions/runtime/utils.d.ts +1 -1
  9. package/dist/actions/runtime/virtual/client.d.ts +0 -1
  10. package/dist/actions/runtime/virtual/client.js +1 -10
  11. package/dist/actions/runtime/virtual/get-action.d.ts +1 -1
  12. package/dist/actions/runtime/virtual/get-action.js +14 -2
  13. package/dist/actions/runtime/virtual/server.d.ts +2 -4
  14. package/dist/actions/runtime/virtual/server.js +18 -6
  15. package/dist/actions/runtime/virtual/shared.d.ts +2 -12
  16. package/dist/actions/runtime/virtual/shared.js +35 -19
  17. package/dist/actions/utils.d.ts +5 -0
  18. package/dist/actions/utils.js +40 -1
  19. package/dist/assets/utils/resolveImports.d.ts +1 -1
  20. package/dist/assets/utils/resolveImports.js +3 -1
  21. package/dist/cli/add/index.d.ts +8 -0
  22. package/dist/cli/add/index.js +60 -140
  23. package/dist/cli/docs/index.d.ts +1 -1
  24. package/dist/cli/docs/open.d.ts +2 -2
  25. package/dist/cli/docs/open.js +2 -2
  26. package/dist/cli/install-package.js +5 -5
  27. package/dist/container/pipeline.d.ts +2 -2
  28. package/dist/container/pipeline.js +3 -3
  29. package/dist/content/consts.d.ts +0 -1
  30. package/dist/content/consts.js +0 -2
  31. package/dist/content/content-layer.d.ts +6 -5
  32. package/dist/content/content-layer.js +36 -32
  33. package/dist/content/loaders/file.js +9 -12
  34. package/dist/content/loaders/glob.js +7 -11
  35. package/dist/content/loaders/types.d.ts +6 -2
  36. package/dist/content/runtime.js +4 -6
  37. package/dist/content/utils.d.ts +33 -17
  38. package/dist/content/utils.js +3 -2
  39. package/dist/content/vite-plugin-content-assets.js +13 -54
  40. package/dist/content/vite-plugin-content-virtual-mod.js +10 -3
  41. package/dist/core/app/pipeline.d.ts +2 -2
  42. package/dist/core/app/pipeline.js +3 -3
  43. package/dist/core/app/types.d.ts +1 -0
  44. package/dist/core/base-pipeline.d.ts +7 -1
  45. package/dist/core/build/generate.js +6 -5
  46. package/dist/core/build/internal.d.ts +5 -18
  47. package/dist/core/build/internal.js +0 -25
  48. package/dist/core/build/page-data.js +2 -4
  49. package/dist/core/build/pipeline.d.ts +2 -1
  50. package/dist/core/build/pipeline.js +5 -13
  51. package/dist/core/build/plugins/index.js +2 -7
  52. package/dist/core/build/plugins/plugin-analyzer.d.ts +2 -3
  53. package/dist/core/build/plugins/plugin-analyzer.js +5 -88
  54. package/dist/core/build/plugins/plugin-content.d.ts +1 -1
  55. package/dist/core/build/plugins/plugin-content.js +0 -1
  56. package/dist/core/build/plugins/plugin-css.js +5 -17
  57. package/dist/core/build/plugins/plugin-manifest.js +2 -11
  58. package/dist/core/build/plugins/plugin-pages.d.ts +1 -1
  59. package/dist/core/build/plugins/plugin-pages.js +0 -1
  60. package/dist/core/build/plugins/plugin-scripts.d.ts +1 -1
  61. package/dist/core/build/types.d.ts +0 -5
  62. package/dist/core/compile/compile.js +1 -1
  63. package/dist/core/config/schema.d.ts +28 -34
  64. package/dist/core/config/schema.js +2 -5
  65. package/dist/core/constants.d.ts +4 -0
  66. package/dist/core/constants.js +3 -1
  67. package/dist/core/create-vite.js +8 -1
  68. package/dist/core/dev/dev.js +1 -1
  69. package/dist/core/dev/restart.js +1 -3
  70. package/dist/core/errors/errors-data.d.ts +8 -8
  71. package/dist/core/errors/errors-data.js +15 -15
  72. package/dist/core/messages.js +2 -2
  73. package/dist/core/middleware/index.js +1 -0
  74. package/dist/core/render/paginate.d.ts +2 -1
  75. package/dist/core/render/paginate.js +15 -13
  76. package/dist/core/render/params-and-props.d.ts +1 -0
  77. package/dist/core/render/params-and-props.js +3 -2
  78. package/dist/core/render/route-cache.d.ts +3 -2
  79. package/dist/core/render/route-cache.js +3 -2
  80. package/dist/core/render/ssr-element.d.ts +0 -4
  81. package/dist/core/render/ssr-element.js +0 -6
  82. package/dist/core/render-context.d.ts +1 -1
  83. package/dist/core/render-context.js +23 -14
  84. package/dist/core/routing/rewrite.d.ts +11 -1
  85. package/dist/core/routing/rewrite.js +16 -8
  86. package/dist/core/sync/index.js +1 -1
  87. package/dist/core/viteUtils.d.ts +4 -0
  88. package/dist/core/viteUtils.js +6 -2
  89. package/dist/i18n/index.d.ts +3 -2
  90. package/dist/i18n/index.js +8 -3
  91. package/dist/i18n/utils.d.ts +1 -0
  92. package/dist/i18n/utils.js +7 -0
  93. package/dist/integrations/hooks.d.ts +1 -1
  94. package/dist/integrations/hooks.js +4 -3
  95. package/dist/prefetch/index.js +1 -0
  96. package/dist/runtime/client/dev-toolbar/toolbar.d.ts +1 -1
  97. package/dist/runtime/client/dev-toolbar/toolbar.js +0 -1
  98. package/dist/runtime/client/idle.js +7 -3
  99. package/dist/runtime/client/idle.prebuilt.d.ts +1 -1
  100. package/dist/runtime/client/idle.prebuilt.js +1 -1
  101. package/dist/runtime/server/astro-global.js +2 -0
  102. package/dist/transitions/swap-functions.d.ts +7 -0
  103. package/dist/transitions/swap-functions.js +8 -0
  104. package/dist/transitions/vite-plugin-transitions.js +1 -0
  105. package/dist/types/public/config.d.ts +46 -131
  106. package/dist/types/public/content.d.ts +4 -0
  107. package/dist/types/public/context.d.ts +23 -3
  108. package/dist/types/public/elements.d.ts +1 -1
  109. package/dist/types/public/integrations.d.ts +1 -1
  110. package/dist/virtual-modules/i18n.d.ts +1 -1
  111. package/dist/virtual-modules/i18n.js +11 -5
  112. package/dist/virtual-modules/transitions-swap-functions.d.ts +1 -0
  113. package/dist/virtual-modules/transitions-swap-functions.js +1 -0
  114. package/dist/vite-plugin-astro/index.js +10 -10
  115. package/dist/vite-plugin-astro/types.d.ts +1 -1
  116. package/dist/vite-plugin-astro-server/pipeline.d.ts +2 -2
  117. package/dist/vite-plugin-astro-server/pipeline.js +4 -6
  118. package/dist/vite-plugin-astro-server/plugin.js +3 -2
  119. package/dist/vite-plugin-astro-server/route.js +2 -1
  120. package/dist/vite-plugin-fileurl/index.d.ts +1 -1
  121. package/dist/vite-plugin-fileurl/index.js +2 -1
  122. package/dist/vite-plugin-scanner/index.d.ts +1 -1
  123. package/dist/vite-plugin-scanner/index.js +0 -1
  124. package/package.json +15 -16
  125. package/templates/actions.mjs +3 -1
  126. package/dist/actions/index.js +0 -112
  127. package/dist/cli/add/babel.d.ts +0 -19
  128. package/dist/cli/add/babel.js +0 -17
  129. package/dist/cli/add/imports.d.ts +0 -2
  130. package/dist/cli/add/imports.js +0 -30
  131. package/dist/cli/add/wrapper.d.ts +0 -2
  132. package/dist/cli/add/wrapper.js +0 -14
  133. package/dist/core/build/plugins/plugin-hoisted-scripts.d.ts +0 -7
  134. package/dist/core/build/plugins/plugin-hoisted-scripts.js +0 -89
  135. package/dist/vite-plugin-astro-server/scripts.d.ts +0 -6
  136. 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
- const baseAction = await getAction(url.pathname);
7
- if (!baseAction) {
8
- return new Response(null, { status: 404 });
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.
@@ -1,3 +1,2 @@
1
1
  export * from './shared.js';
2
2
  export declare function defineAction(): void;
3
- export declare const z: {};
@@ -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> | undefined>;
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
- return void 0;
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
- return void 0;
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 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>>>) & {
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 ActionInputSchema<ActionAccept> | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
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 (!(inputSchema instanceof z.ZodObject)) return await handler(unparsedInput, context);
38
- const parsed = await inputSchema.safeParseAsync(formDataToObject(unparsedInput, inputSchema));
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: devalueStringify(res.data, {
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(JSON.parse(res.body)), data: void 0 };
184
+ return { error: ActionError.fromJson(json), data: void 0 };
168
185
  } else {
169
- const error = ActionError.fromJson(JSON.parse(res.body));
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,
@@ -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>;
@@ -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: string): string | undefined;
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
- params.set("importer", filePath);
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)}`;
@@ -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 {};