mirror of
https://github.com/withastro/astro.git
synced 2025-01-06 22:10:10 -05:00
Actions: expose utility types (#11438)
* feat: expose ACTION_ERROR_CODES util * feat: expose ActionHandler util type * chore: changeset
This commit is contained in:
parent
0d6f3563a5
commit
619f07db70
4 changed files with 41 additions and 29 deletions
5
.changeset/plenty-socks-talk.md
Normal file
5
.changeset/plenty-socks-talk.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Exposes utility types from `astro:actions` for the `defineAction` handler (`ActionHandler`) and the `ActionError` code (`ActionErrorCode`).
|
|
@ -11,7 +11,11 @@ import type {
|
||||||
import type * as babel from '@babel/core';
|
import type * as babel from '@babel/core';
|
||||||
import type * as rollup from 'rollup';
|
import type * as rollup from 'rollup';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
import type { Accept, ActionClient, InputSchema } from '../actions/runtime/virtual/server.js';
|
import type {
|
||||||
|
ActionAccept,
|
||||||
|
ActionClient,
|
||||||
|
ActionInputSchema,
|
||||||
|
} from '../actions/runtime/virtual/server.js';
|
||||||
import type { RemotePattern } from '../assets/utils/remotePattern.js';
|
import type { RemotePattern } from '../assets/utils/remotePattern.js';
|
||||||
import type { AssetsPrefix, SerializedSSRManifest } from '../core/app/types.js';
|
import type { AssetsPrefix, SerializedSSRManifest } from '../core/app/types.js';
|
||||||
import type { PageBuildData } from '../core/build/types.js';
|
import type { PageBuildData } from '../core/build/types.js';
|
||||||
|
@ -2764,8 +2768,8 @@ interface AstroSharedContext<
|
||||||
* Get action result on the server when using a form POST.
|
* Get action result on the server when using a form POST.
|
||||||
*/
|
*/
|
||||||
getActionResult: <
|
getActionResult: <
|
||||||
TAccept extends Accept,
|
TAccept extends ActionAccept,
|
||||||
TInputSchema extends InputSchema<TAccept>,
|
TInputSchema extends ActionInputSchema<TAccept>,
|
||||||
TAction extends ActionClient<unknown, TAccept, TInputSchema>,
|
TAction extends ActionClient<unknown, TAccept, TInputSchema>,
|
||||||
>(
|
>(
|
||||||
action: TAction
|
action: TAction
|
||||||
|
|
|
@ -10,12 +10,12 @@ export { z } from 'zod';
|
||||||
/** @deprecated Access context from the second `handler()` parameter. */
|
/** @deprecated Access context from the second `handler()` parameter. */
|
||||||
export const getApiContext = _getApiContext;
|
export const getApiContext = _getApiContext;
|
||||||
|
|
||||||
export type Accept = 'form' | 'json';
|
export type ActionAccept = 'form' | 'json';
|
||||||
export type InputSchema<T extends Accept | undefined> = T extends 'form'
|
export type ActionInputSchema<T extends ActionAccept | undefined> = T extends 'form'
|
||||||
? z.AnyZodObject | z.ZodType<FormData>
|
? z.AnyZodObject | z.ZodType<FormData>
|
||||||
: z.ZodType;
|
: z.ZodType;
|
||||||
|
|
||||||
type Handler<TInputSchema, TOutput> = TInputSchema extends z.ZodType
|
export type ActionHandler<TInputSchema, TOutput> = TInputSchema extends z.ZodType
|
||||||
? (input: z.infer<TInputSchema>, context: ActionAPIContext) => MaybePromise<TOutput>
|
? (input: z.infer<TInputSchema>, context: ActionAPIContext) => MaybePromise<TOutput>
|
||||||
: (input: any, context: ActionAPIContext) => MaybePromise<TOutput>;
|
: (input: any, context: ActionAPIContext) => MaybePromise<TOutput>;
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ export type ActionReturnType<T extends Handler<any, any>> = Awaited<ReturnType<T
|
||||||
|
|
||||||
export type ActionClient<
|
export type ActionClient<
|
||||||
TOutput,
|
TOutput,
|
||||||
TAccept extends Accept | undefined,
|
TAccept extends ActionAccept | undefined,
|
||||||
TInputSchema extends InputSchema<TAccept> | undefined,
|
TInputSchema extends ActionInputSchema<TAccept> | undefined,
|
||||||
> = TInputSchema extends z.ZodType
|
> = TInputSchema extends z.ZodType
|
||||||
? ((
|
? ((
|
||||||
input: TAccept extends 'form' ? FormData : z.input<TInputSchema>
|
input: TAccept extends 'form' ? FormData : z.input<TInputSchema>
|
||||||
|
@ -46,8 +46,8 @@ export type ActionClient<
|
||||||
|
|
||||||
export function defineAction<
|
export function defineAction<
|
||||||
TOutput,
|
TOutput,
|
||||||
TAccept extends Accept | undefined = undefined,
|
TAccept extends ActionAccept | undefined = undefined,
|
||||||
TInputSchema extends InputSchema<Accept> | undefined = TAccept extends 'form'
|
TInputSchema extends ActionInputSchema<ActionAccept> | undefined = TAccept extends 'form'
|
||||||
? // If `input` is omitted, default to `FormData` for forms and `any` for JSON.
|
? // If `input` is omitted, default to `FormData` for forms and `any` for JSON.
|
||||||
z.ZodType<FormData>
|
z.ZodType<FormData>
|
||||||
: undefined,
|
: undefined,
|
||||||
|
@ -58,7 +58,7 @@ export function defineAction<
|
||||||
}: {
|
}: {
|
||||||
input?: TInputSchema;
|
input?: TInputSchema;
|
||||||
accept?: TAccept;
|
accept?: TAccept;
|
||||||
handler: Handler<TInputSchema, TOutput>;
|
handler: ActionHandler<TInputSchema, TOutput>;
|
||||||
}): ActionClient<TOutput, TAccept, TInputSchema> {
|
}): ActionClient<TOutput, TAccept, TInputSchema> {
|
||||||
const serverHandler =
|
const serverHandler =
|
||||||
accept === 'form'
|
accept === 'form'
|
||||||
|
@ -73,8 +73,8 @@ export function defineAction<
|
||||||
return serverHandler as ActionClient<TOutput, TAccept, TInputSchema>;
|
return serverHandler as ActionClient<TOutput, TAccept, TInputSchema>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormServerHandler<TOutput, TInputSchema extends InputSchema<'form'>>(
|
function getFormServerHandler<TOutput, TInputSchema extends ActionInputSchema<'form'>>(
|
||||||
handler: Handler<TInputSchema, TOutput>,
|
handler: ActionHandler<TInputSchema, TOutput>,
|
||||||
inputSchema?: TInputSchema
|
inputSchema?: TInputSchema
|
||||||
) {
|
) {
|
||||||
return async (unparsedInput: unknown): Promise<Awaited<TOutput>> => {
|
return async (unparsedInput: unknown): Promise<Awaited<TOutput>> => {
|
||||||
|
@ -95,8 +95,8 @@ function getFormServerHandler<TOutput, TInputSchema extends InputSchema<'form'>>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJsonServerHandler<TOutput, TInputSchema extends InputSchema<'json'>>(
|
function getJsonServerHandler<TOutput, TInputSchema extends ActionInputSchema<'json'>>(
|
||||||
handler: Handler<TInputSchema, TOutput>,
|
handler: ActionHandler<TInputSchema, TOutput>,
|
||||||
inputSchema?: TInputSchema
|
inputSchema?: TInputSchema
|
||||||
) {
|
) {
|
||||||
return async (unparsedInput: unknown): Promise<Awaited<TOutput>> => {
|
return async (unparsedInput: unknown): Promise<Awaited<TOutput>> => {
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
import type { ErrorInferenceObject, MaybePromise } from '../utils.js';
|
import type { ErrorInferenceObject, MaybePromise } from '../utils.js';
|
||||||
|
|
||||||
type ActionErrorCode =
|
export const ACTION_ERROR_CODES = [
|
||||||
| 'BAD_REQUEST'
|
'BAD_REQUEST',
|
||||||
| 'UNAUTHORIZED'
|
'UNAUTHORIZED',
|
||||||
| 'FORBIDDEN'
|
'FORBIDDEN',
|
||||||
| 'NOT_FOUND'
|
'NOT_FOUND',
|
||||||
| 'TIMEOUT'
|
'TIMEOUT',
|
||||||
| 'CONFLICT'
|
'CONFLICT',
|
||||||
| 'PRECONDITION_FAILED'
|
'PRECONDITION_FAILED',
|
||||||
| 'PAYLOAD_TOO_LARGE'
|
'PAYLOAD_TOO_LARGE',
|
||||||
| 'UNSUPPORTED_MEDIA_TYPE'
|
'UNSUPPORTED_MEDIA_TYPE',
|
||||||
| 'UNPROCESSABLE_CONTENT'
|
'UNPROCESSABLE_CONTENT',
|
||||||
| 'TOO_MANY_REQUESTS'
|
'TOO_MANY_REQUESTS',
|
||||||
| 'CLIENT_CLOSED_REQUEST'
|
'CLIENT_CLOSED_REQUEST',
|
||||||
| 'INTERNAL_SERVER_ERROR';
|
'INTERNAL_SERVER_ERROR',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type ActionErrorCode = (typeof ACTION_ERROR_CODES)[number];
|
||||||
|
|
||||||
const codeToStatusMap: Record<ActionErrorCode, number> = {
|
const codeToStatusMap: Record<ActionErrorCode, number> = {
|
||||||
// Implemented from tRPC error code table
|
// Implemented from tRPC error code table
|
||||||
|
|
Loading…
Reference in a new issue