next-action-forge 0.4.2 → 0.5.1

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.
@@ -12,7 +12,7 @@ declare function isErrorResponse<T>(response: ServerActionResponse<T>): response
12
12
 
13
13
  type InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;
14
14
  type InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;
15
- type ServerActionMiddleware<Context, Input = unknown> = (params: {
15
+ type ServerActionMiddleware$1<Context, Input = unknown> = (params: {
16
16
  context: Context;
17
17
  input: Input;
18
18
  }) => Promise<{
@@ -22,7 +22,7 @@ type ServerActionMiddleware<Context, Input = unknown> = (params: {
22
22
  }>;
23
23
 
24
24
  type SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {
25
- middlewareFns: ServerActionMiddleware<any, any>[];
25
+ middlewareFns: ServerActionMiddleware$1<any, any>[];
26
26
  inputSchema?: InputSchema;
27
27
  outputSchema?: OutputSchema;
28
28
  onError?: (error: unknown, context: {
@@ -38,7 +38,7 @@ declare class ServerActionClient<Context extends object = {}, InputSchema extend
38
38
  * Use a middleware function.
39
39
  * @param middlewareFn Middleware function
40
40
  */
41
- use<NextContext extends object>(middlewareFn: ServerActionMiddleware<Context & NextContext, InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined>): ServerActionClient<Context & NextContext, InputSchema, OutputSchema>;
41
+ use<NextContext extends object>(middlewareFn: ServerActionMiddleware$1<Context & NextContext, InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined>): ServerActionClient<Context & NextContext, InputSchema, OutputSchema>;
42
42
  /**
43
43
  * Define the input validation schema for the action.
44
44
  * @param schema Input validation schema
@@ -74,4 +74,74 @@ declare class ServerActionClient<Context extends object = {}, InputSchema extend
74
74
  }
75
75
  declare function createActionClient(): ServerActionClient<{}, undefined, undefined>;
76
76
 
77
- export { ServerActionClient, createActionClient, handleServerActionError, isErrorResponse };
77
+ /**
78
+ * Type definition for Server Action Middleware
79
+ *
80
+ * A middleware can either:
81
+ * - Return an updated context that gets merged with the existing context
82
+ * - Return an error that stops the action execution
83
+ */
84
+ type ServerActionMiddleware<Context, Input = unknown> = (params: {
85
+ context: Context;
86
+ input: Input;
87
+ }) => Promise<{
88
+ context: Context;
89
+ } | {
90
+ error: ServerActionError;
91
+ }>;
92
+ /**
93
+ * Helper for creating middleware with correct type inference for the output context.
94
+ *
95
+ * This helper solves the TypeScript type inference issue where factory functions
96
+ * that return middleware lose the context type information. By wrapping your
97
+ * middleware with this helper, you explicitly declare what context type the
98
+ * middleware will output, enabling proper type inference through the `.use()` chain.
99
+ *
100
+ * @template TOutputContext - The type of context this middleware will output
101
+ * @template TInput - The type of input data (defaults to unknown)
102
+ *
103
+ * @param middlewareFn - The middleware function that transforms context
104
+ * @returns A typed middleware function with proper type inference
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * interface AuthContext {
109
+ * userId: string;
110
+ * role: string;
111
+ * }
112
+ *
113
+ * const createAuthMiddleware = () =>
114
+ * createTypedMiddleware<AuthContext>(async ({ context, input }) => {
115
+ * const session = await getSession();
116
+ *
117
+ * if (!session) {
118
+ * return { error: { message: 'Unauthorized', code: 'AUTH_ERROR' } };
119
+ * }
120
+ *
121
+ * return {
122
+ * context: {
123
+ * userId: session.userId,
124
+ * role: session.role,
125
+ * },
126
+ * };
127
+ * });
128
+ *
129
+ * // Now TypeScript correctly infers authClient has AuthContext
130
+ * const authClient = baseClient.use(createAuthMiddleware());
131
+ *
132
+ * // And in your actions, context is properly typed
133
+ * authClient.action(async (context) => {
134
+ * const userId = context.userId; // ✅ Type-safe!
135
+ * });
136
+ * ```
137
+ */
138
+ declare function createTypedMiddleware<TOutputContext extends object, TInput = unknown>(middlewareFn: (params: {
139
+ context: any;
140
+ input: TInput;
141
+ }) => Promise<{
142
+ context: TOutputContext;
143
+ } | {
144
+ error: ServerActionError;
145
+ }>): ServerActionMiddleware<TOutputContext, TInput>;
146
+
147
+ export { ServerActionClient, type ServerActionMiddleware, createActionClient, createTypedMiddleware, handleServerActionError, isErrorResponse };
@@ -12,7 +12,7 @@ declare function isErrorResponse<T>(response: ServerActionResponse<T>): response
12
12
 
13
13
  type InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;
14
14
  type InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;
15
- type ServerActionMiddleware<Context, Input = unknown> = (params: {
15
+ type ServerActionMiddleware$1<Context, Input = unknown> = (params: {
16
16
  context: Context;
17
17
  input: Input;
18
18
  }) => Promise<{
@@ -22,7 +22,7 @@ type ServerActionMiddleware<Context, Input = unknown> = (params: {
22
22
  }>;
23
23
 
24
24
  type SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {
25
- middlewareFns: ServerActionMiddleware<any, any>[];
25
+ middlewareFns: ServerActionMiddleware$1<any, any>[];
26
26
  inputSchema?: InputSchema;
27
27
  outputSchema?: OutputSchema;
28
28
  onError?: (error: unknown, context: {
@@ -38,7 +38,7 @@ declare class ServerActionClient<Context extends object = {}, InputSchema extend
38
38
  * Use a middleware function.
39
39
  * @param middlewareFn Middleware function
40
40
  */
41
- use<NextContext extends object>(middlewareFn: ServerActionMiddleware<Context & NextContext, InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined>): ServerActionClient<Context & NextContext, InputSchema, OutputSchema>;
41
+ use<NextContext extends object>(middlewareFn: ServerActionMiddleware$1<Context & NextContext, InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined>): ServerActionClient<Context & NextContext, InputSchema, OutputSchema>;
42
42
  /**
43
43
  * Define the input validation schema for the action.
44
44
  * @param schema Input validation schema
@@ -74,4 +74,74 @@ declare class ServerActionClient<Context extends object = {}, InputSchema extend
74
74
  }
75
75
  declare function createActionClient(): ServerActionClient<{}, undefined, undefined>;
76
76
 
77
- export { ServerActionClient, createActionClient, handleServerActionError, isErrorResponse };
77
+ /**
78
+ * Type definition for Server Action Middleware
79
+ *
80
+ * A middleware can either:
81
+ * - Return an updated context that gets merged with the existing context
82
+ * - Return an error that stops the action execution
83
+ */
84
+ type ServerActionMiddleware<Context, Input = unknown> = (params: {
85
+ context: Context;
86
+ input: Input;
87
+ }) => Promise<{
88
+ context: Context;
89
+ } | {
90
+ error: ServerActionError;
91
+ }>;
92
+ /**
93
+ * Helper for creating middleware with correct type inference for the output context.
94
+ *
95
+ * This helper solves the TypeScript type inference issue where factory functions
96
+ * that return middleware lose the context type information. By wrapping your
97
+ * middleware with this helper, you explicitly declare what context type the
98
+ * middleware will output, enabling proper type inference through the `.use()` chain.
99
+ *
100
+ * @template TOutputContext - The type of context this middleware will output
101
+ * @template TInput - The type of input data (defaults to unknown)
102
+ *
103
+ * @param middlewareFn - The middleware function that transforms context
104
+ * @returns A typed middleware function with proper type inference
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * interface AuthContext {
109
+ * userId: string;
110
+ * role: string;
111
+ * }
112
+ *
113
+ * const createAuthMiddleware = () =>
114
+ * createTypedMiddleware<AuthContext>(async ({ context, input }) => {
115
+ * const session = await getSession();
116
+ *
117
+ * if (!session) {
118
+ * return { error: { message: 'Unauthorized', code: 'AUTH_ERROR' } };
119
+ * }
120
+ *
121
+ * return {
122
+ * context: {
123
+ * userId: session.userId,
124
+ * role: session.role,
125
+ * },
126
+ * };
127
+ * });
128
+ *
129
+ * // Now TypeScript correctly infers authClient has AuthContext
130
+ * const authClient = baseClient.use(createAuthMiddleware());
131
+ *
132
+ * // And in your actions, context is properly typed
133
+ * authClient.action(async (context) => {
134
+ * const userId = context.userId; // ✅ Type-safe!
135
+ * });
136
+ * ```
137
+ */
138
+ declare function createTypedMiddleware<TOutputContext extends object, TInput = unknown>(middlewareFn: (params: {
139
+ context: any;
140
+ input: TInput;
141
+ }) => Promise<{
142
+ context: TOutputContext;
143
+ } | {
144
+ error: ServerActionError;
145
+ }>): ServerActionMiddleware<TOutputContext, TInput>;
146
+
147
+ export { ServerActionClient, type ServerActionMiddleware, createActionClient, createTypedMiddleware, handleServerActionError, isErrorResponse };
@@ -29,6 +29,7 @@ var core_exports = {};
29
29
  __export(core_exports, {
30
30
  ServerActionClient: () => ServerActionClient,
31
31
  createActionClient: () => createActionClient,
32
+ createTypedMiddleware: () => createTypedMiddleware,
32
33
  handleServerActionError: () => handleServerActionError,
33
34
  isErrorResponse: () => isErrorResponse
34
35
  });
@@ -397,10 +398,16 @@ function createFormServerAction(config) {
397
398
  function createActionClient() {
398
399
  return new ServerActionClient();
399
400
  }
401
+
402
+ // src/core/middleware-helpers.ts
403
+ function createTypedMiddleware(middlewareFn) {
404
+ return middlewareFn;
405
+ }
400
406
  // Annotate the CommonJS export names for ESM import in node:
401
407
  0 && (module.exports = {
402
408
  ServerActionClient,
403
409
  createActionClient,
410
+ createTypedMiddleware,
404
411
  handleServerActionError,
405
412
  isErrorResponse
406
413
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/index.ts","../../src/core/error-handler.ts","../../src/next/errors/redirect.ts","../../src/next/errors/http-access-fallback.ts","../../src/next/errors/index.ts","../../src/core/server-action-client.ts"],"sourcesContent":["export * from \"./error-handler\";\nexport * from \"./server-action-client\";","import { z, ZodError } from \"zod\";\nimport type { ServerActionError, ServerActionResponse } from \"../types\";\n\nfunction convertZodError(error: ZodError): ServerActionError {\n const { fieldErrors, formErrors } = z.flattenError(error);\n const [field] = Object.keys(fieldErrors) as (keyof typeof fieldErrors)[];\n const message = (field && fieldErrors[field]?.[0]) ?? formErrors[0] ?? \"Validation failed\";\n return {\n message,\n code: \"VALIDATION_ERROR\",\n field,\n fields: fieldErrors,\n };\n}\n\nfunction convertGenericError(error: unknown): ServerActionError {\n const message = error instanceof Error ? error.message : \"An unexpected error occurred\";\n\n return {\n message: process.env.NODE_ENV === \"production\" ? \"An unexpected error occurred\" : message,\n code: \"INTERNAL_ERROR\",\n statusCode: 500,\n };\n}\n\nexport function handleServerActionError(\n error: unknown,\n customHandler?: (error: unknown) => ServerActionError | undefined\n): { success: false; error: ServerActionError } {\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.error(\"[Server Action Error]\", error?.constructor?.name || 'Unknown', error instanceof Error ? error.message : error);\n }\n\n // Try custom handler first\n if (customHandler) {\n try {\n const customError = customHandler(error);\n if (customError) {\n return {\n success: false,\n error: customError,\n };\n }\n } catch (handlerError) {\n console.error(\"[Server Action Error] Custom handler threw an error:\", handlerError);\n }\n }\n\n if (error instanceof ZodError) {\n return {\n success: false,\n error: convertZodError(error),\n };\n }\n\n if (error instanceof Error && \"toServerActionError\" in error && typeof error.toServerActionError === \"function\") {\n const serverError = error.toServerActionError() as ServerActionError;\n \n // Check if this is an auth error based on the error type/code\n if (serverError.code === \"AUTHENTICATION_ERROR\" || (error as any).type === \"AUTHENTICATION_ERROR\") {\n serverError.shouldRedirect = true;\n serverError.redirectTo = \"/login\";\n }\n \n return {\n success: false,\n error: serverError,\n };\n }\n\n return {\n success: false,\n error: convertGenericError(error),\n };\n}\n\nexport function isErrorResponse<T>(response: ServerActionResponse<T>): response is { success: false; error: ServerActionError } {\n return !response.success;\n}","// Comes from: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect-error.ts\n\nenum RedirectStatusCode {\n\tSeeOther = 303,\n\tTemporaryRedirect = 307,\n\tPermanentRedirect = 308,\n}\n\nconst REDIRECT_ERROR_CODE = \"NEXT_REDIRECT\";\n\nenum RedirectType {\n\tpush = \"push\",\n\treplace = \"replace\",\n}\n\nexport type RedirectError = Error & {\n\tdigest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${string};${RedirectStatusCode};`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by the\n * `redirect(url)` helper.\n *\n * @param error the error that may reference a redirect error\n * @returns true if the error is a redirect error\n */\nexport function isRedirectError(error: unknown): error is RedirectError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst digest = error.digest.split(\";\");\n\tconst [errorCode, type] = digest;\n\tconst destination = digest.slice(2, -2).join(\";\");\n\tconst status = digest.at(-2);\n\n\tconst statusCode = Number(status);\n\n\treturn (\n\t\terrorCode === REDIRECT_ERROR_CODE &&\n\t\t(type === \"replace\" || type === \"push\") &&\n\t\ttypeof destination === \"string\" &&\n\t\t!isNaN(statusCode) &&\n\t\tstatusCode in RedirectStatusCode\n\t);\n}","// Comes from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts\n\nconst HTTPAccessErrorStatus = {\n\tNOT_FOUND: 404,\n\tFORBIDDEN: 403,\n\tUNAUTHORIZED: 401,\n};\n\nconst ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));\n\nconst HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\nexport type HTTPAccessFallbackError = Error & {\n\tdigest: `${typeof HTTP_ERROR_FALLBACK_ERROR_CODE};${string}`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by\n * the HTTP navigation APIs `notFound()`, `forbidden()` or `unauthorized()`.\n *\n * @param error the error that may reference a HTTP access error\n * @returns true if the error is a HTTP access error\n */\nexport function isHTTPAccessFallbackError(error: unknown): error is HTTPAccessFallbackError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\tconst [prefix, httpStatus] = error.digest.split(\";\");\n\n\treturn prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));\n}\n\nexport function getAccessFallbackHTTPStatus(error: HTTPAccessFallbackError): number {\n\tconst httpStatus = error.digest.split(\";\")[1];\n\treturn Number(httpStatus);\n}","import { isRedirectError } from \"./redirect\";\nimport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\n\nexport { isRedirectError } from \"./redirect\";\nexport type { RedirectError } from \"./redirect\";\n\nexport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\nexport type { HTTPAccessFallbackError } from \"./http-access-fallback\";\n\n/**\n * Checks if the error is a navigation error that should be re-thrown\n * This includes redirect errors and HTTP access errors (notFound, forbidden, unauthorized)\n */\nexport function isNextNavigationError(error: unknown): boolean {\n\treturn isRedirectError(error) || isHTTPAccessFallbackError(error);\n}\n\n/**\n * Checks if the error is a notFound error\n * Note: Next.js implements notFound() using HTTP_ERROR_FALLBACK with status 404,\n * not as a separate error type like NEXT_REDIRECT\n */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error as any) === 404;\n}","import { z } from \"zod\";\nimport type { ServerActionError, ServerActionResponse, ServerAction } from \"../types\";\nimport { handleServerActionError } from \"./error-handler\";\nimport { isNextNavigationError } from \"../next/errors\";\n\ntype InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;\ntype InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;\n\ntype ServerActionMiddleware<Context, Input = unknown> = (params: { context: Context; input: Input }) => Promise<{ context: Context } | { error: ServerActionError }>;\n\nimport type { RedirectConfig } from \"../types\";\n\ntype SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {\n middlewareFns: ServerActionMiddleware<any, any>[];\n inputSchema?: InputSchema;\n outputSchema?: OutputSchema;\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n ctxType?: Context;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n};\n\nexport class ServerActionClient<Context extends object = {}, InputSchema extends z.ZodTypeAny | undefined = undefined, OutputSchema extends z.ZodTypeAny | undefined = undefined> {\n readonly #args: SafeActionClientArgs<Context, InputSchema, OutputSchema>;\n\n constructor(\n args: SafeActionClientArgs<Context, InputSchema, OutputSchema> = {\n middlewareFns: [],\n }\n ) {\n this.#args = args;\n }\n\n /**\n * Use a middleware function.\n * @param middlewareFn Middleware function\n */\n use<NextContext extends object>(\n middlewareFn: ServerActionMiddleware<\n Context & NextContext, \n InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined\n >\n ) {\n return new ServerActionClient<Context & NextContext, InputSchema, OutputSchema>({\n ...this.#args,\n middlewareFns: [...this.#args.middlewareFns, middlewareFn] as any,\n ctxType: {} as Context & NextContext,\n });\n }\n\n /**\n * Define the input validation schema for the action.\n * @param schema Input validation schema\n */\n inputSchema<IS extends z.ZodTypeAny>(schema: IS) {\n return new ServerActionClient<Context, IS, OutputSchema>({\n ...this.#args,\n inputSchema: schema,\n });\n }\n\n /**\n * Define the output validation schema for the action.\n * @param schema Output validation schema\n */\n outputSchema<OS extends z.ZodTypeAny>(schema: OS) {\n return new ServerActionClient<Context, InputSchema, OS>({\n ...this.#args,\n outputSchema: schema,\n });\n }\n\n /**\n * Define a custom error handler for the action.\n * @param handler Error handler function\n */\n onError(handler: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n onError: handler,\n });\n }\n\n /**\n * Define a redirect configuration for successful actions.\n * @param config Redirect URL, config object, or function that returns redirect config based on result\n */\n redirect<Data = any>(\n config: string | RedirectConfig | ((result: Data) => string | RedirectConfig | undefined)\n ) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n redirectConfig: config,\n });\n }\n\n\n /**\n * Define the action.\n * @param serverCodeFn Code that will be executed on the server side\n */\n action<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): ServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void, \n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n > {\n return createServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void,\n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n >({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn: serverCodeFn as any,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n\n /**\n * Define a form action that accepts FormData.\n * @param serverCodeFn Code that will be executed on the server side\n */\n formAction<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): (prev: ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>, formData: FormData) => Promise<ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>> {\n return createFormServerAction({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n}\n\n// Internal function to create the actual server action\nfunction createServerAction<TInput, TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any, any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): ServerAction<TInput, TOutput> {\n const actionFn = async (...args: TInput extends void ? [] : [input: TInput]): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n \n // Type guard: check if we have an input schema\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n const input = hasInputSchema ? args[0] as TInput : undefined;\n\n try {\n let parsedInput: any = undefined;\n\n // Input validation\n if (hasInputSchema && config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(input);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput: input }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n \n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[executeAction] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n \n // Use the handleServerActionError function with custom handler\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n \n return handleServerActionError(error, errorHandler);\n }\n };\n\n // Add metadata for runtime type checking\n (actionFn as any).__hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n \n // Return the function with correct typing based on whether input is void\n return actionFn as ServerAction<TInput, TOutput>;\n}\n\n/**\n * Safely parses JSON strings back to objects/arrays and handles FormData boolean conventions.\n * \n * DESIGN PRINCIPLES:\n * - Parse objects and arrays (start with { or [)\n * - Parse \"true\"/\"false\" to booleans (FormData convention for checkboxes)\n * - DO NOT parse number strings (\"123\") to avoid ambiguity\n * - Fail gracefully on malformed JSON\n * - Maintain perfect symmetry with client-side objectToFormData\n * \n * WHY WE PARSE BOOLEANS:\n * - HTML forms cannot send real JavaScript booleans, only strings\n * - Checkboxes commonly send \"true\"/\"false\" strings\n * - React Hook Form uses this convention\n * - This is the expected behavior in FormData context\n */\nfunction tryParseJSON(value: unknown): unknown {\n // Non-strings pass through unchanged\n if (typeof value !== 'string') return value;\n \n const trimmed = value.trim();\n \n // Empty strings remain empty\n if (!trimmed) return value;\n \n // Parse boolean strings (common for checkboxes and React Hook Form)\n // This is safe in FormData context since HTML can't send real booleans\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n \n // Parse null (less common but sometimes used)\n if (trimmed === 'null') return null;\n \n // Only attempt parsing for obvious JSON structures\n if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))) {\n try {\n const parsed = JSON.parse(trimmed);\n // Extra safety: verify we got an object/array\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // Malformed JSON - return original string\n }\n }\n \n // All other strings (including number strings like \"123\") remain as strings\n // This avoids ambiguity with actual string values that happen to be numeric\n return value;\n}\n\n// Form data parser with automatic JSON deserialization\nfunction parseFormData(formData: FormData): Record<string, any> {\n const result: Record<string, any> = {};\n const keys = new Set<string>();\n\n for (const [key] of formData.entries()) {\n keys.add(key);\n }\n\n for (const key of keys) {\n const values = formData.getAll(key);\n\n if (key.endsWith(\"[]\")) {\n const cleanKey = key.slice(0, -2);\n // Parse each array item (handles nested objects in arrays)\n result[cleanKey] = values.map(tryParseJSON);\n } else if (values.length === 1) {\n // Parse single value (handles JSON stringified objects)\n result[key] = tryParseJSON(values[0]);\n } else {\n // Parse multiple values\n result[key] = values.map(tryParseJSON);\n }\n }\n\n return result;\n}\n\n// Internal function to create form server action\nfunction createFormServerAction<TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): (prev: ServerActionResponse<TOutput>, formData: FormData) => Promise<ServerActionResponse<TOutput>> {\n return async (_prev: ServerActionResponse<TOutput>, formData: FormData): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n\n try {\n let parsedInput: any = parseFormData(formData);\n\n // Input validation\n if (config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(parsedInput);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[ServerActionClient] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n return handleServerActionError(error, errorHandler);\n }\n };\n}\n\n// Export factory function for creating a new client\nexport function createActionClient() {\n return new ServerActionClient();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAA4B;AAG5B,SAAS,gBAAgB,OAAoC;AAC3D,QAAM,EAAE,aAAa,WAAW,IAAI,aAAE,aAAa,KAAK;AACxD,QAAM,CAAC,KAAK,IAAI,OAAO,KAAK,WAAW;AACvC,QAAM,WAAW,SAAS,YAAY,KAAK,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK;AACvE,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,oBAAoB,OAAmC;AAC9D,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AAEzD,SAAO;AAAA,IACL,SAAS,QAAQ,IAAI,aAAa,eAAe,iCAAiC;AAAA,IAClF,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AACF;AAEO,SAAS,wBACd,OACA,eAC8C;AAE9C,MAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,YAAQ,MAAM,yBAAyB,OAAO,aAAa,QAAQ,WAAW,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,EAC9H;AAGA,MAAI,eAAe;AACjB,QAAI;AACF,YAAM,cAAc,cAAc,KAAK;AACvC,UAAI,aAAa;AACf,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,cAAc;AACrB,cAAQ,MAAM,wDAAwD,YAAY;AAAA,IACpF;AAAA,EACF;AAEA,MAAI,iBAAiB,qBAAU;AAC7B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,gBAAgB,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,MAAI,iBAAiB,SAAS,yBAAyB,SAAS,OAAO,MAAM,wBAAwB,YAAY;AAC/G,UAAM,cAAc,MAAM,oBAAoB;AAG9C,QAAI,YAAY,SAAS,0BAA2B,MAAc,SAAS,wBAAwB;AACjG,kBAAY,iBAAiB;AAC7B,kBAAY,aAAa;AAAA,IAC3B;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO,oBAAoB,KAAK;AAAA,EAClC;AACF;AAEO,SAAS,gBAAmB,UAA6F;AAC9H,SAAO,CAAC,SAAS;AACnB;;;AC7EA,IAAK,qBAAL,kBAAKA,wBAAL;AACC,EAAAA,wCAAA,cAAW,OAAX;AACA,EAAAA,wCAAA,uBAAoB,OAApB;AACA,EAAAA,wCAAA,uBAAoB,OAApB;AAHI,SAAAA;AAAA,GAAA;AAML,IAAM,sBAAsB;AAkBrB,SAAS,gBAAgB,OAAwC;AACvE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,UAAU,OAAO,MAAM,WAAW,UAAU;AAC5G,WAAO;AAAA,EACR;AAEA,QAAM,SAAS,MAAM,OAAO,MAAM,GAAG;AACrC,QAAM,CAAC,WAAW,IAAI,IAAI;AAC1B,QAAM,cAAc,OAAO,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG;AAChD,QAAM,SAAS,OAAO,GAAG,EAAE;AAE3B,QAAM,aAAa,OAAO,MAAM;AAEhC,SACC,cAAc,wBACb,SAAS,aAAa,SAAS,WAChC,OAAO,gBAAgB,YACvB,CAAC,MAAM,UAAU,KACjB,cAAc;AAEhB;;;AC3CA,IAAM,wBAAwB;AAAA,EAC7B,WAAW;AAAA,EACX,WAAW;AAAA,EACX,cAAc;AACf;AAEA,IAAM,gBAAgB,IAAI,IAAI,OAAO,OAAO,qBAAqB,CAAC;AAElE,IAAM,iCAAiC;AAahC,SAAS,0BAA0B,OAAkD;AAC3F,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,UAAU,OAAO,MAAM,WAAW,UAAU;AAC5G,WAAO;AAAA,EACR;AACA,QAAM,CAAC,QAAQ,UAAU,IAAI,MAAM,OAAO,MAAM,GAAG;AAEnD,SAAO,WAAW,kCAAkC,cAAc,IAAI,OAAO,UAAU,CAAC;AACzF;;;ACjBO,SAAS,sBAAsB,OAAyB;AAC9D,SAAO,gBAAgB,KAAK,KAAK,0BAA0B,KAAK;AACjE;;;ACfA;AAqBO,IAAM,sBAAN,MAAM,oBAAqK;AAAA,EAGhL,YACE,OAAiE;AAAA,IAC/D,eAAe,CAAC;AAAA,EAClB,GACA;AANF,uBAAS;AAOP,uBAAK,OAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IACE,cAIA;AACA,WAAO,IAAI,oBAAqE;AAAA,MAC9E,GAAG,mBAAK;AAAA,MACR,eAAe,CAAC,GAAG,mBAAK,OAAM,eAAe,YAAY;AAAA,MACzD,SAAS,CAAC;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAqC,QAAY;AAC/C,WAAO,IAAI,oBAA8C;AAAA,MACvD,GAAG,mBAAK;AAAA,MACR,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAsC,QAAY;AAChD,WAAO,IAAI,oBAA6C;AAAA,MACtD,GAAG,mBAAK;AAAA,MACR,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,SAAgG;AACtG,WAAO,IAAI,oBAAuD;AAAA,MAChE,GAAG,mBAAK;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SACE,QACA;AACA,WAAO,IAAI,oBAAuD;AAAA,MAChE,GAAG,mBAAK;AAAA,MACR,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OACE,cAYA;AACA,WAAO,mBAOL;AAAA,MACA,aAAa,mBAAK,OAAM;AAAA,MACxB,cAAc,mBAAK,OAAM;AAAA,MACzB,eAAe,mBAAK,OAAM;AAAA,MAC1B,SAAS,mBAAK,OAAM;AAAA,MACpB;AAAA,MACA,gBAAgB,mBAAK,OAAM;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WACE,cAKqO;AACrO,WAAO,uBAAuB;AAAA,MAC5B,aAAa,mBAAK,OAAM;AAAA,MACxB,cAAc,mBAAK,OAAM;AAAA,MACzB,eAAe,mBAAK,OAAM;AAAA,MAC1B,SAAS,mBAAK,OAAM;AAAA,MACpB;AAAA,MACA,gBAAgB,mBAAK,OAAM;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;AAjIW;AADJ,IAAM,qBAAN;AAqIP,SAAS,mBAAoC,QAOX;AAChC,QAAM,WAAW,UAAU,SAA6F;AACtH,UAAM,UAAqC,CAAC;AAG5C,UAAM,iBAAiB,OAAO,gBAAgB,UAAa,OAAO,gBAAgB;AAClF,UAAM,QAAQ,iBAAiB,KAAK,CAAC,IAAc;AAEnD,QAAI;AACF,UAAI,cAAmB;AAGvB,UAAI,kBAAkB,OAAO,aAAa;AACxC,cAAM,cAAc,OAAO,YAAY,UAAU,KAAK;AACtD,YAAI,CAAC,YAAY,SAAS;AACxB,iBAAO,wBAAwB,YAAY,OAAO,OAAO,UAAU,CAAC,QAAQ,OAAO,QAAS,KAAK,EAAE,aAAa,MAAM,CAAC,IAAI,MAAS;AAAA,QACtI;AACA,sBAAc,YAAY;AAC1B,gBAAQ,cAAc;AAAA,MACxB;AAGA,UAAI,oBAAoB,CAAC;AACzB,iBAAW,cAAc,OAAO,eAAe;AAC7C,cAAM,kBAAkB,iBAAiB,cAAc;AACvD,cAAMC,UAAS,MAAM,WAAW,EAAE,SAAS,mBAAmB,OAAO,gBAAgB,CAAC;AACtF,YAAI,WAAWA,SAAQ;AACrB,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAOA,QAAO;AAAA,UAChB;AAAA,QACF;AACA,4BAAoB,EAAE,GAAG,mBAAmB,GAAGA,QAAO,QAAQ;AAAA,MAChE;AAGA,YAAM,SAAS,iBACX,MAAM,OAAO,aAAa,aAAa,iBAAiB,IACxD,MAAM,OAAO,aAAa,iBAAiB;AAG/C,UAAI,kBAAuB;AAC3B,UAAI,OAAO,cAAc;AACvB,cAAM,cAAc,OAAO,aAAa,UAAU,MAAM;AACxD,YAAI,CAAC,YAAY,SAAS;AACxB,iBAAO,wBAAwB,YAAY,KAAK;AAAA,QAClD;AACA,0BAAkB,YAAY;AAAA,MAChC;AAGA,UAAI;AACJ,UAAI,OAAO,gBAAgB;AACzB,YAAI,OAAO,OAAO,mBAAmB,YAAY;AAC/C,0BAAgB,OAAO,eAAe,eAAe;AAAA,QACvD,OAAO;AACL,0BAAgB,OAAO;AAAA,QACzB;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM;AAAA,QACN,GAAI,iBAAiB,EAAE,UAAU,cAAc;AAAA,MACjD;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,sBAAsB,KAAK,GAAG;AAChC,cAAM;AAAA,MACR;AAGA,UAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAQ,IAAI,0BAA0B,OAAO,aAAa,MAAM,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,MAChH;AAGA,YAAM,eAAe,OAAO,UAAU,CAAC,QAAiB;AACtD,eAAO,OAAO,QAAS,KAAK,EAAE,aAAa,QAAQ,YAAY,CAAC;AAAA,MAClE,IAAI;AAEJ,aAAO,wBAAwB,OAAO,YAAY;AAAA,IACpD;AAAA,EACF;AAGA,EAAC,SAAiB,mBAAmB,OAAO,gBAAgB,UAAa,OAAO,gBAAgB;AAGhG,SAAO;AACT;AAkBA,SAAS,aAAa,OAAyB;AAE7C,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,UAAU,MAAM,KAAK;AAG3B,MAAI,CAAC,QAAS,QAAO;AAIrB,MAAI,YAAY,OAAQ,QAAO;AAC/B,MAAI,YAAY,QAAS,QAAO;AAGhC,MAAI,YAAY,OAAQ,QAAO;AAG/B,MAAK,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,KAC/C,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAI;AACtD,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,UAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAIA,SAAO;AACT;AAGA,SAAS,cAAc,UAAyC;AAC9D,QAAM,SAA8B,CAAC;AACrC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,CAAC,GAAG,KAAK,SAAS,QAAQ,GAAG;AACtC,SAAK,IAAI,GAAG;AAAA,EACd;AAEA,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,SAAS,OAAO,GAAG;AAElC,QAAI,IAAI,SAAS,IAAI,GAAG;AACtB,YAAM,WAAW,IAAI,MAAM,GAAG,EAAE;AAEhC,aAAO,QAAQ,IAAI,OAAO,IAAI,YAAY;AAAA,IAC5C,WAAW,OAAO,WAAW,GAAG;AAE9B,aAAO,GAAG,IAAI,aAAa,OAAO,CAAC,CAAC;AAAA,IACtC,OAAO;AAEL,aAAO,GAAG,IAAI,OAAO,IAAI,YAAY;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,uBAAgC,QAO+D;AACtG,SAAO,OAAO,OAAsC,aAA+D;AACjH,UAAM,UAAqC,CAAC;AAC5C,UAAM,iBAAiB,OAAO,gBAAgB,UAAa,OAAO,gBAAgB;AAElF,QAAI;AACF,UAAI,cAAmB,cAAc,QAAQ;AAG7C,UAAI,OAAO,aAAa;AACtB,cAAM,cAAc,OAAO,YAAY,UAAU,WAAW;AAC5D,YAAI,CAAC,YAAY,SAAS;AACxB,iBAAO,wBAAwB,YAAY,OAAO,OAAO,UAAU,CAAC,QAAQ,OAAO,QAAS,KAAK,EAAE,YAAY,CAAC,IAAI,MAAS;AAAA,QAC/H;AACA,sBAAc,YAAY;AAC1B,gBAAQ,cAAc;AAAA,MACxB;AAGA,UAAI,oBAAoB,CAAC;AACzB,iBAAW,cAAc,OAAO,eAAe;AAC7C,cAAM,kBAAkB,iBAAiB,cAAc;AACvD,cAAMA,UAAS,MAAM,WAAW,EAAE,SAAS,mBAAmB,OAAO,gBAAgB,CAAC;AACtF,YAAI,WAAWA,SAAQ;AACrB,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAOA,QAAO;AAAA,UAChB;AAAA,QACF;AACA,4BAAoB,EAAE,GAAG,mBAAmB,GAAGA,QAAO,QAAQ;AAAA,MAChE;AAGA,YAAM,SAAS,iBACX,MAAM,OAAO,aAAa,aAAa,iBAAiB,IACxD,MAAM,OAAO,aAAa,iBAAiB;AAG/C,UAAI,kBAAuB;AAC3B,UAAI,OAAO,cAAc;AACvB,cAAM,cAAc,OAAO,aAAa,UAAU,MAAM;AACxD,YAAI,CAAC,YAAY,SAAS;AACxB,iBAAO,wBAAwB,YAAY,KAAK;AAAA,QAClD;AACA,0BAAkB,YAAY;AAAA,MAChC;AAGA,UAAI;AACJ,UAAI,OAAO,gBAAgB;AACzB,YAAI,OAAO,OAAO,mBAAmB,YAAY;AAC/C,0BAAgB,OAAO,eAAe,eAAe;AAAA,QACvD,OAAO;AACL,0BAAgB,OAAO;AAAA,QACzB;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM;AAAA,QACN,GAAI,iBAAiB,EAAE,UAAU,cAAc;AAAA,MACjD;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,sBAAsB,KAAK,GAAG;AAChC,cAAM;AAAA,MACR;AAEA,UAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAQ,IAAI,+BAA+B,OAAO,aAAa,MAAM,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AAAA,MACrH;AACA,YAAM,eAAe,OAAO,UAAU,CAAC,QAAiB;AACtD,eAAO,OAAO,QAAS,KAAK,EAAE,aAAa,QAAQ,YAAY,CAAC;AAAA,MAClE,IAAI;AACJ,aAAO,wBAAwB,OAAO,YAAY;AAAA,IACpD;AAAA,EACF;AACF;AAGO,SAAS,qBAAqB;AACnC,SAAO,IAAI,mBAAmB;AAChC;","names":["RedirectStatusCode","result"]}
1
+ {"version":3,"sources":["../../src/core/index.ts","../../src/core/error-handler.ts","../../src/next/errors/redirect.ts","../../src/next/errors/http-access-fallback.ts","../../src/next/errors/index.ts","../../src/core/server-action-client.ts","../../src/core/middleware-helpers.ts"],"sourcesContent":["export * from \"./error-handler\";\nexport * from \"./server-action-client\";\nexport * from \"./middleware-helpers\";","import { z, ZodError } from \"zod\";\nimport type { ServerActionError, ServerActionResponse } from \"../types\";\n\nfunction convertZodError(error: ZodError): ServerActionError {\n const { fieldErrors, formErrors } = z.flattenError(error);\n const [field] = Object.keys(fieldErrors) as (keyof typeof fieldErrors)[];\n const message = (field && fieldErrors[field]?.[0]) ?? formErrors[0] ?? \"Validation failed\";\n return {\n message,\n code: \"VALIDATION_ERROR\",\n field,\n fields: fieldErrors,\n };\n}\n\nfunction convertGenericError(error: unknown): ServerActionError {\n const message = error instanceof Error ? error.message : \"An unexpected error occurred\";\n\n return {\n message: process.env.NODE_ENV === \"production\" ? \"An unexpected error occurred\" : message,\n code: \"INTERNAL_ERROR\",\n statusCode: 500,\n };\n}\n\nexport function handleServerActionError(\n error: unknown,\n customHandler?: (error: unknown) => ServerActionError | undefined\n): { success: false; error: ServerActionError } {\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.error(\"[Server Action Error]\", error?.constructor?.name || 'Unknown', error instanceof Error ? error.message : error);\n }\n\n // Try custom handler first\n if (customHandler) {\n try {\n const customError = customHandler(error);\n if (customError) {\n return {\n success: false,\n error: customError,\n };\n }\n } catch (handlerError) {\n console.error(\"[Server Action Error] Custom handler threw an error:\", handlerError);\n }\n }\n\n if (error instanceof ZodError) {\n return {\n success: false,\n error: convertZodError(error),\n };\n }\n\n if (error instanceof Error && \"toServerActionError\" in error && typeof error.toServerActionError === \"function\") {\n const serverError = error.toServerActionError() as ServerActionError;\n \n // Check if this is an auth error based on the error type/code\n if (serverError.code === \"AUTHENTICATION_ERROR\" || (error as any).type === \"AUTHENTICATION_ERROR\") {\n serverError.shouldRedirect = true;\n serverError.redirectTo = \"/login\";\n }\n \n return {\n success: false,\n error: serverError,\n };\n }\n\n return {\n success: false,\n error: convertGenericError(error),\n };\n}\n\nexport function isErrorResponse<T>(response: ServerActionResponse<T>): response is { success: false; error: ServerActionError } {\n return !response.success;\n}","// Comes from: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect-error.ts\n\nenum RedirectStatusCode {\n\tSeeOther = 303,\n\tTemporaryRedirect = 307,\n\tPermanentRedirect = 308,\n}\n\nconst REDIRECT_ERROR_CODE = \"NEXT_REDIRECT\";\n\nenum RedirectType {\n\tpush = \"push\",\n\treplace = \"replace\",\n}\n\nexport type RedirectError = Error & {\n\tdigest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${string};${RedirectStatusCode};`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by the\n * `redirect(url)` helper.\n *\n * @param error the error that may reference a redirect error\n * @returns true if the error is a redirect error\n */\nexport function isRedirectError(error: unknown): error is RedirectError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst digest = error.digest.split(\";\");\n\tconst [errorCode, type] = digest;\n\tconst destination = digest.slice(2, -2).join(\";\");\n\tconst status = digest.at(-2);\n\n\tconst statusCode = Number(status);\n\n\treturn (\n\t\terrorCode === REDIRECT_ERROR_CODE &&\n\t\t(type === \"replace\" || type === \"push\") &&\n\t\ttypeof destination === \"string\" &&\n\t\t!isNaN(statusCode) &&\n\t\tstatusCode in RedirectStatusCode\n\t);\n}","// Comes from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts\n\nconst HTTPAccessErrorStatus = {\n\tNOT_FOUND: 404,\n\tFORBIDDEN: 403,\n\tUNAUTHORIZED: 401,\n};\n\nconst ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));\n\nconst HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\nexport type HTTPAccessFallbackError = Error & {\n\tdigest: `${typeof HTTP_ERROR_FALLBACK_ERROR_CODE};${string}`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by\n * the HTTP navigation APIs `notFound()`, `forbidden()` or `unauthorized()`.\n *\n * @param error the error that may reference a HTTP access error\n * @returns true if the error is a HTTP access error\n */\nexport function isHTTPAccessFallbackError(error: unknown): error is HTTPAccessFallbackError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\tconst [prefix, httpStatus] = error.digest.split(\";\");\n\n\treturn prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));\n}\n\nexport function getAccessFallbackHTTPStatus(error: HTTPAccessFallbackError): number {\n\tconst httpStatus = error.digest.split(\";\")[1];\n\treturn Number(httpStatus);\n}","import { isRedirectError } from \"./redirect\";\nimport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\n\nexport { isRedirectError } from \"./redirect\";\nexport type { RedirectError } from \"./redirect\";\n\nexport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\nexport type { HTTPAccessFallbackError } from \"./http-access-fallback\";\n\n/**\n * Checks if the error is a navigation error that should be re-thrown\n * This includes redirect errors and HTTP access errors (notFound, forbidden, unauthorized)\n */\nexport function isNextNavigationError(error: unknown): boolean {\n\treturn isRedirectError(error) || isHTTPAccessFallbackError(error);\n}\n\n/**\n * Checks if the error is a notFound error\n * Note: Next.js implements notFound() using HTTP_ERROR_FALLBACK with status 404,\n * not as a separate error type like NEXT_REDIRECT\n */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error as any) === 404;\n}","import { z } from \"zod\";\nimport type { ServerActionError, ServerActionResponse, ServerAction } from \"../types\";\nimport { handleServerActionError } from \"./error-handler\";\nimport { isNextNavigationError } from \"../next/errors\";\n\ntype InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;\ntype InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;\n\ntype ServerActionMiddleware<Context, Input = unknown> = (params: { context: Context; input: Input }) => Promise<{ context: Context } | { error: ServerActionError }>;\n\nimport type { RedirectConfig } from \"../types\";\n\ntype SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {\n middlewareFns: ServerActionMiddleware<any, any>[];\n inputSchema?: InputSchema;\n outputSchema?: OutputSchema;\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n ctxType?: Context;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n};\n\nexport class ServerActionClient<Context extends object = {}, InputSchema extends z.ZodTypeAny | undefined = undefined, OutputSchema extends z.ZodTypeAny | undefined = undefined> {\n readonly #args: SafeActionClientArgs<Context, InputSchema, OutputSchema>;\n\n constructor(\n args: SafeActionClientArgs<Context, InputSchema, OutputSchema> = {\n middlewareFns: [],\n }\n ) {\n this.#args = args;\n }\n\n /**\n * Use a middleware function.\n * @param middlewareFn Middleware function\n */\n use<NextContext extends object>(\n middlewareFn: ServerActionMiddleware<\n Context & NextContext, \n InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined\n >\n ) {\n return new ServerActionClient<Context & NextContext, InputSchema, OutputSchema>({\n ...this.#args,\n middlewareFns: [...this.#args.middlewareFns, middlewareFn] as any,\n ctxType: {} as Context & NextContext,\n });\n }\n\n /**\n * Define the input validation schema for the action.\n * @param schema Input validation schema\n */\n inputSchema<IS extends z.ZodTypeAny>(schema: IS) {\n return new ServerActionClient<Context, IS, OutputSchema>({\n ...this.#args,\n inputSchema: schema,\n });\n }\n\n /**\n * Define the output validation schema for the action.\n * @param schema Output validation schema\n */\n outputSchema<OS extends z.ZodTypeAny>(schema: OS) {\n return new ServerActionClient<Context, InputSchema, OS>({\n ...this.#args,\n outputSchema: schema,\n });\n }\n\n /**\n * Define a custom error handler for the action.\n * @param handler Error handler function\n */\n onError(handler: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n onError: handler,\n });\n }\n\n /**\n * Define a redirect configuration for successful actions.\n * @param config Redirect URL, config object, or function that returns redirect config based on result\n */\n redirect<Data = any>(\n config: string | RedirectConfig | ((result: Data) => string | RedirectConfig | undefined)\n ) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n redirectConfig: config,\n });\n }\n\n\n /**\n * Define the action.\n * @param serverCodeFn Code that will be executed on the server side\n */\n action<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): ServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void, \n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n > {\n return createServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void,\n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n >({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn: serverCodeFn as any,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n\n /**\n * Define a form action that accepts FormData.\n * @param serverCodeFn Code that will be executed on the server side\n */\n formAction<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): (prev: ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>, formData: FormData) => Promise<ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>> {\n return createFormServerAction({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n}\n\n// Internal function to create the actual server action\nfunction createServerAction<TInput, TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any, any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): ServerAction<TInput, TOutput> {\n const actionFn = async (...args: TInput extends void ? [] : [input: TInput]): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n \n // Type guard: check if we have an input schema\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n const input = hasInputSchema ? args[0] as TInput : undefined;\n\n try {\n let parsedInput: any = undefined;\n\n // Input validation\n if (hasInputSchema && config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(input);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput: input }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n \n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[executeAction] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n \n // Use the handleServerActionError function with custom handler\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n \n return handleServerActionError(error, errorHandler);\n }\n };\n\n // Add metadata for runtime type checking\n (actionFn as any).__hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n \n // Return the function with correct typing based on whether input is void\n return actionFn as ServerAction<TInput, TOutput>;\n}\n\n/**\n * Safely parses JSON strings back to objects/arrays and handles FormData boolean conventions.\n * \n * DESIGN PRINCIPLES:\n * - Parse objects and arrays (start with { or [)\n * - Parse \"true\"/\"false\" to booleans (FormData convention for checkboxes)\n * - DO NOT parse number strings (\"123\") to avoid ambiguity\n * - Fail gracefully on malformed JSON\n * - Maintain perfect symmetry with client-side objectToFormData\n * \n * WHY WE PARSE BOOLEANS:\n * - HTML forms cannot send real JavaScript booleans, only strings\n * - Checkboxes commonly send \"true\"/\"false\" strings\n * - React Hook Form uses this convention\n * - This is the expected behavior in FormData context\n */\nfunction tryParseJSON(value: unknown): unknown {\n // Non-strings pass through unchanged\n if (typeof value !== 'string') return value;\n \n const trimmed = value.trim();\n \n // Empty strings remain empty\n if (!trimmed) return value;\n \n // Parse boolean strings (common for checkboxes and React Hook Form)\n // This is safe in FormData context since HTML can't send real booleans\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n \n // Parse null (less common but sometimes used)\n if (trimmed === 'null') return null;\n \n // Only attempt parsing for obvious JSON structures\n if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))) {\n try {\n const parsed = JSON.parse(trimmed);\n // Extra safety: verify we got an object/array\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // Malformed JSON - return original string\n }\n }\n \n // All other strings (including number strings like \"123\") remain as strings\n // This avoids ambiguity with actual string values that happen to be numeric\n return value;\n}\n\n// Form data parser with automatic JSON deserialization\nfunction parseFormData(formData: FormData): Record<string, any> {\n const result: Record<string, any> = {};\n const keys = new Set<string>();\n\n for (const [key] of formData.entries()) {\n keys.add(key);\n }\n\n for (const key of keys) {\n const values = formData.getAll(key);\n\n if (key.endsWith(\"[]\")) {\n const cleanKey = key.slice(0, -2);\n // Parse each array item (handles nested objects in arrays)\n result[cleanKey] = values.map(tryParseJSON);\n } else if (values.length === 1) {\n // Parse single value (handles JSON stringified objects)\n result[key] = tryParseJSON(values[0]);\n } else {\n // Parse multiple values\n result[key] = values.map(tryParseJSON);\n }\n }\n\n return result;\n}\n\n// Internal function to create form server action\nfunction createFormServerAction<TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): (prev: ServerActionResponse<TOutput>, formData: FormData) => Promise<ServerActionResponse<TOutput>> {\n return async (_prev: ServerActionResponse<TOutput>, formData: FormData): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n\n try {\n let parsedInput: any = parseFormData(formData);\n\n // Input validation\n if (config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(parsedInput);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[ServerActionClient] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n return handleServerActionError(error, errorHandler);\n }\n };\n}\n\n// Export factory function for creating a new client\nexport function createActionClient() {\n return new ServerActionClient();\n}\n","import type { ServerActionError } from '../types';\n\n/**\n * Type definition for Server Action Middleware\n *\n * A middleware can either:\n * - Return an updated context that gets merged with the existing context\n * - Return an error that stops the action execution\n */\nexport type ServerActionMiddleware<Context, Input = unknown> = (params: {\n context: Context;\n input: Input;\n}) => Promise<{ context: Context } | { error: ServerActionError }>;\n\n/**\n * Helper for creating middleware with correct type inference for the output context.\n *\n * This helper solves the TypeScript type inference issue where factory functions\n * that return middleware lose the context type information. By wrapping your\n * middleware with this helper, you explicitly declare what context type the\n * middleware will output, enabling proper type inference through the `.use()` chain.\n *\n * @template TOutputContext - The type of context this middleware will output\n * @template TInput - The type of input data (defaults to unknown)\n *\n * @param middlewareFn - The middleware function that transforms context\n * @returns A typed middleware function with proper type inference\n *\n * @example\n * ```typescript\n * interface AuthContext {\n * userId: string;\n * role: string;\n * }\n *\n * const createAuthMiddleware = () =>\n * createTypedMiddleware<AuthContext>(async ({ context, input }) => {\n * const session = await getSession();\n *\n * if (!session) {\n * return { error: { message: 'Unauthorized', code: 'AUTH_ERROR' } };\n * }\n *\n * return {\n * context: {\n * userId: session.userId,\n * role: session.role,\n * },\n * };\n * });\n *\n * // Now TypeScript correctly infers authClient has AuthContext\n * const authClient = baseClient.use(createAuthMiddleware());\n *\n * // And in your actions, context is properly typed\n * authClient.action(async (context) => {\n * const userId = context.userId; // ✅ Type-safe!\n * });\n * ```\n */\nexport function createTypedMiddleware<TOutputContext extends object, TInput = unknown>(\n middlewareFn: (params: {\n context: any;\n input: TInput;\n }) => Promise<{ context: TOutputContext } | { error: ServerActionError }>\n): ServerActionMiddleware<TOutputContext, TInput> {\n return middlewareFn as any;\n}\n"],"mappings":"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","names":["RedirectStatusCode","result"]}
@@ -369,9 +369,15 @@ function createFormServerAction(config) {
369
369
  function createActionClient() {
370
370
  return new ServerActionClient();
371
371
  }
372
+
373
+ // src/core/middleware-helpers.ts
374
+ function createTypedMiddleware(middlewareFn) {
375
+ return middlewareFn;
376
+ }
372
377
  export {
373
378
  ServerActionClient,
374
379
  createActionClient,
380
+ createTypedMiddleware,
375
381
  handleServerActionError,
376
382
  isErrorResponse
377
383
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/error-handler.ts","../../src/next/errors/redirect.ts","../../src/next/errors/http-access-fallback.ts","../../src/next/errors/index.ts","../../src/core/server-action-client.ts"],"sourcesContent":["import { z, ZodError } from \"zod\";\nimport type { ServerActionError, ServerActionResponse } from \"../types\";\n\nfunction convertZodError(error: ZodError): ServerActionError {\n const { fieldErrors, formErrors } = z.flattenError(error);\n const [field] = Object.keys(fieldErrors) as (keyof typeof fieldErrors)[];\n const message = (field && fieldErrors[field]?.[0]) ?? formErrors[0] ?? \"Validation failed\";\n return {\n message,\n code: \"VALIDATION_ERROR\",\n field,\n fields: fieldErrors,\n };\n}\n\nfunction convertGenericError(error: unknown): ServerActionError {\n const message = error instanceof Error ? error.message : \"An unexpected error occurred\";\n\n return {\n message: process.env.NODE_ENV === \"production\" ? \"An unexpected error occurred\" : message,\n code: \"INTERNAL_ERROR\",\n statusCode: 500,\n };\n}\n\nexport function handleServerActionError(\n error: unknown,\n customHandler?: (error: unknown) => ServerActionError | undefined\n): { success: false; error: ServerActionError } {\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.error(\"[Server Action Error]\", error?.constructor?.name || 'Unknown', error instanceof Error ? error.message : error);\n }\n\n // Try custom handler first\n if (customHandler) {\n try {\n const customError = customHandler(error);\n if (customError) {\n return {\n success: false,\n error: customError,\n };\n }\n } catch (handlerError) {\n console.error(\"[Server Action Error] Custom handler threw an error:\", handlerError);\n }\n }\n\n if (error instanceof ZodError) {\n return {\n success: false,\n error: convertZodError(error),\n };\n }\n\n if (error instanceof Error && \"toServerActionError\" in error && typeof error.toServerActionError === \"function\") {\n const serverError = error.toServerActionError() as ServerActionError;\n \n // Check if this is an auth error based on the error type/code\n if (serverError.code === \"AUTHENTICATION_ERROR\" || (error as any).type === \"AUTHENTICATION_ERROR\") {\n serverError.shouldRedirect = true;\n serverError.redirectTo = \"/login\";\n }\n \n return {\n success: false,\n error: serverError,\n };\n }\n\n return {\n success: false,\n error: convertGenericError(error),\n };\n}\n\nexport function isErrorResponse<T>(response: ServerActionResponse<T>): response is { success: false; error: ServerActionError } {\n return !response.success;\n}","// Comes from: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect-error.ts\n\nenum RedirectStatusCode {\n\tSeeOther = 303,\n\tTemporaryRedirect = 307,\n\tPermanentRedirect = 308,\n}\n\nconst REDIRECT_ERROR_CODE = \"NEXT_REDIRECT\";\n\nenum RedirectType {\n\tpush = \"push\",\n\treplace = \"replace\",\n}\n\nexport type RedirectError = Error & {\n\tdigest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${string};${RedirectStatusCode};`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by the\n * `redirect(url)` helper.\n *\n * @param error the error that may reference a redirect error\n * @returns true if the error is a redirect error\n */\nexport function isRedirectError(error: unknown): error is RedirectError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst digest = error.digest.split(\";\");\n\tconst [errorCode, type] = digest;\n\tconst destination = digest.slice(2, -2).join(\";\");\n\tconst status = digest.at(-2);\n\n\tconst statusCode = Number(status);\n\n\treturn (\n\t\terrorCode === REDIRECT_ERROR_CODE &&\n\t\t(type === \"replace\" || type === \"push\") &&\n\t\ttypeof destination === \"string\" &&\n\t\t!isNaN(statusCode) &&\n\t\tstatusCode in RedirectStatusCode\n\t);\n}","// Comes from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts\n\nconst HTTPAccessErrorStatus = {\n\tNOT_FOUND: 404,\n\tFORBIDDEN: 403,\n\tUNAUTHORIZED: 401,\n};\n\nconst ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));\n\nconst HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\nexport type HTTPAccessFallbackError = Error & {\n\tdigest: `${typeof HTTP_ERROR_FALLBACK_ERROR_CODE};${string}`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by\n * the HTTP navigation APIs `notFound()`, `forbidden()` or `unauthorized()`.\n *\n * @param error the error that may reference a HTTP access error\n * @returns true if the error is a HTTP access error\n */\nexport function isHTTPAccessFallbackError(error: unknown): error is HTTPAccessFallbackError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\tconst [prefix, httpStatus] = error.digest.split(\";\");\n\n\treturn prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));\n}\n\nexport function getAccessFallbackHTTPStatus(error: HTTPAccessFallbackError): number {\n\tconst httpStatus = error.digest.split(\";\")[1];\n\treturn Number(httpStatus);\n}","import { isRedirectError } from \"./redirect\";\nimport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\n\nexport { isRedirectError } from \"./redirect\";\nexport type { RedirectError } from \"./redirect\";\n\nexport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\nexport type { HTTPAccessFallbackError } from \"./http-access-fallback\";\n\n/**\n * Checks if the error is a navigation error that should be re-thrown\n * This includes redirect errors and HTTP access errors (notFound, forbidden, unauthorized)\n */\nexport function isNextNavigationError(error: unknown): boolean {\n\treturn isRedirectError(error) || isHTTPAccessFallbackError(error);\n}\n\n/**\n * Checks if the error is a notFound error\n * Note: Next.js implements notFound() using HTTP_ERROR_FALLBACK with status 404,\n * not as a separate error type like NEXT_REDIRECT\n */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error as any) === 404;\n}","import { z } from \"zod\";\nimport type { ServerActionError, ServerActionResponse, ServerAction } from \"../types\";\nimport { handleServerActionError } from \"./error-handler\";\nimport { isNextNavigationError } from \"../next/errors\";\n\ntype InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;\ntype InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;\n\ntype ServerActionMiddleware<Context, Input = unknown> = (params: { context: Context; input: Input }) => Promise<{ context: Context } | { error: ServerActionError }>;\n\nimport type { RedirectConfig } from \"../types\";\n\ntype SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {\n middlewareFns: ServerActionMiddleware<any, any>[];\n inputSchema?: InputSchema;\n outputSchema?: OutputSchema;\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n ctxType?: Context;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n};\n\nexport class ServerActionClient<Context extends object = {}, InputSchema extends z.ZodTypeAny | undefined = undefined, OutputSchema extends z.ZodTypeAny | undefined = undefined> {\n readonly #args: SafeActionClientArgs<Context, InputSchema, OutputSchema>;\n\n constructor(\n args: SafeActionClientArgs<Context, InputSchema, OutputSchema> = {\n middlewareFns: [],\n }\n ) {\n this.#args = args;\n }\n\n /**\n * Use a middleware function.\n * @param middlewareFn Middleware function\n */\n use<NextContext extends object>(\n middlewareFn: ServerActionMiddleware<\n Context & NextContext, \n InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined\n >\n ) {\n return new ServerActionClient<Context & NextContext, InputSchema, OutputSchema>({\n ...this.#args,\n middlewareFns: [...this.#args.middlewareFns, middlewareFn] as any,\n ctxType: {} as Context & NextContext,\n });\n }\n\n /**\n * Define the input validation schema for the action.\n * @param schema Input validation schema\n */\n inputSchema<IS extends z.ZodTypeAny>(schema: IS) {\n return new ServerActionClient<Context, IS, OutputSchema>({\n ...this.#args,\n inputSchema: schema,\n });\n }\n\n /**\n * Define the output validation schema for the action.\n * @param schema Output validation schema\n */\n outputSchema<OS extends z.ZodTypeAny>(schema: OS) {\n return new ServerActionClient<Context, InputSchema, OS>({\n ...this.#args,\n outputSchema: schema,\n });\n }\n\n /**\n * Define a custom error handler for the action.\n * @param handler Error handler function\n */\n onError(handler: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n onError: handler,\n });\n }\n\n /**\n * Define a redirect configuration for successful actions.\n * @param config Redirect URL, config object, or function that returns redirect config based on result\n */\n redirect<Data = any>(\n config: string | RedirectConfig | ((result: Data) => string | RedirectConfig | undefined)\n ) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n redirectConfig: config,\n });\n }\n\n\n /**\n * Define the action.\n * @param serverCodeFn Code that will be executed on the server side\n */\n action<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): ServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void, \n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n > {\n return createServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void,\n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n >({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn: serverCodeFn as any,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n\n /**\n * Define a form action that accepts FormData.\n * @param serverCodeFn Code that will be executed on the server side\n */\n formAction<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): (prev: ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>, formData: FormData) => Promise<ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>> {\n return createFormServerAction({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n}\n\n// Internal function to create the actual server action\nfunction createServerAction<TInput, TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any, any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): ServerAction<TInput, TOutput> {\n const actionFn = async (...args: TInput extends void ? [] : [input: TInput]): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n \n // Type guard: check if we have an input schema\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n const input = hasInputSchema ? args[0] as TInput : undefined;\n\n try {\n let parsedInput: any = undefined;\n\n // Input validation\n if (hasInputSchema && config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(input);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput: input }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n \n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[executeAction] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n \n // Use the handleServerActionError function with custom handler\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n \n return handleServerActionError(error, errorHandler);\n }\n };\n\n // Add metadata for runtime type checking\n (actionFn as any).__hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n \n // Return the function with correct typing based on whether input is void\n return actionFn as ServerAction<TInput, TOutput>;\n}\n\n/**\n * Safely parses JSON strings back to objects/arrays and handles FormData boolean conventions.\n * \n * DESIGN PRINCIPLES:\n * - Parse objects and arrays (start with { or [)\n * - Parse \"true\"/\"false\" to booleans (FormData convention for checkboxes)\n * - DO NOT parse number strings (\"123\") to avoid ambiguity\n * - Fail gracefully on malformed JSON\n * - Maintain perfect symmetry with client-side objectToFormData\n * \n * WHY WE PARSE BOOLEANS:\n * - HTML forms cannot send real JavaScript booleans, only strings\n * - Checkboxes commonly send \"true\"/\"false\" strings\n * - React Hook Form uses this convention\n * - This is the expected behavior in FormData context\n */\nfunction tryParseJSON(value: unknown): unknown {\n // Non-strings pass through unchanged\n if (typeof value !== 'string') return value;\n \n const trimmed = value.trim();\n \n // Empty strings remain empty\n if (!trimmed) return value;\n \n // Parse boolean strings (common for checkboxes and React Hook Form)\n // This is safe in FormData context since HTML can't send real booleans\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n \n // Parse null (less common but sometimes used)\n if (trimmed === 'null') return null;\n \n // Only attempt parsing for obvious JSON structures\n if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))) {\n try {\n const parsed = JSON.parse(trimmed);\n // Extra safety: verify we got an object/array\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // Malformed JSON - return original string\n }\n }\n \n // All other strings (including number strings like \"123\") remain as strings\n // This avoids ambiguity with actual string values that happen to be numeric\n return value;\n}\n\n// Form data parser with automatic JSON deserialization\nfunction parseFormData(formData: FormData): Record<string, any> {\n const result: Record<string, any> = {};\n const keys = new Set<string>();\n\n for (const [key] of formData.entries()) {\n keys.add(key);\n }\n\n for (const key of keys) {\n const values = formData.getAll(key);\n\n if (key.endsWith(\"[]\")) {\n const cleanKey = key.slice(0, -2);\n // Parse each array item (handles nested objects in arrays)\n result[cleanKey] = values.map(tryParseJSON);\n } else if (values.length === 1) {\n // Parse single value (handles JSON stringified objects)\n result[key] = tryParseJSON(values[0]);\n } else {\n // Parse multiple values\n result[key] = values.map(tryParseJSON);\n }\n }\n\n return result;\n}\n\n// Internal function to create form server action\nfunction createFormServerAction<TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): (prev: ServerActionResponse<TOutput>, formData: FormData) => Promise<ServerActionResponse<TOutput>> {\n return async (_prev: ServerActionResponse<TOutput>, formData: FormData): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n\n try {\n let parsedInput: any = parseFormData(formData);\n\n // Input validation\n if (config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(parsedInput);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[ServerActionClient] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n return handleServerActionError(error, errorHandler);\n }\n };\n}\n\n// Export factory function for creating a new client\nexport function createActionClient() {\n return new ServerActionClient();\n}\n"],"mappings":"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","names":["RedirectStatusCode","result"]}
1
+ {"version":3,"sources":["../../src/core/error-handler.ts","../../src/next/errors/redirect.ts","../../src/next/errors/http-access-fallback.ts","../../src/next/errors/index.ts","../../src/core/server-action-client.ts","../../src/core/middleware-helpers.ts"],"sourcesContent":["import { z, ZodError } from \"zod\";\nimport type { ServerActionError, ServerActionResponse } from \"../types\";\n\nfunction convertZodError(error: ZodError): ServerActionError {\n const { fieldErrors, formErrors } = z.flattenError(error);\n const [field] = Object.keys(fieldErrors) as (keyof typeof fieldErrors)[];\n const message = (field && fieldErrors[field]?.[0]) ?? formErrors[0] ?? \"Validation failed\";\n return {\n message,\n code: \"VALIDATION_ERROR\",\n field,\n fields: fieldErrors,\n };\n}\n\nfunction convertGenericError(error: unknown): ServerActionError {\n const message = error instanceof Error ? error.message : \"An unexpected error occurred\";\n\n return {\n message: process.env.NODE_ENV === \"production\" ? \"An unexpected error occurred\" : message,\n code: \"INTERNAL_ERROR\",\n statusCode: 500,\n };\n}\n\nexport function handleServerActionError(\n error: unknown,\n customHandler?: (error: unknown) => ServerActionError | undefined\n): { success: false; error: ServerActionError } {\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.error(\"[Server Action Error]\", error?.constructor?.name || 'Unknown', error instanceof Error ? error.message : error);\n }\n\n // Try custom handler first\n if (customHandler) {\n try {\n const customError = customHandler(error);\n if (customError) {\n return {\n success: false,\n error: customError,\n };\n }\n } catch (handlerError) {\n console.error(\"[Server Action Error] Custom handler threw an error:\", handlerError);\n }\n }\n\n if (error instanceof ZodError) {\n return {\n success: false,\n error: convertZodError(error),\n };\n }\n\n if (error instanceof Error && \"toServerActionError\" in error && typeof error.toServerActionError === \"function\") {\n const serverError = error.toServerActionError() as ServerActionError;\n \n // Check if this is an auth error based on the error type/code\n if (serverError.code === \"AUTHENTICATION_ERROR\" || (error as any).type === \"AUTHENTICATION_ERROR\") {\n serverError.shouldRedirect = true;\n serverError.redirectTo = \"/login\";\n }\n \n return {\n success: false,\n error: serverError,\n };\n }\n\n return {\n success: false,\n error: convertGenericError(error),\n };\n}\n\nexport function isErrorResponse<T>(response: ServerActionResponse<T>): response is { success: false; error: ServerActionError } {\n return !response.success;\n}","// Comes from: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect-error.ts\n\nenum RedirectStatusCode {\n\tSeeOther = 303,\n\tTemporaryRedirect = 307,\n\tPermanentRedirect = 308,\n}\n\nconst REDIRECT_ERROR_CODE = \"NEXT_REDIRECT\";\n\nenum RedirectType {\n\tpush = \"push\",\n\treplace = \"replace\",\n}\n\nexport type RedirectError = Error & {\n\tdigest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${string};${RedirectStatusCode};`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by the\n * `redirect(url)` helper.\n *\n * @param error the error that may reference a redirect error\n * @returns true if the error is a redirect error\n */\nexport function isRedirectError(error: unknown): error is RedirectError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\n\tconst digest = error.digest.split(\";\");\n\tconst [errorCode, type] = digest;\n\tconst destination = digest.slice(2, -2).join(\";\");\n\tconst status = digest.at(-2);\n\n\tconst statusCode = Number(status);\n\n\treturn (\n\t\terrorCode === REDIRECT_ERROR_CODE &&\n\t\t(type === \"replace\" || type === \"push\") &&\n\t\ttypeof destination === \"string\" &&\n\t\t!isNaN(statusCode) &&\n\t\tstatusCode in RedirectStatusCode\n\t);\n}","// Comes from https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts\n\nconst HTTPAccessErrorStatus = {\n\tNOT_FOUND: 404,\n\tFORBIDDEN: 403,\n\tUNAUTHORIZED: 401,\n};\n\nconst ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));\n\nconst HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\nexport type HTTPAccessFallbackError = Error & {\n\tdigest: `${typeof HTTP_ERROR_FALLBACK_ERROR_CODE};${string}`;\n};\n\n/**\n * Checks an error to determine if it's an error generated by\n * the HTTP navigation APIs `notFound()`, `forbidden()` or `unauthorized()`.\n *\n * @param error the error that may reference a HTTP access error\n * @returns true if the error is a HTTP access error\n */\nexport function isHTTPAccessFallbackError(error: unknown): error is HTTPAccessFallbackError {\n\tif (typeof error !== \"object\" || error === null || !(\"digest\" in error) || typeof error.digest !== \"string\") {\n\t\treturn false;\n\t}\n\tconst [prefix, httpStatus] = error.digest.split(\";\");\n\n\treturn prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));\n}\n\nexport function getAccessFallbackHTTPStatus(error: HTTPAccessFallbackError): number {\n\tconst httpStatus = error.digest.split(\";\")[1];\n\treturn Number(httpStatus);\n}","import { isRedirectError } from \"./redirect\";\nimport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\n\nexport { isRedirectError } from \"./redirect\";\nexport type { RedirectError } from \"./redirect\";\n\nexport { isHTTPAccessFallbackError, getAccessFallbackHTTPStatus } from \"./http-access-fallback\";\nexport type { HTTPAccessFallbackError } from \"./http-access-fallback\";\n\n/**\n * Checks if the error is a navigation error that should be re-thrown\n * This includes redirect errors and HTTP access errors (notFound, forbidden, unauthorized)\n */\nexport function isNextNavigationError(error: unknown): boolean {\n\treturn isRedirectError(error) || isHTTPAccessFallbackError(error);\n}\n\n/**\n * Checks if the error is a notFound error\n * Note: Next.js implements notFound() using HTTP_ERROR_FALLBACK with status 404,\n * not as a separate error type like NEXT_REDIRECT\n */\nexport function isNotFoundError(error: unknown): boolean {\n\treturn isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error as any) === 404;\n}","import { z } from \"zod\";\nimport type { ServerActionError, ServerActionResponse, ServerAction } from \"../types\";\nimport { handleServerActionError } from \"./error-handler\";\nimport { isNextNavigationError } from \"../next/errors\";\n\ntype InferZodOutput<T> = T extends z.ZodTypeAny ? z.output<T> : never;\ntype InferZodInput<T> = T extends z.ZodTypeAny ? z.input<T> : never;\n\ntype ServerActionMiddleware<Context, Input = unknown> = (params: { context: Context; input: Input }) => Promise<{ context: Context } | { error: ServerActionError }>;\n\nimport type { RedirectConfig } from \"../types\";\n\ntype SafeActionClientArgs<Context extends object, InputSchema extends z.ZodTypeAny | undefined, OutputSchema extends z.ZodTypeAny | undefined> = {\n middlewareFns: ServerActionMiddleware<any, any>[];\n inputSchema?: InputSchema;\n outputSchema?: OutputSchema;\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n ctxType?: Context;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n};\n\nexport class ServerActionClient<Context extends object = {}, InputSchema extends z.ZodTypeAny | undefined = undefined, OutputSchema extends z.ZodTypeAny | undefined = undefined> {\n readonly #args: SafeActionClientArgs<Context, InputSchema, OutputSchema>;\n\n constructor(\n args: SafeActionClientArgs<Context, InputSchema, OutputSchema> = {\n middlewareFns: [],\n }\n ) {\n this.#args = args;\n }\n\n /**\n * Use a middleware function.\n * @param middlewareFn Middleware function\n */\n use<NextContext extends object>(\n middlewareFn: ServerActionMiddleware<\n Context & NextContext, \n InputSchema extends z.ZodTypeAny ? z.output<InputSchema> : undefined\n >\n ) {\n return new ServerActionClient<Context & NextContext, InputSchema, OutputSchema>({\n ...this.#args,\n middlewareFns: [...this.#args.middlewareFns, middlewareFn] as any,\n ctxType: {} as Context & NextContext,\n });\n }\n\n /**\n * Define the input validation schema for the action.\n * @param schema Input validation schema\n */\n inputSchema<IS extends z.ZodTypeAny>(schema: IS) {\n return new ServerActionClient<Context, IS, OutputSchema>({\n ...this.#args,\n inputSchema: schema,\n });\n }\n\n /**\n * Define the output validation schema for the action.\n * @param schema Output validation schema\n */\n outputSchema<OS extends z.ZodTypeAny>(schema: OS) {\n return new ServerActionClient<Context, InputSchema, OS>({\n ...this.#args,\n outputSchema: schema,\n });\n }\n\n /**\n * Define a custom error handler for the action.\n * @param handler Error handler function\n */\n onError(handler: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n onError: handler,\n });\n }\n\n /**\n * Define a redirect configuration for successful actions.\n * @param config Redirect URL, config object, or function that returns redirect config based on result\n */\n redirect<Data = any>(\n config: string | RedirectConfig | ((result: Data) => string | RedirectConfig | undefined)\n ) {\n return new ServerActionClient<Context, InputSchema, OutputSchema>({\n ...this.#args,\n redirectConfig: config,\n });\n }\n\n\n /**\n * Define the action.\n * @param serverCodeFn Code that will be executed on the server side\n */\n action<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): ServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void, \n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n > {\n return createServerAction<\n InputSchema extends undefined \n ? void \n : InputSchema extends z.ZodTypeAny \n ? InferZodInput<InputSchema> \n : void,\n OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data\n >({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn: serverCodeFn as any,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n\n /**\n * Define a form action that accepts FormData.\n * @param serverCodeFn Code that will be executed on the server side\n */\n formAction<Data>(\n serverCodeFn: InputSchema extends undefined\n ? (context: Context) => Promise<Data>\n : InputSchema extends z.ZodTypeAny \n ? (input: InferZodOutput<InputSchema>, context: Context) => Promise<Data>\n : (context: Context) => Promise<Data>\n ): (prev: ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>, formData: FormData) => Promise<ServerActionResponse<OutputSchema extends z.ZodTypeAny ? InferZodOutput<OutputSchema> : Data>> {\n return createFormServerAction({\n inputSchema: this.#args.inputSchema,\n outputSchema: this.#args.outputSchema,\n middlewareFns: this.#args.middlewareFns,\n onError: this.#args.onError,\n serverCodeFn,\n redirectConfig: this.#args.redirectConfig,\n });\n }\n}\n\n// Internal function to create the actual server action\nfunction createServerAction<TInput, TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any, any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): ServerAction<TInput, TOutput> {\n const actionFn = async (...args: TInput extends void ? [] : [input: TInput]): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n \n // Type guard: check if we have an input schema\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n const input = hasInputSchema ? args[0] as TInput : undefined;\n\n try {\n let parsedInput: any = undefined;\n\n // Input validation\n if (hasInputSchema && config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(input);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput: input }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n \n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[executeAction] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n \n // Use the handleServerActionError function with custom handler\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n \n return handleServerActionError(error, errorHandler);\n }\n };\n\n // Add metadata for runtime type checking\n (actionFn as any).__hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n \n // Return the function with correct typing based on whether input is void\n return actionFn as ServerAction<TInput, TOutput>;\n}\n\n/**\n * Safely parses JSON strings back to objects/arrays and handles FormData boolean conventions.\n * \n * DESIGN PRINCIPLES:\n * - Parse objects and arrays (start with { or [)\n * - Parse \"true\"/\"false\" to booleans (FormData convention for checkboxes)\n * - DO NOT parse number strings (\"123\") to avoid ambiguity\n * - Fail gracefully on malformed JSON\n * - Maintain perfect symmetry with client-side objectToFormData\n * \n * WHY WE PARSE BOOLEANS:\n * - HTML forms cannot send real JavaScript booleans, only strings\n * - Checkboxes commonly send \"true\"/\"false\" strings\n * - React Hook Form uses this convention\n * - This is the expected behavior in FormData context\n */\nfunction tryParseJSON(value: unknown): unknown {\n // Non-strings pass through unchanged\n if (typeof value !== 'string') return value;\n \n const trimmed = value.trim();\n \n // Empty strings remain empty\n if (!trimmed) return value;\n \n // Parse boolean strings (common for checkboxes and React Hook Form)\n // This is safe in FormData context since HTML can't send real booleans\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n \n // Parse null (less common but sometimes used)\n if (trimmed === 'null') return null;\n \n // Only attempt parsing for obvious JSON structures\n if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))) {\n try {\n const parsed = JSON.parse(trimmed);\n // Extra safety: verify we got an object/array\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // Malformed JSON - return original string\n }\n }\n \n // All other strings (including number strings like \"123\") remain as strings\n // This avoids ambiguity with actual string values that happen to be numeric\n return value;\n}\n\n// Form data parser with automatic JSON deserialization\nfunction parseFormData(formData: FormData): Record<string, any> {\n const result: Record<string, any> = {};\n const keys = new Set<string>();\n\n for (const [key] of formData.entries()) {\n keys.add(key);\n }\n\n for (const key of keys) {\n const values = formData.getAll(key);\n\n if (key.endsWith(\"[]\")) {\n const cleanKey = key.slice(0, -2);\n // Parse each array item (handles nested objects in arrays)\n result[cleanKey] = values.map(tryParseJSON);\n } else if (values.length === 1) {\n // Parse single value (handles JSON stringified objects)\n result[key] = tryParseJSON(values[0]);\n } else {\n // Parse multiple values\n result[key] = values.map(tryParseJSON);\n }\n }\n\n return result;\n}\n\n// Internal function to create form server action\nfunction createFormServerAction<TOutput>(config: {\n inputSchema?: z.ZodTypeAny;\n outputSchema?: z.ZodTypeAny;\n middlewareFns: ServerActionMiddleware<any>[];\n onError?: (error: unknown, context: { parsedInput?: unknown }) => ServerActionError | undefined;\n serverCodeFn: (...args: any[]) => Promise<any>;\n redirectConfig?: string | RedirectConfig | ((result: any) => string | RedirectConfig | undefined);\n}): (prev: ServerActionResponse<TOutput>, formData: FormData) => Promise<ServerActionResponse<TOutput>> {\n return async (_prev: ServerActionResponse<TOutput>, formData: FormData): Promise<ServerActionResponse<TOutput>> => {\n const context: { parsedInput?: unknown } = {};\n const hasInputSchema = config.inputSchema !== undefined && config.inputSchema !== null;\n\n try {\n let parsedInput: any = parseFormData(formData);\n\n // Input validation\n if (config.inputSchema) {\n const parseResult = config.inputSchema.safeParse(parsedInput);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error, config.onError ? (err) => config.onError!(err, { parsedInput }) : undefined);\n }\n parsedInput = parseResult.data;\n context.parsedInput = parsedInput;\n }\n\n // Execute middleware chain\n let middlewareContext = {};\n for (const middleware of config.middlewareFns) {\n const middlewareInput = hasInputSchema ? parsedInput : undefined;\n const result = await middleware({ context: middlewareContext, input: middlewareInput });\n if (\"error\" in result) {\n return {\n success: false,\n error: result.error,\n };\n }\n middlewareContext = { ...middlewareContext, ...result.context };\n }\n\n // Execute the server code\n const result = hasInputSchema \n ? await config.serverCodeFn(parsedInput, middlewareContext)\n : await config.serverCodeFn(middlewareContext);\n\n // Output validation\n let validatedOutput: any = result;\n if (config.outputSchema) {\n const parseResult = config.outputSchema.safeParse(result);\n if (!parseResult.success) {\n return handleServerActionError(parseResult.error);\n }\n validatedOutput = parseResult.data;\n }\n\n // Handle redirect config if present\n let redirectValue: string | RedirectConfig | undefined;\n if (config.redirectConfig) {\n if (typeof config.redirectConfig === 'function') {\n redirectValue = config.redirectConfig(validatedOutput);\n } else {\n redirectValue = config.redirectConfig;\n }\n }\n\n return {\n success: true,\n data: validatedOutput,\n ...(redirectValue && { redirect: redirectValue }),\n };\n } catch (error) {\n // Preserve Next.js navigation errors (redirect, notFound, etc.)\n if (isNextNavigationError(error)) {\n throw error;\n }\n // Debug logging only in development\n if (process.env.NODE_ENV === 'development') {\n console.log(\"[ServerActionClient] Error:\", error?.constructor?.name, error instanceof Error ? error.message : error);\n }\n const errorHandler = config.onError ? (err: unknown) => {\n return config.onError!(err, { parsedInput: context.parsedInput });\n } : undefined;\n return handleServerActionError(error, errorHandler);\n }\n };\n}\n\n// Export factory function for creating a new client\nexport function createActionClient() {\n return new ServerActionClient();\n}\n","import type { ServerActionError } from '../types';\n\n/**\n * Type definition for Server Action Middleware\n *\n * A middleware can either:\n * - Return an updated context that gets merged with the existing context\n * - Return an error that stops the action execution\n */\nexport type ServerActionMiddleware<Context, Input = unknown> = (params: {\n context: Context;\n input: Input;\n}) => Promise<{ context: Context } | { error: ServerActionError }>;\n\n/**\n * Helper for creating middleware with correct type inference for the output context.\n *\n * This helper solves the TypeScript type inference issue where factory functions\n * that return middleware lose the context type information. By wrapping your\n * middleware with this helper, you explicitly declare what context type the\n * middleware will output, enabling proper type inference through the `.use()` chain.\n *\n * @template TOutputContext - The type of context this middleware will output\n * @template TInput - The type of input data (defaults to unknown)\n *\n * @param middlewareFn - The middleware function that transforms context\n * @returns A typed middleware function with proper type inference\n *\n * @example\n * ```typescript\n * interface AuthContext {\n * userId: string;\n * role: string;\n * }\n *\n * const createAuthMiddleware = () =>\n * createTypedMiddleware<AuthContext>(async ({ context, input }) => {\n * const session = await getSession();\n *\n * if (!session) {\n * return { error: { message: 'Unauthorized', code: 'AUTH_ERROR' } };\n * }\n *\n * return {\n * context: {\n * userId: session.userId,\n * role: session.role,\n * },\n * };\n * });\n *\n * // Now TypeScript correctly infers authClient has AuthContext\n * const authClient = baseClient.use(createAuthMiddleware());\n *\n * // And in your actions, context is properly typed\n * authClient.action(async (context) => {\n * const userId = context.userId; // ✅ Type-safe!\n * });\n * ```\n */\nexport function createTypedMiddleware<TOutputContext extends object, TInput = unknown>(\n middlewareFn: (params: {\n context: any;\n input: TInput;\n }) => Promise<{ context: TOutputContext } | { error: ServerActionError }>\n): ServerActionMiddleware<TOutputContext, TInput> {\n return middlewareFn as any;\n}\n"],"mappings":"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","names":["RedirectStatusCode","result"]}
@@ -274,7 +274,10 @@ function objectToFormData(obj) {
274
274
  if (value instanceof File || value instanceof Blob) {
275
275
  formData.append(key, value);
276
276
  } else if (Array.isArray(value)) {
277
- value.forEach((item) => formData.append(`${key}[]`, String(item)));
277
+ value.forEach((item) => {
278
+ const serialized = typeof item === "object" && item !== null ? JSON.stringify(item) : String(item);
279
+ formData.append(`${key}[]`, serialized);
280
+ });
278
281
  } else if (typeof value === "object") {
279
282
  formData.append(key, JSON.stringify(value));
280
283
  } else {