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.
- package/client.d.ts +7 -0
- package/dist/@types/astro.d.ts +40 -103
- package/dist/actions/integration.d.ts +8 -0
- package/dist/actions/integration.js +45 -0
- package/dist/actions/{index.d.ts → plugins.d.ts} +6 -6
- package/dist/actions/plugins.js +80 -0
- package/dist/actions/runtime/middleware.js +0 -33
- package/dist/actions/runtime/route.js +7 -3
- 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 +0 -1
- package/dist/actions/runtime/virtual/server.js +1 -3
- package/dist/actions/runtime/virtual/shared.d.ts +0 -11
- package/dist/actions/runtime/virtual/shared.js +14 -15
- 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/content-layer.js +12 -3
- package/dist/content/loaders/file.js +7 -7
- package/dist/content/loaders/glob.js +7 -11
- package/dist/content/loaders/types.d.ts +4 -2
- package/dist/content/runtime.js +4 -6
- package/dist/content/utils.d.ts +32 -16
- package/dist/content/utils.js +2 -1
- package/dist/content/vite-plugin-content-assets.js +9 -1
- 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 +2 -1
- package/dist/core/build/pipeline.d.ts +2 -1
- package/dist/core/build/pipeline.js +3 -3
- package/dist/core/build/plugins/plugin-manifest.js +2 -1
- package/dist/core/config/schema.d.ts +28 -17
- package/dist/core/config/schema.js +2 -3
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +7 -0
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +5 -19
- package/dist/core/errors/errors-data.js +8 -15
- package/dist/core/messages.js +2 -2
- package/dist/core/render-context.js +7 -7
- 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/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/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/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/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-server/pipeline.d.ts +2 -2
- package/dist/vite-plugin-astro-server/pipeline.js +3 -3
- package/dist/vite-plugin-astro-server/plugin.js +3 -2
- package/dist/vite-plugin-markdown/content-entry-type.js +2 -2
- package/package.json +6 -7
- 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/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'];
|
package/dist/@types/astro.d.ts
CHANGED
|
@@ -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?(
|
|
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 {
|
|
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
|
-
|
|
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");
|
|
@@ -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,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(
|
|
184
|
+
return { error: ActionError.fromJson(json), data: void 0 };
|
|
185
185
|
} else {
|
|
186
|
-
const error = ActionError.fromJson(
|
|
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,
|
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/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>;
|
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;
|