From 1c3265a8c9c0b1b1bd597f756b63463146bacc3a Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 30 Jul 2024 11:42:52 -0400 Subject: [PATCH] Actions: Make `.safe()` the default return value (#11571) * feat: new orThrow types * fix: parens on return type * feat: switch implementation to orThrow() * feat(e2e): update PostComment * fix: remove callSafely from middleware * fix: toString() for actions * fix(e2e): more orThrow updates * feat: remove progressive enhancement from orThrow * fix: remove _astroActionSafe handler from react * feat(e2e): update test to use safe calling * chore: console log * chore: unused import * fix: add rewriting: true to test fixture * fix: correctly throw for server-only actions * chore: changeset * fix: update type tests * fix(test): remove .safe() chain * docs: use "patch" with BREAKING CHANGE notice * docs: clarify react integration in changeset --- .changeset/light-chairs-happen.md | 29 ++++++++++ .../actions-blog/src/components/Like.tsx | 2 +- .../src/components/PostComment.tsx | 2 +- .../actions-react-19/src/actions/index.ts | 7 +-- .../actions-react-19/src/components/Like.tsx | 4 +- packages/astro/src/@types/astro.ts | 2 +- .../astro/src/actions/runtime/middleware.ts | 10 ++-- packages/astro/src/actions/runtime/route.ts | 3 +- packages/astro/src/actions/runtime/utils.ts | 5 +- .../src/actions/runtime/virtual/server.ts | 37 +++++++------ packages/astro/templates/actions.mjs | 54 +++++++++---------- .../test/fixtures/actions/astro.config.mjs | 1 + .../actions/src/pages/subscribe.astro | 6 +-- .../astro/test/types/action-return-type.ts | 11 +++- packages/astro/test/types/is-input-error.ts | 2 +- packages/integrations/react/server.js | 13 +---- 16 files changed, 105 insertions(+), 83 deletions(-) create mode 100644 .changeset/light-chairs-happen.md diff --git a/.changeset/light-chairs-happen.md b/.changeset/light-chairs-happen.md new file mode 100644 index 000000000000..486ecd327e6b --- /dev/null +++ b/.changeset/light-chairs-happen.md @@ -0,0 +1,29 @@ +--- +'@astrojs/react': patch +'astro': patch +--- + +**BREAKING CHANGE to the experimental Actions API only.** Install the latest `@astrojs/react` integration as well if you're using React 19 features. + +Make `.safe()` the default return value for actions. This means `{ data, error }` will be returned when calling an action directly. If you prefer to get the data while allowing errors to throw, chain the `.orThrow()` modifier. + +```ts +import { actions } from 'astro:actions'; + +// Before +const { data, error } = await actions.like.safe(); +// After +const { data, error } = await actions.like(); + +// Before +const newLikes = await actions.like(); +// After +const newLikes = await actions.like.orThrow(); +``` + +## Migration + +To migrate your existing action calls: + +- Remove `.safe` from existing _safe_ action calls +- Add `.orThrow` to existing _unsafe_ action calls diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx b/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx index 7d4e6a53d161..9e39d8f9c7cb 100644 --- a/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx @@ -11,7 +11,7 @@ export function Like({ postId, initial }: { postId: string; initial: number }) { disabled={pending} onClick={async () => { setPending(true); - setLikes(await actions.blog.like({ postId })); + setLikes(await actions.blog.like.orThrow({ postId })); setPending(false); }} type="submit" diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx b/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx index f73d152e12bf..b6b6bcea1c29 100644 --- a/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx @@ -21,7 +21,7 @@ export function PostComment({ e.preventDefault(); const form = e.target as HTMLFormElement; const formData = new FormData(form); - const { data, error } = await actions.blog.comment.safe(formData); + const { data, error } = await actions.blog.comment(formData); if (isInputError(error)) { return setBodyError(error.fields.body?.join(' ')); } else if (error) { diff --git a/packages/astro/e2e/fixtures/actions-react-19/src/actions/index.ts b/packages/astro/e2e/fixtures/actions-react-19/src/actions/index.ts index 39f9dcf9aab8..cd42207729cf 100644 --- a/packages/astro/e2e/fixtures/actions-react-19/src/actions/index.ts +++ b/packages/astro/e2e/fixtures/actions-react-19/src/actions/index.ts @@ -1,5 +1,5 @@ import { db, Likes, eq, sql } from 'astro:db'; -import { defineAction, getApiContext, z } from 'astro:actions'; +import { defineAction, z, type SafeResult } from 'astro:actions'; import { experimental_getActionState } from '@astrojs/react/actions'; export const server = { @@ -28,12 +28,13 @@ export const server = { handler: async ({ postId }, ctx) => { await new Promise((r) => setTimeout(r, 200)); - const state = await experimental_getActionState(ctx); + const state = await experimental_getActionState>(ctx); + const previousLikes = state.data ?? 0; const { likes } = await db .update(Likes) .set({ - likes: state + 1, + likes: previousLikes + 1, }) .where(eq(Likes.postId, postId)) .returning() diff --git a/packages/astro/e2e/fixtures/actions-react-19/src/components/Like.tsx b/packages/astro/e2e/fixtures/actions-react-19/src/components/Like.tsx index 0d2dde00916e..652ea935ab1c 100644 --- a/packages/astro/e2e/fixtures/actions-react-19/src/components/Like.tsx +++ b/packages/astro/e2e/fixtures/actions-react-19/src/components/Like.tsx @@ -16,13 +16,13 @@ export function Like({ postId, label, likes }: { postId: string; label: string; export function LikeWithActionState({ postId, label, likes: initial }: { postId: string; label: string; likes: number }) { const [likes, action] = useActionState( experimental_withState(actions.blog.likeWithActionState), - 10, + { data: initial }, ); return (
-