astro 4.7.1 → 4.8.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 +1 -0
- package/content-module.template.mjs +2 -0
- package/dist/@types/astro.d.ts +219 -3
- package/dist/actions/consts.d.ts +3 -0
- package/dist/actions/consts.js +8 -0
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.js +72 -0
- package/dist/actions/runtime/middleware.d.ts +7 -0
- package/dist/actions/runtime/middleware.js +38 -0
- package/dist/actions/runtime/route.d.ts +2 -0
- package/dist/actions/runtime/route.js +37 -0
- package/dist/actions/runtime/store.d.ts +6 -0
- package/dist/actions/runtime/store.js +18 -0
- package/dist/actions/runtime/utils.d.ts +4 -0
- package/dist/actions/runtime/utils.js +23 -0
- package/dist/actions/runtime/virtual/client.d.ts +4 -0
- package/dist/actions/runtime/virtual/client.js +20 -0
- package/dist/actions/runtime/virtual/server.d.ts +21 -0
- package/dist/actions/runtime/virtual/server.js +98 -0
- package/dist/actions/runtime/virtual/shared.d.ts +37 -0
- package/dist/actions/runtime/virtual/shared.js +104 -0
- package/dist/actions/utils.d.ts +2 -0
- package/dist/actions/utils.js +18 -0
- package/dist/assets/build/generate.js +1 -1
- package/dist/assets/internal.js +1 -2
- package/dist/assets/services/service.js +2 -4
- package/dist/assets/services/sharp.js +2 -4
- package/dist/assets/services/squoosh.js +2 -4
- package/dist/assets/services/vendor/squoosh/avif/avif_node_dec.js +34 -68
- package/dist/assets/services/vendor/squoosh/avif/avif_node_enc.js +39 -78
- package/dist/assets/services/vendor/squoosh/mozjpeg/mozjpeg_node_dec.js +32 -64
- package/dist/assets/services/vendor/squoosh/mozjpeg/mozjpeg_node_enc.js +32 -64
- package/dist/assets/services/vendor/squoosh/png/squoosh_png.js +2 -4
- package/dist/assets/services/vendor/squoosh/webp/webp_node_dec.js +29 -58
- package/dist/assets/services/vendor/squoosh/webp/webp_node_enc.js +29 -58
- package/dist/assets/utils/getAssetsPrefix.js +2 -4
- package/dist/assets/utils/remotePattern.js +1 -2
- package/dist/assets/utils/remoteProbe.js +1 -2
- package/dist/assets/utils/vendor/image-size/types/cur.js +1 -2
- package/dist/assets/utils/vendor/image-size/types/icns.js +1 -2
- package/dist/assets/utils/vendor/image-size/types/ico.js +2 -4
- package/dist/assets/utils/vendor/image-size/types/jp2.js +2 -4
- package/dist/assets/utils/vendor/image-size/types/utils.js +4 -8
- package/dist/assets/vite-plugin-assets.js +1 -1
- package/dist/cli/add/babel.d.ts +1 -1
- package/dist/cli/add/imports.js +4 -8
- package/dist/cli/add/index.js +23 -46
- package/dist/cli/add/wrapper.js +1 -2
- package/dist/cli/index.js +1 -2
- package/dist/cli/info/index.js +1 -2
- package/dist/cli/install-package.js +3 -6
- package/dist/cli/throw-and-exit.js +1 -2
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +2 -2
- package/dist/content/index.d.ts +1 -1
- package/dist/content/index.js +1 -7
- package/dist/content/runtime.d.ts +2 -1
- package/dist/content/runtime.js +11 -20
- package/dist/content/server-listeners.js +5 -10
- package/dist/content/types-generator.js +5 -10
- package/dist/content/utils.d.ts +0 -4
- package/dist/content/utils.js +4 -15
- package/dist/content/vite-plugin-content-assets.d.ts +1 -1
- package/dist/content/vite-plugin-content-assets.js +14 -47
- package/dist/content/vite-plugin-content-imports.js +6 -11
- package/dist/content/vite-plugin-content-virtual-mod.js +7 -14
- package/dist/core/app/index.js +11 -46
- package/dist/core/app/node.js +4 -3
- package/dist/core/app/pipeline.d.ts +7 -2
- package/dist/core/app/pipeline.js +70 -2
- package/dist/core/app/types.d.ts +1 -0
- package/dist/core/base-pipeline.d.ts +16 -1
- package/dist/core/build/generate.js +15 -61
- package/dist/core/build/index.js +2 -4
- package/dist/core/build/internal.d.ts +39 -9
- package/dist/core/build/internal.js +43 -54
- package/dist/core/build/page-data.js +6 -6
- package/dist/core/build/pipeline.d.ts +7 -3
- package/dist/core/build/pipeline.js +134 -23
- package/dist/core/build/plugins/plugin-analyzer.js +11 -32
- package/dist/core/build/plugins/plugin-content.d.ts +1 -0
- package/dist/core/build/plugins/plugin-content.js +34 -32
- package/dist/core/build/plugins/plugin-css.js +23 -51
- package/dist/core/build/plugins/plugin-manifest.js +7 -8
- package/dist/core/build/plugins/plugin-pages.d.ts +0 -1
- package/dist/core/build/plugins/plugin-pages.js +10 -12
- package/dist/core/build/plugins/plugin-ssr.js +15 -13
- package/dist/core/build/plugins/util.d.ts +26 -11
- package/dist/core/build/plugins/util.js +22 -6
- package/dist/core/build/static-build.js +30 -25
- package/dist/core/build/types.d.ts +6 -6
- package/dist/core/client-directive/build.js +1 -2
- package/dist/core/config/config.js +2 -7
- package/dist/core/config/logging.js +1 -2
- package/dist/core/config/schema.d.ts +92 -60
- package/dist/core/config/schema.js +6 -2
- package/dist/core/config/settings.js +1 -2
- package/dist/core/config/timer.js +4 -8
- package/dist/core/constants.js +1 -1
- package/dist/core/cookies/cookies.js +3 -6
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/dev/restart.js +1 -2
- package/dist/core/errors/errors-data.d.ts +24 -0
- package/dist/core/errors/errors-data.js +13 -2
- package/dist/core/errors/errors.js +1 -2
- package/dist/core/errors/overlay.js +1 -2
- package/dist/core/errors/printer.js +2 -4
- package/dist/core/errors/zod-error-map.js +2 -4
- package/dist/core/fs/index.js +2 -4
- package/dist/core/logger/vite.js +9 -18
- package/dist/core/messages.js +2 -2
- package/dist/core/middleware/callMiddleware.d.ts +3 -2
- package/dist/core/middleware/callMiddleware.js +13 -3
- package/dist/core/middleware/index.js +12 -8
- package/dist/core/middleware/sequence.js +22 -4
- package/dist/core/module-loader/vite.js +1 -2
- package/dist/core/render/params-and-props.js +2 -4
- package/dist/core/render/slots.js +4 -8
- package/dist/core/render-context.d.ts +15 -5
- package/dist/core/render-context.js +134 -28
- package/dist/core/request.js +1 -2
- package/dist/core/routing/manifest/create.js +3 -6
- package/dist/core/sync/index.js +10 -3
- package/dist/core/util.d.ts +2 -0
- package/dist/core/util.js +18 -19
- package/dist/i18n/index.js +2 -4
- package/dist/i18n/middleware.js +1 -2
- package/dist/i18n/utils.js +1 -2
- package/dist/i18n/vite-plugin-i18n.js +1 -2
- package/dist/integrations/hooks.js +5 -1
- package/dist/jsx/babel.d.ts +3 -0
- package/dist/jsx/babel.js +9 -18
- package/dist/jsx/rehype.d.ts +11 -0
- package/dist/jsx/rehype.js +197 -0
- package/dist/jsx/server.js +20 -14
- package/dist/jsx/transform-options.d.ts +3 -0
- package/dist/jsx-runtime/index.js +8 -16
- package/dist/preferences/index.js +3 -6
- package/dist/preferences/store.js +3 -6
- package/dist/prefetch/index.js +8 -16
- package/dist/prefetch/vite-plugin-prefetch.js +2 -4
- package/dist/prerender/metadata.js +1 -2
- package/dist/prerender/routing.js +1 -1
- package/dist/prerender/utils.d.ts +0 -1
- package/dist/prerender/utils.js +2 -5
- package/dist/runtime/client/dev-toolbar/apps/astro.js +5 -10
- package/dist/runtime/client/dev-toolbar/apps/audit/index.js +5 -10
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +45 -90
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.js +1 -2
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/perf.js +16 -32
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.js +2 -4
- package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +3 -6
- package/dist/runtime/client/dev-toolbar/apps/utils/highlight.js +1 -2
- package/dist/runtime/client/dev-toolbar/apps/utils/window.js +4 -8
- package/dist/runtime/client/dev-toolbar/entrypoint.js +8 -11
- package/dist/runtime/client/dev-toolbar/helpers.js +2 -4
- package/dist/runtime/client/dev-toolbar/toolbar.js +11 -22
- package/dist/runtime/client/dev-toolbar/ui-library/badge.js +1 -2
- package/dist/runtime/client/dev-toolbar/ui-library/button.d.ts +5 -0
- package/dist/runtime/client/dev-toolbar/ui-library/button.js +26 -5
- package/dist/runtime/client/dev-toolbar/ui-library/index.d.ts +1 -0
- package/dist/runtime/client/dev-toolbar/ui-library/index.js +2 -0
- package/dist/runtime/client/dev-toolbar/ui-library/radio-checkbox.d.ts +13 -0
- package/dist/runtime/client/dev-toolbar/ui-library/radio-checkbox.js +109 -0
- package/dist/runtime/client/visible.js +1 -2
- package/dist/runtime/server/astro-component.js +2 -4
- package/dist/runtime/server/astro-island.js +7 -14
- package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
- package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt.js +1 -1
- package/dist/runtime/server/index.js +3 -6
- package/dist/runtime/server/jsx.js +1 -2
- package/dist/runtime/server/render/any.js +1 -2
- package/dist/runtime/server/render/astro/instance.js +1 -2
- package/dist/runtime/server/render/astro/render.js +5 -10
- package/dist/runtime/server/render/component.js +6 -11
- package/dist/runtime/server/render/dom.js +1 -2
- package/dist/runtime/server/render/page.js +1 -2
- package/dist/runtime/server/render/script.js +1 -2
- package/dist/runtime/server/render/slot.js +1 -2
- package/dist/runtime/server/render/tags.js +2 -4
- package/dist/runtime/server/render/util.js +2 -4
- package/dist/runtime/server/shorthash.js +1 -2
- package/dist/runtime/server/transition.js +4 -8
- package/dist/runtime/server/util.js +1 -2
- package/dist/transitions/events.d.ts +3 -3
- package/dist/transitions/events.js +5 -4
- package/dist/transitions/router.js +22 -113
- package/dist/transitions/swap-functions.d.ts +12 -0
- package/dist/transitions/swap-functions.js +105 -0
- package/dist/vite-plugin-astro/compile.js +1 -2
- package/dist/vite-plugin-astro/hmr.js +5 -10
- package/dist/vite-plugin-astro/index.js +2 -4
- package/dist/vite-plugin-astro-server/pipeline.d.ts +8 -3
- package/dist/vite-plugin-astro-server/pipeline.js +59 -11
- package/dist/vite-plugin-astro-server/plugin.js +6 -6
- package/dist/vite-plugin-astro-server/response.js +1 -2
- package/dist/vite-plugin-astro-server/route.js +36 -42
- package/dist/vite-plugin-astro-server/vite.js +1 -2
- package/dist/vite-plugin-config-alias/index.js +7 -14
- package/dist/vite-plugin-head/index.js +3 -6
- package/dist/vite-plugin-html/index.js +1 -2
- package/dist/vite-plugin-html/transform/escape.js +2 -4
- package/dist/vite-plugin-html/transform/slots.js +1 -2
- package/dist/vite-plugin-html/transform/utils.js +1 -2
- package/dist/vite-plugin-inject-env-ts/index.js +37 -11
- package/dist/vite-plugin-integrations-container/index.js +3 -6
- package/dist/vite-plugin-load-fallback/index.js +1 -2
- package/dist/vite-plugin-markdown/index.js +1 -2
- package/dist/vite-plugin-mdx/index.d.ts +3 -0
- package/dist/vite-plugin-mdx/tag.d.ts +2 -0
- package/dist/vite-plugin-mdx/tag.js +3 -6
- package/dist/vite-plugin-mdx/transform-jsx.d.ts +3 -0
- package/dist/vite-plugin-mdx/transform-jsx.js +1 -2
- package/dist/vite-plugin-scanner/index.js +4 -6
- package/dist/vite-plugin-scanner/scan.js +2 -4
- package/dist/vite-plugin-scripts/page-ssr.js +3 -6
- package/package.json +18 -14
- package/templates/actions.mjs +61 -0
- package/types/actions.d.ts +3 -0
- package/types/content.d.ts +2 -2
package/client.d.ts
CHANGED
|
@@ -48,10 +48,12 @@ const collectionToRenderEntryMap = createCollectionToGlobResultMap({
|
|
|
48
48
|
contentDir,
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
const cacheEntriesByCollection = new Map();
|
|
51
52
|
export const getCollection = createGetCollection({
|
|
52
53
|
contentCollectionToEntryMap,
|
|
53
54
|
dataCollectionToEntryMap,
|
|
54
55
|
getRenderEntryImport: createGlobLookup(collectionToRenderEntryMap),
|
|
56
|
+
cacheEntriesByCollection,
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
export const getEntryBySlug = createGetEntryBySlug({
|
package/dist/@types/astro.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { MarkdownHeading, MarkdownVFile, RehypePlugins, RemarkPlugins, Rema
|
|
|
6
6
|
import type * as babel from '@babel/core';
|
|
7
7
|
import type * as rollup from 'rollup';
|
|
8
8
|
import type * as vite from 'vite';
|
|
9
|
+
import type { Accept, ActionClient, InputSchema } from '../actions/runtime/virtual/server.js';
|
|
9
10
|
import type { RemotePattern } from '../assets/utils/remotePattern.js';
|
|
10
11
|
import type { AssetsPrefix, SerializedSSRManifest } from '../core/app/types.js';
|
|
11
12
|
import type { PageBuildData } from '../core/build/types.js';
|
|
@@ -19,7 +20,7 @@ import type { AstroPreferences } from '../preferences/index.js';
|
|
|
19
20
|
import type { ToolbarAppEventTarget, ToolbarServerHelpers } from '../runtime/client/dev-toolbar/helpers.js';
|
|
20
21
|
import type { AstroDevToolbar, DevToolbarCanvas } from '../runtime/client/dev-toolbar/toolbar.js';
|
|
21
22
|
import type { Icon } from '../runtime/client/dev-toolbar/ui-library/icons.js';
|
|
22
|
-
import type { DevToolbarBadge, DevToolbarButton, DevToolbarCard, DevToolbarHighlight, DevToolbarIcon, DevToolbarSelect, DevToolbarToggle, DevToolbarTooltip, DevToolbarWindow } from '../runtime/client/dev-toolbar/ui-library/index.js';
|
|
23
|
+
import type { DevToolbarBadge, DevToolbarButton, DevToolbarCard, DevToolbarHighlight, DevToolbarIcon, DevToolbarRadioCheckbox, DevToolbarSelect, DevToolbarToggle, DevToolbarTooltip, DevToolbarWindow } from '../runtime/client/dev-toolbar/ui-library/index.js';
|
|
23
24
|
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
|
|
24
25
|
import type { TransitionBeforePreparationEvent, TransitionBeforeSwapEvent } from '../transitions/events.js';
|
|
25
26
|
import type { DeepPartial, OmitIndexSignature, Simplify } from '../type-utils.js';
|
|
@@ -165,6 +166,22 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
|
|
165
166
|
response: ResponseInit & {
|
|
166
167
|
readonly headers: Headers;
|
|
167
168
|
};
|
|
169
|
+
/**
|
|
170
|
+
* Get an action result on the server when using a form POST.
|
|
171
|
+
* Expects the action function as a parameter.
|
|
172
|
+
* Returns a type-safe result with the action data when
|
|
173
|
+
* a matching POST request is received
|
|
174
|
+
* and `undefined` otherwise.
|
|
175
|
+
*
|
|
176
|
+
* Example usage:
|
|
177
|
+
*
|
|
178
|
+
* ```typescript
|
|
179
|
+
* import { actions } from 'astro:actions';
|
|
180
|
+
*
|
|
181
|
+
* const result = await Astro.getActionResult(actions.myAction);
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
getActionResult: AstroSharedContext['getActionResult'];
|
|
168
185
|
/** Redirect to another page (**SSR Only**)
|
|
169
186
|
*
|
|
170
187
|
* Example usage:
|
|
@@ -177,6 +194,19 @@ export interface AstroGlobal<Props extends Record<string, any> = Record<string,
|
|
|
177
194
|
* [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/)
|
|
178
195
|
*/
|
|
179
196
|
redirect: AstroSharedContext['redirect'];
|
|
197
|
+
/**
|
|
198
|
+
* It rewrites to another page. As opposed to redirects, the URL won't change, and Astro will render the HTML emitted
|
|
199
|
+
* by the rewritten URL passed as argument.
|
|
200
|
+
*
|
|
201
|
+
* ## Example
|
|
202
|
+
*
|
|
203
|
+
* ```js
|
|
204
|
+
* if (pageIsNotEnabled) {
|
|
205
|
+
* return Astro.rewrite('/fallback-page')
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
rewrite: AstroSharedContext['rewrite'];
|
|
180
210
|
/**
|
|
181
211
|
* The <Astro.self /> element allows a component to reference itself recursively.
|
|
182
212
|
*
|
|
@@ -1514,7 +1544,7 @@ export interface AstroUserConfig {
|
|
|
1514
1544
|
*/
|
|
1515
1545
|
domains?: Record<string, string>;
|
|
1516
1546
|
};
|
|
1517
|
-
/**
|
|
1547
|
+
/** ! WARNING: SUBJECT TO CHANGE */
|
|
1518
1548
|
db?: Config.Database;
|
|
1519
1549
|
/**
|
|
1520
1550
|
* @docs
|
|
@@ -1561,6 +1591,104 @@ export interface AstroUserConfig {
|
|
|
1561
1591
|
* ```
|
|
1562
1592
|
*/
|
|
1563
1593
|
directRenderScript?: boolean;
|
|
1594
|
+
/**
|
|
1595
|
+
* @docs
|
|
1596
|
+
* @name experimental.actions
|
|
1597
|
+
* @type {boolean}
|
|
1598
|
+
* @default `false`
|
|
1599
|
+
* @version 4.7.0
|
|
1600
|
+
* @description
|
|
1601
|
+
*
|
|
1602
|
+
* 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:
|
|
1603
|
+
*
|
|
1604
|
+
* ```js
|
|
1605
|
+
* {
|
|
1606
|
+
* output: 'hybrid', // or 'server'
|
|
1607
|
+
* experimental: {
|
|
1608
|
+
* actions: true,
|
|
1609
|
+
* },
|
|
1610
|
+
* }
|
|
1611
|
+
* ```
|
|
1612
|
+
*
|
|
1613
|
+
* Declare all your actions in `src/actions/index.ts`. This file is the global actions handler.
|
|
1614
|
+
*
|
|
1615
|
+
* Define an action using the `defineAction()` utility from the `astro:actions` module. These accept the `handler` property to define your server-side request handler. If your action accepts arguments, apply the `input` property to validate parameters with Zod.
|
|
1616
|
+
*
|
|
1617
|
+
* 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.
|
|
1618
|
+
*
|
|
1619
|
+
* ```ts
|
|
1620
|
+
* // src/actions/index.ts
|
|
1621
|
+
* import { defineAction, z } from "astro:actions";
|
|
1622
|
+
*
|
|
1623
|
+
* export const server = {
|
|
1624
|
+
* like: defineAction({
|
|
1625
|
+
* input: z.object({ postId: z.string() }),
|
|
1626
|
+
* handler: async ({ postId }, context) => {
|
|
1627
|
+
* // update likes in db
|
|
1628
|
+
*
|
|
1629
|
+
* return likes;
|
|
1630
|
+
* },
|
|
1631
|
+
* }),
|
|
1632
|
+
* comment: defineAction({
|
|
1633
|
+
* accept: 'form',
|
|
1634
|
+
* input: z.object({
|
|
1635
|
+
* postId: z.string(),
|
|
1636
|
+
* author: z.string(),
|
|
1637
|
+
* body: z.string(),
|
|
1638
|
+
* }),
|
|
1639
|
+
* handler: async ({ postId }, context) => {
|
|
1640
|
+
* // insert comments in db
|
|
1641
|
+
*
|
|
1642
|
+
* return comment;
|
|
1643
|
+
* },
|
|
1644
|
+
* }),
|
|
1645
|
+
* };
|
|
1646
|
+
* ```
|
|
1647
|
+
*
|
|
1648
|
+
* 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:
|
|
1649
|
+
*
|
|
1650
|
+
* ```tsx "actions"
|
|
1651
|
+
* // src/components/blog.tsx
|
|
1652
|
+
* import { actions } from "astro:actions";
|
|
1653
|
+
* import { useState } from "preact/hooks";
|
|
1654
|
+
*
|
|
1655
|
+
* export function Like({ postId }: { postId: string }) {
|
|
1656
|
+
* const [likes, setLikes] = useState(0);
|
|
1657
|
+
* return (
|
|
1658
|
+
* <button
|
|
1659
|
+
* onClick={async () => {
|
|
1660
|
+
* const newLikes = await actions.like({ postId });
|
|
1661
|
+
* setLikes(newLikes);
|
|
1662
|
+
* }}
|
|
1663
|
+
* >
|
|
1664
|
+
* {likes} likes
|
|
1665
|
+
* </button>
|
|
1666
|
+
* );
|
|
1667
|
+
* }
|
|
1668
|
+
*
|
|
1669
|
+
* export function Comment({ postId }: { postId: string }) {
|
|
1670
|
+
* return (
|
|
1671
|
+
* <form
|
|
1672
|
+
* onSubmit={async (e) => {
|
|
1673
|
+
* e.preventDefault();
|
|
1674
|
+
* const formData = new FormData(e.target);
|
|
1675
|
+
* const result = await actions.blog.comment(formData);
|
|
1676
|
+
* // handle result
|
|
1677
|
+
* }}
|
|
1678
|
+
* >
|
|
1679
|
+
* <input type="hidden" name="postId" value={postId} />
|
|
1680
|
+
* <label for="author">Author</label>
|
|
1681
|
+
* <input id="author" type="text" name="author" />
|
|
1682
|
+
* <textarea rows={10} name="body"></textarea>
|
|
1683
|
+
* <button type="submit">Post</button>
|
|
1684
|
+
* </form>
|
|
1685
|
+
* );
|
|
1686
|
+
* }
|
|
1687
|
+
* ```
|
|
1688
|
+
*
|
|
1689
|
+
* 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).
|
|
1690
|
+
*/
|
|
1691
|
+
actions?: boolean;
|
|
1564
1692
|
/**
|
|
1565
1693
|
* @docs
|
|
1566
1694
|
* @name experimental.contentCollectionCache
|
|
@@ -1786,6 +1914,61 @@ export interface AstroUserConfig {
|
|
|
1786
1914
|
origin?: boolean;
|
|
1787
1915
|
};
|
|
1788
1916
|
};
|
|
1917
|
+
/**
|
|
1918
|
+
* @docs
|
|
1919
|
+
* @name experimental.rewriting
|
|
1920
|
+
* @type {boolean}
|
|
1921
|
+
* @default `false`
|
|
1922
|
+
* @version 4.8.0
|
|
1923
|
+
* @description
|
|
1924
|
+
*
|
|
1925
|
+
* Enables a routing feature for rewriting requests in Astro pages, endpoints and Astro middleware, giving you programmatic control over your routes.
|
|
1926
|
+
*
|
|
1927
|
+
* ```js
|
|
1928
|
+
* {
|
|
1929
|
+
* experimental: {
|
|
1930
|
+
* rewriting: true,
|
|
1931
|
+
* },
|
|
1932
|
+
* }
|
|
1933
|
+
* ```
|
|
1934
|
+
*
|
|
1935
|
+
* Use `Astro.rewrite` in your `.astro` files to reroute to a different page:
|
|
1936
|
+
*
|
|
1937
|
+
* ```astro "rewrite"
|
|
1938
|
+
* ---
|
|
1939
|
+
* // src/pages/dashboard.astro
|
|
1940
|
+
* if (!Astro.props.allowed) {
|
|
1941
|
+
* return Astro.rewrite("/")
|
|
1942
|
+
* }
|
|
1943
|
+
* ---
|
|
1944
|
+
* ```
|
|
1945
|
+
*
|
|
1946
|
+
* Use `context.rewrite` in your endpoint files to reroute to a different page:
|
|
1947
|
+
*
|
|
1948
|
+
* ```js
|
|
1949
|
+
* // src/pages/api.js
|
|
1950
|
+
* export function GET(ctx) {
|
|
1951
|
+
* if (!ctx.locals.allowed) {
|
|
1952
|
+
* return ctx.rewrite("/")
|
|
1953
|
+
* }
|
|
1954
|
+
* }
|
|
1955
|
+
* ```
|
|
1956
|
+
*
|
|
1957
|
+
* Use `next("/")` in your middleware file to reroute to a different page, and then call the next middleware function:
|
|
1958
|
+
*
|
|
1959
|
+
* ```js
|
|
1960
|
+
* // src/middleware.js
|
|
1961
|
+
* export function onRequest(ctx, next) {
|
|
1962
|
+
* if (!ctx.cookies.get("allowed")) {
|
|
1963
|
+
* return next("/") // new signature
|
|
1964
|
+
* }
|
|
1965
|
+
* return next();
|
|
1966
|
+
* }
|
|
1967
|
+
* ```
|
|
1968
|
+
*
|
|
1969
|
+
* For a complete overview, and to give feedback on this experimental API, see the [Rerouting RFC](https://github.com/withastro/roadmap/blob/feat/reroute/proposals/0047-rerouting.md).
|
|
1970
|
+
*/
|
|
1971
|
+
rewriting: boolean;
|
|
1789
1972
|
};
|
|
1790
1973
|
}
|
|
1791
1974
|
/**
|
|
@@ -2244,6 +2427,10 @@ interface AstroSharedContext<Props extends Record<string, any> = Record<string,
|
|
|
2244
2427
|
* A full URL object of the request URL.
|
|
2245
2428
|
*/
|
|
2246
2429
|
url: URL;
|
|
2430
|
+
/**
|
|
2431
|
+
* Get action result on the server when using a form POST.
|
|
2432
|
+
*/
|
|
2433
|
+
getActionResult: <TAccept extends Accept, TInputSchema extends InputSchema<TAccept>, TAction extends ActionClient<unknown, TAccept, TInputSchema>>(action: TAction) => Awaited<ReturnType<TAction['safe']>> | undefined;
|
|
2247
2434
|
/**
|
|
2248
2435
|
* Route parameters for this request if this is a dynamic route.
|
|
2249
2436
|
*/
|
|
@@ -2256,6 +2443,19 @@ interface AstroSharedContext<Props extends Record<string, any> = Record<string,
|
|
|
2256
2443
|
* Redirect to another page (**SSR Only**).
|
|
2257
2444
|
*/
|
|
2258
2445
|
redirect(path: string, status?: ValidRedirectStatus): Response;
|
|
2446
|
+
/**
|
|
2447
|
+
* It rewrites to another page. As opposed to redirects, the URL won't change, and Astro will render the HTML emitted
|
|
2448
|
+
* by the rerouted URL passed as argument.
|
|
2449
|
+
*
|
|
2450
|
+
* ## Example
|
|
2451
|
+
*
|
|
2452
|
+
* ```js
|
|
2453
|
+
* if (pageIsNotEnabled) {
|
|
2454
|
+
* return Astro.rewrite('/fallback-page')
|
|
2455
|
+
* }
|
|
2456
|
+
* ```
|
|
2457
|
+
*/
|
|
2458
|
+
rewrite(rewritePayload: RewritePayload): Promise<Response>;
|
|
2259
2459
|
/**
|
|
2260
2460
|
* Object accessed via Astro middleware
|
|
2261
2461
|
*/
|
|
@@ -2361,6 +2561,20 @@ export interface APIContext<Props extends Record<string, any> = Record<string, a
|
|
|
2361
2561
|
* [Reference](https://docs.astro.build/en/guides/api-reference/#contextredirect)
|
|
2362
2562
|
*/
|
|
2363
2563
|
redirect: AstroSharedContext['redirect'];
|
|
2564
|
+
/**
|
|
2565
|
+
* It reroutes to another page. As opposed to redirects, the URL won't change, and Astro will render the HTML emitted
|
|
2566
|
+
* by the rerouted URL passed as argument.
|
|
2567
|
+
*
|
|
2568
|
+
* ## Example
|
|
2569
|
+
*
|
|
2570
|
+
* ```ts
|
|
2571
|
+
* // src/pages/secret.ts
|
|
2572
|
+
* export function GET(ctx) {
|
|
2573
|
+
* return ctx.rewrite(new URL("../"), ctx.url);
|
|
2574
|
+
* }
|
|
2575
|
+
* ```
|
|
2576
|
+
*/
|
|
2577
|
+
rewrite: AstroSharedContext['rewrite'];
|
|
2364
2578
|
/**
|
|
2365
2579
|
* An object that middlewares can use to store extra information related to the request.
|
|
2366
2580
|
*
|
|
@@ -2539,7 +2753,8 @@ export interface AstroIntegration {
|
|
|
2539
2753
|
}) => void | Promise<void>;
|
|
2540
2754
|
};
|
|
2541
2755
|
}
|
|
2542
|
-
export type
|
|
2756
|
+
export type RewritePayload = string | URL | Request;
|
|
2757
|
+
export type MiddlewareNext = (rewritePayload?: RewritePayload) => Promise<Response>;
|
|
2543
2758
|
export type MiddlewareHandler = (context: APIContext, next: MiddlewareNext) => Promise<Response> | Response | Promise<void> | void;
|
|
2544
2759
|
export type AstroMiddlewareInstance = {
|
|
2545
2760
|
onRequest?: MiddlewareHandler;
|
|
@@ -2764,6 +2979,7 @@ declare global {
|
|
|
2764
2979
|
'astro-dev-toolbar-icon': DevToolbarIcon;
|
|
2765
2980
|
'astro-dev-toolbar-card': DevToolbarCard;
|
|
2766
2981
|
'astro-dev-toolbar-select': DevToolbarSelect;
|
|
2982
|
+
'astro-dev-toolbar-radio-checkbox': DevToolbarRadioCheckbox;
|
|
2767
2983
|
'astro-dev-overlay': AstroDevToolbar;
|
|
2768
2984
|
'astro-dev-overlay-window': DevToolbarWindow;
|
|
2769
2985
|
'astro-dev-overlay-plugin-canvas': DevToolbarCanvas;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { ACTIONS_TYPES_FILE, RESOLVED_VIRTUAL_MODULE_ID, VIRTUAL_MODULE_ID } from "./consts.js";
|
|
3
|
+
function astroActions() {
|
|
4
|
+
return {
|
|
5
|
+
name: VIRTUAL_MODULE_ID,
|
|
6
|
+
hooks: {
|
|
7
|
+
async "astro:config:setup"(params) {
|
|
8
|
+
const stringifiedActionsImport = JSON.stringify(
|
|
9
|
+
new URL("actions", params.config.srcDir).pathname
|
|
10
|
+
);
|
|
11
|
+
params.updateConfig({
|
|
12
|
+
vite: {
|
|
13
|
+
define: {
|
|
14
|
+
"import.meta.env.ACTIONS_PATH": stringifiedActionsImport
|
|
15
|
+
},
|
|
16
|
+
plugins: [vitePluginActions]
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
params.injectRoute({
|
|
20
|
+
pattern: "/_actions/[...path]",
|
|
21
|
+
entrypoint: "astro/actions/runtime/route.js",
|
|
22
|
+
prerender: false
|
|
23
|
+
});
|
|
24
|
+
params.addMiddleware({
|
|
25
|
+
entrypoint: "astro/actions/runtime/middleware.js",
|
|
26
|
+
order: "pre"
|
|
27
|
+
});
|
|
28
|
+
await typegen({
|
|
29
|
+
stringifiedActionsImport,
|
|
30
|
+
root: params.config.root
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const vitePluginActions = {
|
|
37
|
+
name: VIRTUAL_MODULE_ID,
|
|
38
|
+
enforce: "pre",
|
|
39
|
+
resolveId(id) {
|
|
40
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
41
|
+
return RESOLVED_VIRTUAL_MODULE_ID;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
async load(id, opts) {
|
|
45
|
+
if (id !== RESOLVED_VIRTUAL_MODULE_ID) return;
|
|
46
|
+
let code = await readFile(new URL("../../templates/actions.mjs", import.meta.url), "utf-8");
|
|
47
|
+
if (opts?.ssr) {
|
|
48
|
+
code += `
|
|
49
|
+
export * from 'astro/actions/runtime/virtual/server.js';`;
|
|
50
|
+
} else {
|
|
51
|
+
code += `
|
|
52
|
+
export * from 'astro/actions/runtime/virtual/client.js';`;
|
|
53
|
+
}
|
|
54
|
+
return code;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
async function typegen({
|
|
58
|
+
stringifiedActionsImport,
|
|
59
|
+
root
|
|
60
|
+
}) {
|
|
61
|
+
const content = `declare module "astro:actions" {
|
|
62
|
+
type Actions = typeof import(${stringifiedActionsImport})["server"];
|
|
63
|
+
|
|
64
|
+
export const actions: Actions;
|
|
65
|
+
}`;
|
|
66
|
+
const dotAstroDir = new URL(".astro/", root);
|
|
67
|
+
await mkdir(dotAstroDir, { recursive: true });
|
|
68
|
+
await writeFile(new URL(ACTIONS_TYPES_FILE, dotAstroDir), content);
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
astroActions as default
|
|
72
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { defineMiddleware } from "../../core/middleware/index.js";
|
|
2
|
+
import { ApiContextStorage } from "./store.js";
|
|
3
|
+
import { formContentTypes, getAction, hasContentType } from "./utils.js";
|
|
4
|
+
import { callSafely } from "./virtual/shared.js";
|
|
5
|
+
const onRequest = defineMiddleware(async (context, next) => {
|
|
6
|
+
const locals = context.locals;
|
|
7
|
+
const { request, url } = context;
|
|
8
|
+
const contentType = request.headers.get("Content-Type");
|
|
9
|
+
if (url.pathname.startsWith("/_actions")) return nextWithLocalsStub(next, locals);
|
|
10
|
+
if (!contentType || !hasContentType(contentType, formContentTypes))
|
|
11
|
+
return nextWithLocalsStub(next, locals);
|
|
12
|
+
const formData = await request.clone().formData();
|
|
13
|
+
const actionPath = formData.get("_astroAction");
|
|
14
|
+
if (typeof actionPath !== "string") return nextWithLocalsStub(next, locals);
|
|
15
|
+
const actionPathKeys = actionPath.replace("/_actions/", "").split(".");
|
|
16
|
+
const action = await getAction(actionPathKeys);
|
|
17
|
+
const result = await ApiContextStorage.run(context, () => callSafely(() => action(formData)));
|
|
18
|
+
const actionsInternal = {
|
|
19
|
+
getActionResult: (actionFn) => {
|
|
20
|
+
if (actionFn.toString() !== actionPath) return Promise.resolve(void 0);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(locals, "_actionsInternal", { writable: false, value: actionsInternal });
|
|
25
|
+
return next();
|
|
26
|
+
});
|
|
27
|
+
function nextWithLocalsStub(next, locals) {
|
|
28
|
+
Object.defineProperty(locals, "_actionsInternal", {
|
|
29
|
+
writable: false,
|
|
30
|
+
value: {
|
|
31
|
+
getActionResult: () => void 0
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return next();
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
onRequest
|
|
38
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ApiContextStorage } from "./store.js";
|
|
2
|
+
import { formContentTypes, getAction, hasContentType } from "./utils.js";
|
|
3
|
+
import { callSafely } from "./virtual/shared.js";
|
|
4
|
+
const POST = async (context) => {
|
|
5
|
+
const { request, url } = context;
|
|
6
|
+
const actionPathKeys = url.pathname.replace("/_actions/", "").split(".");
|
|
7
|
+
const action = await getAction(actionPathKeys);
|
|
8
|
+
const contentType = request.headers.get("Content-Type");
|
|
9
|
+
let args;
|
|
10
|
+
if (contentType && hasContentType(contentType, formContentTypes)) {
|
|
11
|
+
args = await request.clone().formData();
|
|
12
|
+
} else if (contentType && hasContentType(contentType, ["application/json"])) {
|
|
13
|
+
args = await request.clone().json();
|
|
14
|
+
} else {
|
|
15
|
+
return new Response(null, { status: 415 });
|
|
16
|
+
}
|
|
17
|
+
const result = await ApiContextStorage.run(context, () => callSafely(() => action(args)));
|
|
18
|
+
if (result.error) {
|
|
19
|
+
if (import.meta.env.PROD) {
|
|
20
|
+
result.error.stack = void 0;
|
|
21
|
+
}
|
|
22
|
+
return new Response(JSON.stringify(result.error), {
|
|
23
|
+
status: result.error.status,
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json"
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return new Response(JSON.stringify(result.data), {
|
|
30
|
+
headers: {
|
|
31
|
+
"Content-Type": "application/json"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
POST
|
|
37
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
import type { APIContext } from '../../@types/astro.js';
|
|
4
|
+
export type ActionAPIContext = Omit<APIContext, 'getActionResult' | 'props'>;
|
|
5
|
+
export declare const ApiContextStorage: AsyncLocalStorage<ActionAPIContext>;
|
|
6
|
+
export declare function getApiContext(): ActionAPIContext;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { AstroError } from "../../core/errors/errors.js";
|
|
3
|
+
const ApiContextStorage = new AsyncLocalStorage();
|
|
4
|
+
function getApiContext() {
|
|
5
|
+
const context = ApiContextStorage.getStore();
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new AstroError({
|
|
8
|
+
name: "AstroActionError",
|
|
9
|
+
message: "Unable to get API context.",
|
|
10
|
+
hint: "If you attempted to call this action from server code, trying using `Astro.getActionResult()` instead."
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
ApiContextStorage,
|
|
17
|
+
getApiContext
|
|
18
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const formContentTypes: string[];
|
|
2
|
+
export declare function hasContentType(contentType: string, expected: string[]): boolean;
|
|
3
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
4
|
+
export declare function getAction(pathKeys: string[]): Promise<(param: unknown) => MaybePromise<unknown>>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const formContentTypes = ["application/x-www-form-urlencoded", "multipart/form-data"];
|
|
2
|
+
function hasContentType(contentType, expected) {
|
|
3
|
+
const type = contentType.split(";")[0].toLowerCase();
|
|
4
|
+
return expected.some((t) => type === t);
|
|
5
|
+
}
|
|
6
|
+
async function getAction(pathKeys) {
|
|
7
|
+
let { server: actionLookup } = await import(import.meta.env.ACTIONS_PATH);
|
|
8
|
+
for (const key of pathKeys) {
|
|
9
|
+
if (!(key in actionLookup)) {
|
|
10
|
+
throw new Error("Action not found");
|
|
11
|
+
}
|
|
12
|
+
actionLookup = actionLookup[key];
|
|
13
|
+
}
|
|
14
|
+
if (typeof actionLookup !== "function") {
|
|
15
|
+
throw new Error("Action not found");
|
|
16
|
+
}
|
|
17
|
+
return actionLookup;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
formContentTypes,
|
|
21
|
+
getAction,
|
|
22
|
+
hasContentType
|
|
23
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from "./shared.js";
|
|
2
|
+
function defineAction() {
|
|
3
|
+
throw new Error("[astro:action] `defineAction()` unexpectedly used on the client.");
|
|
4
|
+
}
|
|
5
|
+
function getApiContext() {
|
|
6
|
+
throw new Error("[astro:action] `getApiContext()` unexpectedly used on the client.");
|
|
7
|
+
}
|
|
8
|
+
const z = new Proxy(
|
|
9
|
+
{},
|
|
10
|
+
{
|
|
11
|
+
get() {
|
|
12
|
+
throw new Error("[astro:action] `z` unexpectedly used on the client.");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
export {
|
|
17
|
+
defineAction,
|
|
18
|
+
getApiContext,
|
|
19
|
+
z
|
|
20
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type MaybePromise } from '../utils.js';
|
|
3
|
+
import { type ErrorInferenceObject, type SafeResult } from './shared.js';
|
|
4
|
+
export * from './shared.js';
|
|
5
|
+
export { z } from 'zod';
|
|
6
|
+
export { getApiContext } from '../store.js';
|
|
7
|
+
export type Accept = 'form' | 'json';
|
|
8
|
+
export type InputSchema<T extends Accept> = T extends 'form' ? z.AnyZodObject | z.ZodType<FormData> : z.ZodType;
|
|
9
|
+
type Handler<TInputSchema, TOutput> = TInputSchema extends z.ZodType ? (input: z.infer<TInputSchema>) => MaybePromise<TOutput> : (input?: any) => MaybePromise<TOutput>;
|
|
10
|
+
export type ActionClient<TOutput, TAccept extends Accept, TInputSchema extends InputSchema<TAccept> | undefined> = TInputSchema extends z.ZodType ? ((input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<Awaited<TOutput>>) & {
|
|
11
|
+
safe: (input: TAccept extends 'form' ? FormData : z.input<TInputSchema>) => Promise<SafeResult<z.input<TInputSchema> extends ErrorInferenceObject ? z.input<TInputSchema> : ErrorInferenceObject, Awaited<TOutput>>>;
|
|
12
|
+
} : ((input?: any) => Promise<Awaited<TOutput>>) & {
|
|
13
|
+
safe: (input?: any) => Promise<SafeResult<never, Awaited<TOutput>>>;
|
|
14
|
+
};
|
|
15
|
+
export declare function defineAction<TOutput, TAccept extends Accept = 'json', TInputSchema extends InputSchema<Accept> | undefined = TAccept extends 'form' ? z.ZodType<FormData> : undefined>({ accept, input: inputSchema, handler, }: {
|
|
16
|
+
input?: TInputSchema;
|
|
17
|
+
accept?: TAccept;
|
|
18
|
+
handler: Handler<TInputSchema, TOutput>;
|
|
19
|
+
}): ActionClient<TOutput, TAccept, TInputSchema>;
|
|
20
|
+
/** Transform form data to an object based on a Zod schema. */
|
|
21
|
+
export declare function formDataToObject<T extends z.AnyZodObject>(formData: FormData, schema: T): Record<string, unknown>;
|