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.
Files changed (222) hide show
  1. package/client.d.ts +1 -0
  2. package/content-module.template.mjs +2 -0
  3. package/dist/@types/astro.d.ts +219 -3
  4. package/dist/actions/consts.d.ts +3 -0
  5. package/dist/actions/consts.js +8 -0
  6. package/dist/actions/index.d.ts +2 -0
  7. package/dist/actions/index.js +72 -0
  8. package/dist/actions/runtime/middleware.d.ts +7 -0
  9. package/dist/actions/runtime/middleware.js +38 -0
  10. package/dist/actions/runtime/route.d.ts +2 -0
  11. package/dist/actions/runtime/route.js +37 -0
  12. package/dist/actions/runtime/store.d.ts +6 -0
  13. package/dist/actions/runtime/store.js +18 -0
  14. package/dist/actions/runtime/utils.d.ts +4 -0
  15. package/dist/actions/runtime/utils.js +23 -0
  16. package/dist/actions/runtime/virtual/client.d.ts +4 -0
  17. package/dist/actions/runtime/virtual/client.js +20 -0
  18. package/dist/actions/runtime/virtual/server.d.ts +21 -0
  19. package/dist/actions/runtime/virtual/server.js +98 -0
  20. package/dist/actions/runtime/virtual/shared.d.ts +37 -0
  21. package/dist/actions/runtime/virtual/shared.js +104 -0
  22. package/dist/actions/utils.d.ts +2 -0
  23. package/dist/actions/utils.js +18 -0
  24. package/dist/assets/build/generate.js +1 -1
  25. package/dist/assets/internal.js +1 -2
  26. package/dist/assets/services/service.js +2 -4
  27. package/dist/assets/services/sharp.js +2 -4
  28. package/dist/assets/services/squoosh.js +2 -4
  29. package/dist/assets/services/vendor/squoosh/avif/avif_node_dec.js +34 -68
  30. package/dist/assets/services/vendor/squoosh/avif/avif_node_enc.js +39 -78
  31. package/dist/assets/services/vendor/squoosh/mozjpeg/mozjpeg_node_dec.js +32 -64
  32. package/dist/assets/services/vendor/squoosh/mozjpeg/mozjpeg_node_enc.js +32 -64
  33. package/dist/assets/services/vendor/squoosh/png/squoosh_png.js +2 -4
  34. package/dist/assets/services/vendor/squoosh/webp/webp_node_dec.js +29 -58
  35. package/dist/assets/services/vendor/squoosh/webp/webp_node_enc.js +29 -58
  36. package/dist/assets/utils/getAssetsPrefix.js +2 -4
  37. package/dist/assets/utils/remotePattern.js +1 -2
  38. package/dist/assets/utils/remoteProbe.js +1 -2
  39. package/dist/assets/utils/vendor/image-size/types/cur.js +1 -2
  40. package/dist/assets/utils/vendor/image-size/types/icns.js +1 -2
  41. package/dist/assets/utils/vendor/image-size/types/ico.js +2 -4
  42. package/dist/assets/utils/vendor/image-size/types/jp2.js +2 -4
  43. package/dist/assets/utils/vendor/image-size/types/utils.js +4 -8
  44. package/dist/assets/vite-plugin-assets.js +1 -1
  45. package/dist/cli/add/babel.d.ts +1 -1
  46. package/dist/cli/add/imports.js +4 -8
  47. package/dist/cli/add/index.js +23 -46
  48. package/dist/cli/add/wrapper.js +1 -2
  49. package/dist/cli/index.js +1 -2
  50. package/dist/cli/info/index.js +1 -2
  51. package/dist/cli/install-package.js +3 -6
  52. package/dist/cli/throw-and-exit.js +1 -2
  53. package/dist/config/index.d.ts +2 -2
  54. package/dist/config/index.js +2 -2
  55. package/dist/content/index.d.ts +1 -1
  56. package/dist/content/index.js +1 -7
  57. package/dist/content/runtime.d.ts +2 -1
  58. package/dist/content/runtime.js +11 -20
  59. package/dist/content/server-listeners.js +5 -10
  60. package/dist/content/types-generator.js +5 -10
  61. package/dist/content/utils.d.ts +0 -4
  62. package/dist/content/utils.js +4 -15
  63. package/dist/content/vite-plugin-content-assets.d.ts +1 -1
  64. package/dist/content/vite-plugin-content-assets.js +14 -47
  65. package/dist/content/vite-plugin-content-imports.js +6 -11
  66. package/dist/content/vite-plugin-content-virtual-mod.js +7 -14
  67. package/dist/core/app/index.js +11 -46
  68. package/dist/core/app/node.js +4 -3
  69. package/dist/core/app/pipeline.d.ts +7 -2
  70. package/dist/core/app/pipeline.js +70 -2
  71. package/dist/core/app/types.d.ts +1 -0
  72. package/dist/core/base-pipeline.d.ts +16 -1
  73. package/dist/core/build/generate.js +15 -61
  74. package/dist/core/build/index.js +2 -4
  75. package/dist/core/build/internal.d.ts +39 -9
  76. package/dist/core/build/internal.js +43 -54
  77. package/dist/core/build/page-data.js +6 -6
  78. package/dist/core/build/pipeline.d.ts +7 -3
  79. package/dist/core/build/pipeline.js +134 -23
  80. package/dist/core/build/plugins/plugin-analyzer.js +11 -32
  81. package/dist/core/build/plugins/plugin-content.d.ts +1 -0
  82. package/dist/core/build/plugins/plugin-content.js +34 -32
  83. package/dist/core/build/plugins/plugin-css.js +23 -51
  84. package/dist/core/build/plugins/plugin-manifest.js +7 -8
  85. package/dist/core/build/plugins/plugin-pages.d.ts +0 -1
  86. package/dist/core/build/plugins/plugin-pages.js +10 -12
  87. package/dist/core/build/plugins/plugin-ssr.js +15 -13
  88. package/dist/core/build/plugins/util.d.ts +26 -11
  89. package/dist/core/build/plugins/util.js +22 -6
  90. package/dist/core/build/static-build.js +30 -25
  91. package/dist/core/build/types.d.ts +6 -6
  92. package/dist/core/client-directive/build.js +1 -2
  93. package/dist/core/config/config.js +2 -7
  94. package/dist/core/config/logging.js +1 -2
  95. package/dist/core/config/schema.d.ts +92 -60
  96. package/dist/core/config/schema.js +6 -2
  97. package/dist/core/config/settings.js +1 -2
  98. package/dist/core/config/timer.js +4 -8
  99. package/dist/core/constants.js +1 -1
  100. package/dist/core/cookies/cookies.js +3 -6
  101. package/dist/core/dev/dev.js +1 -1
  102. package/dist/core/dev/restart.js +1 -2
  103. package/dist/core/errors/errors-data.d.ts +24 -0
  104. package/dist/core/errors/errors-data.js +13 -2
  105. package/dist/core/errors/errors.js +1 -2
  106. package/dist/core/errors/overlay.js +1 -2
  107. package/dist/core/errors/printer.js +2 -4
  108. package/dist/core/errors/zod-error-map.js +2 -4
  109. package/dist/core/fs/index.js +2 -4
  110. package/dist/core/logger/vite.js +9 -18
  111. package/dist/core/messages.js +2 -2
  112. package/dist/core/middleware/callMiddleware.d.ts +3 -2
  113. package/dist/core/middleware/callMiddleware.js +13 -3
  114. package/dist/core/middleware/index.js +12 -8
  115. package/dist/core/middleware/sequence.js +22 -4
  116. package/dist/core/module-loader/vite.js +1 -2
  117. package/dist/core/render/params-and-props.js +2 -4
  118. package/dist/core/render/slots.js +4 -8
  119. package/dist/core/render-context.d.ts +15 -5
  120. package/dist/core/render-context.js +134 -28
  121. package/dist/core/request.js +1 -2
  122. package/dist/core/routing/manifest/create.js +3 -6
  123. package/dist/core/sync/index.js +10 -3
  124. package/dist/core/util.d.ts +2 -0
  125. package/dist/core/util.js +18 -19
  126. package/dist/i18n/index.js +2 -4
  127. package/dist/i18n/middleware.js +1 -2
  128. package/dist/i18n/utils.js +1 -2
  129. package/dist/i18n/vite-plugin-i18n.js +1 -2
  130. package/dist/integrations/hooks.js +5 -1
  131. package/dist/jsx/babel.d.ts +3 -0
  132. package/dist/jsx/babel.js +9 -18
  133. package/dist/jsx/rehype.d.ts +11 -0
  134. package/dist/jsx/rehype.js +197 -0
  135. package/dist/jsx/server.js +20 -14
  136. package/dist/jsx/transform-options.d.ts +3 -0
  137. package/dist/jsx-runtime/index.js +8 -16
  138. package/dist/preferences/index.js +3 -6
  139. package/dist/preferences/store.js +3 -6
  140. package/dist/prefetch/index.js +8 -16
  141. package/dist/prefetch/vite-plugin-prefetch.js +2 -4
  142. package/dist/prerender/metadata.js +1 -2
  143. package/dist/prerender/routing.js +1 -1
  144. package/dist/prerender/utils.d.ts +0 -1
  145. package/dist/prerender/utils.js +2 -5
  146. package/dist/runtime/client/dev-toolbar/apps/astro.js +5 -10
  147. package/dist/runtime/client/dev-toolbar/apps/audit/index.js +5 -10
  148. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +45 -90
  149. package/dist/runtime/client/dev-toolbar/apps/audit/rules/index.js +1 -2
  150. package/dist/runtime/client/dev-toolbar/apps/audit/rules/perf.js +16 -32
  151. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-list-window.js +2 -4
  152. package/dist/runtime/client/dev-toolbar/apps/audit/ui/audit-ui.js +3 -6
  153. package/dist/runtime/client/dev-toolbar/apps/utils/highlight.js +1 -2
  154. package/dist/runtime/client/dev-toolbar/apps/utils/window.js +4 -8
  155. package/dist/runtime/client/dev-toolbar/entrypoint.js +8 -11
  156. package/dist/runtime/client/dev-toolbar/helpers.js +2 -4
  157. package/dist/runtime/client/dev-toolbar/toolbar.js +11 -22
  158. package/dist/runtime/client/dev-toolbar/ui-library/badge.js +1 -2
  159. package/dist/runtime/client/dev-toolbar/ui-library/button.d.ts +5 -0
  160. package/dist/runtime/client/dev-toolbar/ui-library/button.js +26 -5
  161. package/dist/runtime/client/dev-toolbar/ui-library/index.d.ts +1 -0
  162. package/dist/runtime/client/dev-toolbar/ui-library/index.js +2 -0
  163. package/dist/runtime/client/dev-toolbar/ui-library/radio-checkbox.d.ts +13 -0
  164. package/dist/runtime/client/dev-toolbar/ui-library/radio-checkbox.js +109 -0
  165. package/dist/runtime/client/visible.js +1 -2
  166. package/dist/runtime/server/astro-component.js +2 -4
  167. package/dist/runtime/server/astro-island.js +7 -14
  168. package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
  169. package/dist/runtime/server/astro-island.prebuilt-dev.js +1 -1
  170. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  171. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  172. package/dist/runtime/server/index.js +3 -6
  173. package/dist/runtime/server/jsx.js +1 -2
  174. package/dist/runtime/server/render/any.js +1 -2
  175. package/dist/runtime/server/render/astro/instance.js +1 -2
  176. package/dist/runtime/server/render/astro/render.js +5 -10
  177. package/dist/runtime/server/render/component.js +6 -11
  178. package/dist/runtime/server/render/dom.js +1 -2
  179. package/dist/runtime/server/render/page.js +1 -2
  180. package/dist/runtime/server/render/script.js +1 -2
  181. package/dist/runtime/server/render/slot.js +1 -2
  182. package/dist/runtime/server/render/tags.js +2 -4
  183. package/dist/runtime/server/render/util.js +2 -4
  184. package/dist/runtime/server/shorthash.js +1 -2
  185. package/dist/runtime/server/transition.js +4 -8
  186. package/dist/runtime/server/util.js +1 -2
  187. package/dist/transitions/events.d.ts +3 -3
  188. package/dist/transitions/events.js +5 -4
  189. package/dist/transitions/router.js +22 -113
  190. package/dist/transitions/swap-functions.d.ts +12 -0
  191. package/dist/transitions/swap-functions.js +105 -0
  192. package/dist/vite-plugin-astro/compile.js +1 -2
  193. package/dist/vite-plugin-astro/hmr.js +5 -10
  194. package/dist/vite-plugin-astro/index.js +2 -4
  195. package/dist/vite-plugin-astro-server/pipeline.d.ts +8 -3
  196. package/dist/vite-plugin-astro-server/pipeline.js +59 -11
  197. package/dist/vite-plugin-astro-server/plugin.js +6 -6
  198. package/dist/vite-plugin-astro-server/response.js +1 -2
  199. package/dist/vite-plugin-astro-server/route.js +36 -42
  200. package/dist/vite-plugin-astro-server/vite.js +1 -2
  201. package/dist/vite-plugin-config-alias/index.js +7 -14
  202. package/dist/vite-plugin-head/index.js +3 -6
  203. package/dist/vite-plugin-html/index.js +1 -2
  204. package/dist/vite-plugin-html/transform/escape.js +2 -4
  205. package/dist/vite-plugin-html/transform/slots.js +1 -2
  206. package/dist/vite-plugin-html/transform/utils.js +1 -2
  207. package/dist/vite-plugin-inject-env-ts/index.js +37 -11
  208. package/dist/vite-plugin-integrations-container/index.js +3 -6
  209. package/dist/vite-plugin-load-fallback/index.js +1 -2
  210. package/dist/vite-plugin-markdown/index.js +1 -2
  211. package/dist/vite-plugin-mdx/index.d.ts +3 -0
  212. package/dist/vite-plugin-mdx/tag.d.ts +2 -0
  213. package/dist/vite-plugin-mdx/tag.js +3 -6
  214. package/dist/vite-plugin-mdx/transform-jsx.d.ts +3 -0
  215. package/dist/vite-plugin-mdx/transform-jsx.js +1 -2
  216. package/dist/vite-plugin-scanner/index.js +4 -6
  217. package/dist/vite-plugin-scanner/scan.js +2 -4
  218. package/dist/vite-plugin-scripts/page-ssr.js +3 -6
  219. package/package.json +18 -14
  220. package/templates/actions.mjs +61 -0
  221. package/types/actions.d.ts +3 -0
  222. package/types/content.d.ts +2 -2
package/client.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="vite/types/import-meta.d.ts" />
2
2
  /// <reference path="./types/content.d.ts" />
3
+ /// <reference path="./types/actions.d.ts" />
3
4
 
4
5
  // eslint-disable-next-line @typescript-eslint/no-namespace
5
6
  declare namespace App {
@@ -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({
@@ -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
- /** ⚠️ WARNING: SUBJECT TO CHANGE */
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 MiddlewareNext = () => Promise<Response>;
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,3 @@
1
+ export declare const VIRTUAL_MODULE_ID = "astro:actions";
2
+ export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
3
+ export declare const ACTIONS_TYPES_FILE = "actions.d.ts";
@@ -0,0 +1,8 @@
1
+ const VIRTUAL_MODULE_ID = "astro:actions";
2
+ const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
3
+ const ACTIONS_TYPES_FILE = "actions.d.ts";
4
+ export {
5
+ ACTIONS_TYPES_FILE,
6
+ RESOLVED_VIRTUAL_MODULE_ID,
7
+ VIRTUAL_MODULE_ID
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { AstroIntegration } from '../@types/astro.js';
2
+ export default function astroActions(): AstroIntegration;
@@ -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,7 @@
1
+ import type { APIContext } from '../../@types/astro.js';
2
+ export type Locals = {
3
+ _actionsInternal: {
4
+ getActionResult: APIContext['getActionResult'];
5
+ };
6
+ };
7
+ export declare const onRequest: import("../../@types/astro.js").MiddlewareHandler;
@@ -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,2 @@
1
+ import type { APIRoute } from '../../@types/astro.js';
2
+ export declare const POST: APIRoute;
@@ -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,4 @@
1
+ export * from './shared.js';
2
+ export declare function defineAction(): void;
3
+ export declare function getApiContext(): void;
4
+ export declare const z: {};
@@ -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>;