astro 4.14.6 → 4.15.0

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 (84) hide show
  1. package/client.d.ts +7 -0
  2. package/dist/@types/astro.d.ts +40 -103
  3. package/dist/actions/integration.d.ts +8 -0
  4. package/dist/actions/integration.js +45 -0
  5. package/dist/actions/{index.d.ts → plugins.d.ts} +6 -6
  6. package/dist/actions/plugins.js +80 -0
  7. package/dist/actions/runtime/middleware.js +0 -33
  8. package/dist/actions/runtime/route.js +7 -3
  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 +0 -1
  14. package/dist/actions/runtime/virtual/server.js +1 -3
  15. package/dist/actions/runtime/virtual/shared.d.ts +0 -11
  16. package/dist/actions/runtime/virtual/shared.js +14 -15
  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/content-layer.js +12 -3
  30. package/dist/content/loaders/file.js +7 -7
  31. package/dist/content/loaders/glob.js +7 -11
  32. package/dist/content/loaders/types.d.ts +4 -2
  33. package/dist/content/runtime.js +4 -6
  34. package/dist/content/utils.d.ts +32 -16
  35. package/dist/content/utils.js +2 -1
  36. package/dist/content/vite-plugin-content-assets.js +9 -1
  37. package/dist/core/app/pipeline.d.ts +2 -2
  38. package/dist/core/app/pipeline.js +3 -3
  39. package/dist/core/app/types.d.ts +1 -0
  40. package/dist/core/base-pipeline.d.ts +7 -1
  41. package/dist/core/build/generate.js +2 -1
  42. package/dist/core/build/pipeline.d.ts +2 -1
  43. package/dist/core/build/pipeline.js +3 -3
  44. package/dist/core/build/plugins/plugin-manifest.js +2 -1
  45. package/dist/core/config/schema.d.ts +28 -17
  46. package/dist/core/config/schema.js +2 -3
  47. package/dist/core/constants.js +1 -1
  48. package/dist/core/create-vite.js +7 -0
  49. package/dist/core/dev/dev.js +1 -1
  50. package/dist/core/errors/errors-data.d.ts +5 -19
  51. package/dist/core/errors/errors-data.js +8 -15
  52. package/dist/core/messages.js +2 -2
  53. package/dist/core/render-context.js +7 -7
  54. package/dist/core/routing/rewrite.d.ts +11 -1
  55. package/dist/core/routing/rewrite.js +16 -8
  56. package/dist/core/sync/index.js +1 -1
  57. package/dist/i18n/index.d.ts +3 -2
  58. package/dist/i18n/index.js +8 -3
  59. package/dist/i18n/utils.d.ts +1 -0
  60. package/dist/i18n/utils.js +7 -0
  61. package/dist/integrations/hooks.d.ts +1 -1
  62. package/dist/integrations/hooks.js +4 -3
  63. package/dist/runtime/client/idle.js +7 -3
  64. package/dist/runtime/client/idle.prebuilt.d.ts +1 -1
  65. package/dist/runtime/client/idle.prebuilt.js +1 -1
  66. package/dist/transitions/swap-functions.d.ts +7 -0
  67. package/dist/transitions/swap-functions.js +8 -0
  68. package/dist/transitions/vite-plugin-transitions.js +1 -0
  69. package/dist/virtual-modules/i18n.d.ts +1 -1
  70. package/dist/virtual-modules/i18n.js +11 -5
  71. package/dist/virtual-modules/transitions-swap-functions.d.ts +1 -0
  72. package/dist/virtual-modules/transitions-swap-functions.js +1 -0
  73. package/dist/vite-plugin-astro-server/pipeline.d.ts +2 -2
  74. package/dist/vite-plugin-astro-server/pipeline.js +3 -3
  75. package/dist/vite-plugin-astro-server/plugin.js +3 -2
  76. package/dist/vite-plugin-markdown/content-entry-type.js +2 -2
  77. package/package.json +6 -7
  78. package/dist/actions/index.js +0 -112
  79. package/dist/cli/add/babel.d.ts +0 -19
  80. package/dist/cli/add/babel.js +0 -17
  81. package/dist/cli/add/imports.d.ts +0 -2
  82. package/dist/cli/add/imports.js +0 -30
  83. package/dist/cli/add/wrapper.d.ts +0 -2
  84. package/dist/cli/add/wrapper.js +0 -14
package/client.d.ts CHANGED
@@ -150,6 +150,9 @@ declare module 'astro:transitions/client' {
150
150
  import('./dist/virtual-modules/transitions-events.js').TransitionBeforeSwapEvent;
151
151
  export const isTransitionBeforePreparationEvent: EventModule['isTransitionBeforePreparationEvent'];
152
152
  export const isTransitionBeforeSwapEvent: EventModule['isTransitionBeforeSwapEvent'];
153
+ type TransitionSwapFunctionModule =
154
+ typeof import('./dist/virtual-modules/transitions-swap-functions.js');
155
+ export const swapFunctions: TransitionSwapFunctionModule['swapFunctions'];
153
156
  }
154
157
 
155
158
  declare module 'astro:prefetch' {
@@ -172,6 +175,10 @@ declare module 'astro:components' {
172
175
  export * from 'astro/components';
173
176
  }
174
177
 
178
+ declare module 'astro:schema' {
179
+ export * from 'astro/zod';
180
+ }
181
+
175
182
  type MD = import('./dist/@types/astro.js').MarkdownInstance<Record<string, any>>;
176
183
  interface ExportedMarkdownModuleEntities {
177
184
  frontmatter: MD['frontmatter'];
@@ -35,7 +35,7 @@ export type { AssetsPrefix, SSRManifest } from '../core/app/types.js';
35
35
  export type { AstroCookieGetOptions, AstroCookieSetOptions, AstroCookies, } from '../core/cookies/index.js';
36
36
  export interface AstroBuiltinProps {
37
37
  'client:load'?: boolean;
38
- 'client:idle'?: boolean;
38
+ 'client:idle'?: IdleRequestOptions | boolean;
39
39
  'client:media'?: string;
40
40
  'client:visible'?: ClientVisibleOptions | boolean;
41
41
  'client:only'?: boolean | string;
@@ -1531,6 +1531,42 @@ export interface AstroUserConfig {
1531
1531
  *```
1532
1532
  * */
1533
1533
  redirectToDefaultLocale?: boolean;
1534
+ /**
1535
+ * @docs
1536
+ * @name i18n.routing.fallbackType
1537
+ * @kind h4
1538
+ * @type {"redirect" | "rewrite"}
1539
+ * @default `"redirect"`
1540
+ * @version 4.15.0
1541
+ * @description
1542
+ *
1543
+ * When [`i18n.fallback`](#i18nfallback) is configured to avoid showing a 404 page for missing page routes, this option controls whether to [redirect](https://docs.astro.build/en/guides/routing/#redirects) to the fallback page, or to [rewrite](https://docs.astro.build/en/guides/routing/#rewrites) the fallback page's content in place.
1544
+ *
1545
+ * By default, Astro's i18n routing creates pages that redirect your visitors to a new destination based on your fallback configuration. The browser will refresh and show the destination address in the URL bar.
1546
+ *
1547
+ * When `i18n.routing.fallback: "rewrite"` is configured, Astro will create pages that render the contents of the fallback page on the original, requested URL.
1548
+ *
1549
+ * With the following configuration, if you have the file `src/pages/en/about.astro` but not `src/pages/fr/about.astro`, the `astro build` command will generate `dist/fr/about.html` with the same content as the `dist/en/index.html` page.
1550
+ * Your site visitor will see the English version of the page at `https://example.com/fr/about/` and will not be redirected.
1551
+ *
1552
+ * ```js
1553
+ * //astro.config.mjs
1554
+ * export default defineConfig({
1555
+ * i18n: {
1556
+ * defaultLocale: "en",
1557
+ * locales: ["en", "fr"],
1558
+ * routing: {
1559
+ * prefixDefaultLocale: false,
1560
+ * fallbackType: "rewrite",
1561
+ * },
1562
+ * fallback: {
1563
+ * fr: "en",
1564
+ * }
1565
+ * },
1566
+ * })
1567
+ * ```
1568
+ */
1569
+ fallbackType: 'redirect' | 'rewrite';
1534
1570
  /**
1535
1571
  * @name i18n.routing.strategy
1536
1572
  * @type {"pathname"}
@@ -1654,106 +1690,6 @@ export interface AstroUserConfig {
1654
1690
  * ```
1655
1691
  */
1656
1692
  directRenderScript?: boolean;
1657
- /**
1658
- * @docs
1659
- * @name experimental.actions
1660
- * @type {boolean}
1661
- * @default `false`
1662
- * @version 4.8.0
1663
- * @description
1664
- *
1665
- * Actions help you write type-safe backend functions you can call from anywhere. Enable server rendering [using the `output` property](https://docs.astro.build/en/basics/rendering-modes/#on-demand-rendered) and add the `actions` flag to the `experimental` object:
1666
- *
1667
- * ```js
1668
- * {
1669
- * output: 'hybrid', // or 'server'
1670
- * experimental: {
1671
- * actions: true,
1672
- * },
1673
- * }
1674
- * ```
1675
- *
1676
- * Declare all your actions in `src/actions/index.ts`. This file is the global actions handler.
1677
- *
1678
- * Define an action using the `defineAction()` utility from the `astro:actions` module. An action accepts the `handler` property to define your server-side request handler. If your action accepts arguments, apply the `input` property to validate parameters with Zod.
1679
- *
1680
- * This example defines two actions: `like` and `comment`. The `like` action accepts a JSON object with a `postId` string, while the `comment` action accepts [FormData](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects) with `postId`, `author`, and `body` strings. Each `handler` updates your database and return a type-safe response.
1681
- *
1682
- * ```ts
1683
- * // src/actions/index.ts
1684
- * import { defineAction, z } from "astro:actions";
1685
- *
1686
- * export const server = {
1687
- * like: defineAction({
1688
- * input: z.object({ postId: z.string() }),
1689
- * handler: async ({ postId }) => {
1690
- * // update likes in db
1691
- *
1692
- * return likes;
1693
- * },
1694
- * }),
1695
- * comment: defineAction({
1696
- * accept: 'form',
1697
- * input: z.object({
1698
- * postId: z.string(),
1699
- * author: z.string(),
1700
- * body: z.string(),
1701
- * }),
1702
- * handler: async ({ postId }) => {
1703
- * // insert comments in db
1704
- *
1705
- * return comment;
1706
- * },
1707
- * }),
1708
- * };
1709
- * ```
1710
- *
1711
- * Then, call an action from your client components using the `actions` object from `astro:actions`. You can pass a type-safe object when using JSON, or a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects) object when using `accept: 'form'` in your action definition.
1712
- *
1713
- * This example calls the `like` and `comment` actions from a React component:
1714
- *
1715
- * ```tsx "actions"
1716
- * // src/components/blog.tsx
1717
- * import { actions } from "astro:actions";
1718
- * import { useState } from "react";
1719
- *
1720
- * export function Like({ postId }: { postId: string }) {
1721
- * const [likes, setLikes] = useState(0);
1722
- * return (
1723
- * <button
1724
- * onClick={async () => {
1725
- * const newLikes = await actions.like({ postId });
1726
- * setLikes(newLikes);
1727
- * }}
1728
- * >
1729
- * {likes} likes
1730
- * </button>
1731
- * );
1732
- * }
1733
- *
1734
- * export function Comment({ postId }: { postId: string }) {
1735
- * return (
1736
- * <form
1737
- * onSubmit={async (e) => {
1738
- * e.preventDefault();
1739
- * const formData = new FormData(e.target as HTMLFormElement);
1740
- * const result = await actions.blog.comment(formData);
1741
- * // handle result
1742
- * }}
1743
- * >
1744
- * <input type="hidden" name="postId" value={postId} />
1745
- * <label htmlFor="author">Author</label>
1746
- * <input id="author" type="text" name="author" />
1747
- * <textarea rows={10} name="body"></textarea>
1748
- * <button type="submit">Post</button>
1749
- * </form>
1750
- * );
1751
- * }
1752
- * ```
1753
- *
1754
- * For a complete overview, and to give feedback on this experimental API, see the [Actions RFC](https://github.com/withastro/roadmap/blob/actions/proposals/0046-actions.md).
1755
- */
1756
- actions?: boolean;
1757
1693
  /**
1758
1694
  * @docs
1759
1695
  * @name experimental.contentCollectionCache
@@ -2303,6 +2239,7 @@ export interface RouteOptions {
2303
2239
  }
2304
2240
  /**
2305
2241
  * Resolved Astro Config
2242
+ *
2306
2243
  * Config with user settings along with all defaults filled in.
2307
2244
  */
2308
2245
  export interface AstroConfig extends AstroConfigType {
@@ -2378,7 +2315,7 @@ export interface ContentEntryType {
2378
2315
  viteId: string;
2379
2316
  }): rollup.LoadResult | Promise<rollup.LoadResult>;
2380
2317
  contentModuleTypes?: string;
2381
- getRenderFunction?(settings: AstroSettings): Promise<ContentEntryRenderFuction>;
2318
+ getRenderFunction?(config: AstroConfig): Promise<ContentEntryRenderFuction>;
2382
2319
  /**
2383
2320
  * Handle asset propagation for rendered content to avoid bleed.
2384
2321
  * Ex. MDX content can import styles and scripts, so `handlePropagation` should be true.
@@ -3016,7 +2953,7 @@ declare global {
3016
2953
  interface IntegrationHooks {
3017
2954
  'astro:config:setup': (options: {
3018
2955
  config: AstroConfig;
3019
- command: 'dev' | 'build' | 'preview';
2956
+ command: 'dev' | 'build' | 'preview' | 'sync';
3020
2957
  isRestart: boolean;
3021
2958
  updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
3022
2959
  addRenderer: (renderer: AstroRenderer) => void;
@@ -0,0 +1,8 @@
1
+ import type { AstroIntegration, AstroSettings } from '../@types/astro.js';
2
+ /**
3
+ * This integration is applied when the user is using Actions in their project.
4
+ * It will inject the necessary routes and middlewares to handle actions.
5
+ */
6
+ export default function astroIntegrationActionsRouteHandler({ settings, }: {
7
+ settings: AstroSettings;
8
+ }): 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,10 +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
- import type { AstroIntegration, AstroSettings } from '../@types/astro.js';
4
- export default function astroActions({ fs, settings, }: {
5
- fs?: typeof fsMod;
6
- settings: AstroSettings;
7
- }): AstroIntegration;
3
+ import type { AstroSettings } from '../@types/astro.js';
8
4
  /**
9
5
  * This plugin is responsible to load the known file `actions/index.js` / `actions.js`
10
6
  * If the file doesn't exist, it returns an empty object.
@@ -13,3 +9,7 @@ export default function astroActions({ fs, settings, }: {
13
9
  export declare function vitePluginUserActions({ settings }: {
14
10
  settings: AstroSettings;
15
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";
@@ -31,9 +29,6 @@ const onRequest = defineMiddleware(async (context, next) => {
31
29
  if (context.request.method === "POST" && actionName) {
32
30
  return handlePost({ context, next, actionName });
33
31
  }
34
- if (context.request.method === "POST") {
35
- return handlePostLegacy({ context, next });
36
- }
37
32
  return next();
38
33
  });
39
34
  async function renderResult({
@@ -62,12 +57,6 @@ async function handlePost({
62
57
  }) {
63
58
  const { request } = context;
64
59
  const baseAction = await getAction(actionName);
65
- if (!baseAction) {
66
- throw new AstroError({
67
- ...ActionQueryStringInvalidError,
68
- message: ActionQueryStringInvalidError.message(actionName)
69
- });
70
- }
71
60
  const contentType = request.headers.get("content-type");
72
61
  let formData;
73
62
  if (contentType && hasContentType(contentType, formContentTypes)) {
@@ -103,28 +92,6 @@ async function redirectWithResult({
103
92
  }
104
93
  return context.redirect(context.url.pathname);
105
94
  }
106
- async function handlePostLegacy({ context, next }) {
107
- const { request } = context;
108
- if (context.url.pathname.startsWith("/_actions")) return next();
109
- const contentType = request.headers.get("content-type");
110
- let formData;
111
- if (contentType && hasContentType(contentType, formContentTypes)) {
112
- formData = await request.clone().formData();
113
- }
114
- if (!formData) return next();
115
- const actionName = formData.get(ACTION_QUERY_PARAMS.actionName);
116
- if (!actionName) return next();
117
- const baseAction = await getAction(actionName);
118
- if (!baseAction) {
119
- throw new AstroError({
120
- ...ActionQueryStringInvalidError,
121
- message: ActionQueryStringInvalidError.message(actionName)
122
- });
123
- }
124
- const action = baseAction.bind(context);
125
- const actionResult = await action(formData);
126
- return redirectWithResult({ context, actionName, actionResult });
127
- }
128
95
  function isActionPayload(json) {
129
96
  if (typeof json !== "object" || json == null) return false;
130
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,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,7 +2,6 @@ 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
6
  export type ActionHandler<TInputSchema, TOutput> = TInputSchema extends z.ZodType ? (input: z.infer<TInputSchema>, context: ActionAPIContext) => MaybePromise<TOutput> : (input: any, context: ActionAPIContext) => MaybePromise<TOutput>;
8
7
  export type ActionReturnType<T extends ActionHandler<any, any>> = Awaited<ReturnType<T>>;
@@ -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,
@@ -114,6 +113,5 @@ function unwrapSchemaEffects(schema) {
114
113
  }
115
114
  export {
116
115
  defineAction,
117
- formDataToObject,
118
- z2 as z
116
+ formDataToObject
119
117
  };
@@ -39,17 +39,6 @@ export declare class ActionInputError<T extends ErrorInferenceObject> extends Ac
39
39
  }
40
40
  export declare function callSafely<TOutput>(handler: () => MaybePromise<TOutput>): Promise<SafeResult<z.ZodType, TOutput>>;
41
41
  export declare function getActionQueryString(name: string): string;
42
- /**
43
- * @deprecated You can now pass action functions
44
- * directly to the `action` attribute on a form.
45
- *
46
- * Example: `<form action={actions.like} />`
47
- */
48
- export declare function getActionProps<T extends (args: FormData) => MaybePromise<unknown>>(action: T): {
49
- readonly type: "hidden";
50
- readonly name: "_astroAction";
51
- readonly value: string;
52
- };
53
42
  export type SerializedActionResult = {
54
43
  type: 'data';
55
44
  contentType: 'application/json+devalue';
@@ -121,18 +121,6 @@ function getActionQueryString(name) {
121
121
  const searchParams = new URLSearchParams({ [_ACTION_QUERY_PARAMS.actionName]: name });
122
122
  return `?${searchParams.toString()}`;
123
123
  }
124
- function getActionProps(action) {
125
- const params = new URLSearchParams(action.toString());
126
- const actionName = params.get("_astroAction");
127
- if (!actionName) {
128
- throw new Error("Invalid actions function was passed to getActionProps()");
129
- }
130
- return {
131
- type: "hidden",
132
- name: "_astroAction",
133
- value: actionName
134
- };
135
- }
136
124
  function serializeActionResult(res) {
137
125
  if (res.error) {
138
126
  if (import.meta.env?.DEV) {
@@ -180,10 +168,22 @@ function serializeActionResult(res) {
180
168
  }
181
169
  function deserializeActionResult(res) {
182
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
+ }
183
183
  if (import.meta.env?.PROD) {
184
- return { error: ActionError.fromJson(JSON.parse(res.body)), data: void 0 };
184
+ return { error: ActionError.fromJson(json), data: void 0 };
185
185
  } else {
186
- const error = ActionError.fromJson(JSON.parse(res.body));
186
+ const error = ActionError.fromJson(json);
187
187
  error.stack = actionResultErrorStack.get();
188
188
  return {
189
189
  error,
@@ -219,7 +219,6 @@ export {
219
219
  ActionInputError,
220
220
  callSafely,
221
221
  deserializeActionResult,
222
- getActionProps,
223
222
  getActionQueryString,
224
223
  isActionError,
225
224
  isInputError,
@@ -1,6 +1,11 @@
1
+ import type fsMod from 'node:fs';
1
2
  import type { APIContext } from '../@types/astro.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;