next-safe-action
Version:
Type safe and validated Server Actions in your Next.js project.
931 lines (916 loc) • 30.1 kB
JavaScript
// ../../node_modules/.pnpm/deepmerge-ts@7.1.5/node_modules/deepmerge-ts/dist/index.mjs
var actions = {
defaultMerge: Symbol("deepmerge-ts: default merge"),
skip: Symbol("deepmerge-ts: skip"),
};
var actionsInto = {
defaultMerge: actions.defaultMerge,
};
function defaultMetaDataUpdater(previousMeta, metaMeta) {
return metaMeta;
}
function defaultFilterValues(values, meta) {
return values.filter((value) => value !== void 0);
}
var ObjectType;
(function (ObjectType2) {
ObjectType2[(ObjectType2["NOT"] = 0)] = "NOT";
ObjectType2[(ObjectType2["RECORD"] = 1)] = "RECORD";
ObjectType2[(ObjectType2["ARRAY"] = 2)] = "ARRAY";
ObjectType2[(ObjectType2["SET"] = 3)] = "SET";
ObjectType2[(ObjectType2["MAP"] = 4)] = "MAP";
ObjectType2[(ObjectType2["OTHER"] = 5)] = "OTHER";
})(ObjectType || (ObjectType = {}));
function getObjectType(object) {
if (typeof object !== "object" || object === null) {
return 0;
}
if (Array.isArray(object)) {
return 2;
}
if (isRecord(object)) {
return 1;
}
if (object instanceof Set) {
return 3;
}
if (object instanceof Map) {
return 4;
}
return 5;
}
function getKeys(objects) {
const keys = /* @__PURE__ */ new Set();
for (const object of objects) {
for (const key of [...Object.keys(object), ...Object.getOwnPropertySymbols(object)]) {
keys.add(key);
}
}
return keys;
}
function objectHasProperty(object, property) {
return typeof object === "object" && Object.prototype.propertyIsEnumerable.call(object, property);
}
function getIterableOfIterables(iterables) {
let mut_iterablesIndex = 0;
let mut_iterator = iterables[0]?.[Symbol.iterator]();
return {
[Symbol.iterator]() {
return {
next() {
do {
if (mut_iterator === void 0) {
return { done: true, value: void 0 };
}
const result = mut_iterator.next();
if (result.done === true) {
mut_iterablesIndex += 1;
mut_iterator = iterables[mut_iterablesIndex]?.[Symbol.iterator]();
continue;
}
return {
done: false,
value: result.value,
};
} while (true);
},
};
},
};
}
var validRecordToStringValues = ["[object Object]", "[object Module]"];
function isRecord(value) {
if (!validRecordToStringValues.includes(Object.prototype.toString.call(value))) {
return false;
}
const { constructor } = value;
if (constructor === void 0) {
return true;
}
const prototype = constructor.prototype;
if (
prototype === null ||
typeof prototype !== "object" ||
!validRecordToStringValues.includes(Object.prototype.toString.call(prototype))
) {
return false;
}
if (!prototype.hasOwnProperty("isPrototypeOf")) {
return false;
}
return true;
}
function mergeRecords$1(values, utils, meta) {
const result = {};
for (const key of getKeys(values)) {
const propValues = [];
for (const value of values) {
if (objectHasProperty(value, key)) {
propValues.push(value[key]);
}
}
if (propValues.length === 0) {
continue;
}
const updatedMeta = utils.metaDataUpdater(meta, {
key,
parents: values,
});
const propertyResult = mergeUnknowns(propValues, utils, updatedMeta);
if (propertyResult === actions.skip) {
continue;
}
if (key === "__proto__") {
Object.defineProperty(result, key, {
value: propertyResult,
configurable: true,
enumerable: true,
writable: true,
});
} else {
result[key] = propertyResult;
}
}
return result;
}
function mergeArrays$1(values) {
return values.flat();
}
function mergeSets$1(values) {
return new Set(getIterableOfIterables(values));
}
function mergeMaps$1(values) {
return new Map(getIterableOfIterables(values));
}
function mergeOthers$1(values) {
return values.at(-1);
}
var mergeFunctions = {
mergeRecords: mergeRecords$1,
mergeArrays: mergeArrays$1,
mergeSets: mergeSets$1,
mergeMaps: mergeMaps$1,
mergeOthers: mergeOthers$1,
};
function deepmerge(...objects) {
return deepmergeCustom({})(...objects);
}
function deepmergeCustom(options, rootMetaData) {
const utils = getUtils(options, customizedDeepmerge);
function customizedDeepmerge(...objects) {
return mergeUnknowns(objects, utils, rootMetaData);
}
return customizedDeepmerge;
}
function getUtils(options, customizedDeepmerge) {
return {
defaultMergeFunctions: mergeFunctions,
mergeFunctions: {
...mergeFunctions,
...Object.fromEntries(
Object.entries(options)
.filter(([key, option]) => Object.hasOwn(mergeFunctions, key))
.map(([key, option]) => (option === false ? [key, mergeFunctions.mergeOthers] : [key, option]))
),
},
metaDataUpdater: options.metaDataUpdater ?? defaultMetaDataUpdater,
deepmerge: customizedDeepmerge,
useImplicitDefaultMerging: options.enableImplicitDefaultMerging ?? false,
filterValues: options.filterValues === false ? void 0 : (options.filterValues ?? defaultFilterValues),
actions,
};
}
function mergeUnknowns(values, utils, meta) {
const filteredValues = utils.filterValues?.(values, meta) ?? values;
if (filteredValues.length === 0) {
return void 0;
}
if (filteredValues.length === 1) {
return mergeOthers(filteredValues, utils, meta);
}
const type = getObjectType(filteredValues[0]);
if (type !== 0 && type !== 5) {
for (let mut_index = 1; mut_index < filteredValues.length; mut_index++) {
if (getObjectType(filteredValues[mut_index]) === type) {
continue;
}
return mergeOthers(filteredValues, utils, meta);
}
}
switch (type) {
case 1: {
return mergeRecords(filteredValues, utils, meta);
}
case 2: {
return mergeArrays(filteredValues, utils, meta);
}
case 3: {
return mergeSets(filteredValues, utils, meta);
}
case 4: {
return mergeMaps(filteredValues, utils, meta);
}
default: {
return mergeOthers(filteredValues, utils, meta);
}
}
}
function mergeRecords(values, utils, meta) {
const result = utils.mergeFunctions.mergeRecords(values, utils, meta);
if (
result === actions.defaultMerge ||
(utils.useImplicitDefaultMerging &&
result === void 0 &&
utils.mergeFunctions.mergeRecords !== utils.defaultMergeFunctions.mergeRecords)
) {
return utils.defaultMergeFunctions.mergeRecords(values, utils, meta);
}
return result;
}
function mergeArrays(values, utils, meta) {
const result = utils.mergeFunctions.mergeArrays(values, utils, meta);
if (
result === actions.defaultMerge ||
(utils.useImplicitDefaultMerging &&
result === void 0 &&
utils.mergeFunctions.mergeArrays !== utils.defaultMergeFunctions.mergeArrays)
) {
return utils.defaultMergeFunctions.mergeArrays(values);
}
return result;
}
function mergeSets(values, utils, meta) {
const result = utils.mergeFunctions.mergeSets(values, utils, meta);
if (
result === actions.defaultMerge ||
(utils.useImplicitDefaultMerging &&
result === void 0 &&
utils.mergeFunctions.mergeSets !== utils.defaultMergeFunctions.mergeSets)
) {
return utils.defaultMergeFunctions.mergeSets(values);
}
return result;
}
function mergeMaps(values, utils, meta) {
const result = utils.mergeFunctions.mergeMaps(values, utils, meta);
if (
result === actions.defaultMerge ||
(utils.useImplicitDefaultMerging &&
result === void 0 &&
utils.mergeFunctions.mergeMaps !== utils.defaultMergeFunctions.mergeMaps)
) {
return utils.defaultMergeFunctions.mergeMaps(values);
}
return result;
}
function mergeOthers(values, utils, meta) {
const result = utils.mergeFunctions.mergeOthers(values, utils, meta);
if (
result === actions.defaultMerge ||
(utils.useImplicitDefaultMerging &&
result === void 0 &&
utils.mergeFunctions.mergeOthers !== utils.defaultMergeFunctions.mergeOthers)
) {
return utils.defaultMergeFunctions.mergeOthers(values);
}
return result;
}
// src/next/errors/bailout-to-csr.ts
var BAILOUT_TO_CSR = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
function isBailoutToCSRError(err) {
if (typeof err !== "object" || err === null || !("digest" in err)) {
return false;
}
return err.digest === BAILOUT_TO_CSR;
}
// src/next/errors/http-access-fallback.ts
var HTTPAccessErrorStatus = {
NOT_FOUND: 404,
FORBIDDEN: 403,
UNAUTHORIZED: 401,
};
var ALLOWED_CODES = new Set(Object.values(HTTPAccessErrorStatus));
var HTTP_ERROR_FALLBACK_ERROR_CODE = "NEXT_HTTP_ERROR_FALLBACK";
function isHTTPAccessFallbackError(error) {
if (typeof error !== "object" || error === null || !("digest" in error) || typeof error.digest !== "string") {
return false;
}
const [prefix, httpStatus] = error.digest.split(";");
return prefix === HTTP_ERROR_FALLBACK_ERROR_CODE && ALLOWED_CODES.has(Number(httpStatus));
}
function getAccessFallbackHTTPStatus(error) {
const httpStatus = error.digest.split(";")[1];
return Number(httpStatus);
}
// src/next/errors/redirect.ts
var RedirectStatusCode = /* @__PURE__ */ ((RedirectStatusCode2) => {
RedirectStatusCode2[(RedirectStatusCode2["SeeOther"] = 303)] = "SeeOther";
RedirectStatusCode2[(RedirectStatusCode2["TemporaryRedirect"] = 307)] = "TemporaryRedirect";
RedirectStatusCode2[(RedirectStatusCode2["PermanentRedirect"] = 308)] = "PermanentRedirect";
return RedirectStatusCode2;
})(RedirectStatusCode || {});
var REDIRECT_ERROR_CODE = "NEXT_REDIRECT";
function isRedirectError(error) {
if (typeof error !== "object" || error === null || !("digest" in error) || typeof error.digest !== "string") {
return false;
}
const digest = error.digest.split(";");
const [errorCode, type] = digest;
const destination = digest.slice(2, -2).join(";");
const status = digest.at(-2);
const statusCode = Number(status);
return (
errorCode === REDIRECT_ERROR_CODE &&
(type === "replace" || type === "push") &&
typeof destination === "string" &&
!isNaN(statusCode) &&
statusCode in RedirectStatusCode
);
}
// src/next/errors/router.ts
function isNextRouterError(error) {
return isRedirectError(error) || isHTTPAccessFallbackError(error);
}
// src/next/errors/dynamic-usage.ts
var DYNAMIC_ERROR_CODE = "DYNAMIC_SERVER_USAGE";
function isDynamicServerError(err) {
if (typeof err !== "object" || err === null || !("digest" in err) || typeof err.digest !== "string") {
return false;
}
return err.digest === DYNAMIC_ERROR_CODE;
}
function isDynamicPostponeReason(reason) {
return (
reason.includes("needs to bail out of prerendering at this point because it used") &&
reason.includes("Learn more: https://nextjs.org/docs/messages/ppr-caught-error")
);
}
function isDynamicPostpone(err) {
if (
typeof err === "object" &&
err !== null && // eslint-disable-next-line
typeof err.message === "string"
) {
return isDynamicPostponeReason(err.message);
}
return false;
}
var isDynamicUsageError = (err) =>
isDynamicServerError(err) || isBailoutToCSRError(err) || isNextRouterError(err) || isDynamicPostpone(err);
// src/next/errors/postpone.ts
var REACT_POSTPONE_TYPE = Symbol.for("react.postpone");
function isPostpone(error) {
return (
typeof error === "object" &&
error !== null && // eslint-disable-next-line
error.$$typeof === REACT_POSTPONE_TYPE
);
}
// src/next/errors/index.ts
var FrameworkErrorHandler = class _FrameworkErrorHandler {
#frameworkError;
static isNavigationError(error) {
return isNextRouterError(error) || isBailoutToCSRError(error) || isDynamicUsageError(error) || isPostpone(error);
}
static getNavigationKind(error) {
if (isRedirectError(error)) {
return "redirect";
} else if (isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error) === 404) {
return "notFound";
} else if (isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error) === 403) {
return "forbidden";
} else if (isHTTPAccessFallbackError(error) && getAccessFallbackHTTPStatus(error) === 401) {
return "unauthorized";
} else {
return "other";
}
}
// Used in action builder.
handleError(e) {
if (_FrameworkErrorHandler.isNavigationError(e)) {
this.#frameworkError = e;
return;
}
throw e;
}
get error() {
return this.#frameworkError;
}
};
// src/standard-schema.ts
async function standardParse(schema, value) {
return schema["~standard"].validate(value);
}
// src/utils.ts
var DEFAULT_SERVER_ERROR_MESSAGE = "Something went wrong while executing the operation.";
var isError = (error) => error instanceof Error;
var winningBoolean = (...args) => {
return args.reduce((acc, v) => (typeof v === "boolean" ? v : acc), false);
};
// src/validation-errors.ts
var getKey = (segment) => (typeof segment === "object" ? segment.key : segment);
var getIssueMessage = (issue) => {
if (issue.unionErrors) {
return issue.unionErrors.map((u) => u.issues.map((i) => i.message)).flat();
}
return issue.message;
};
var buildValidationErrors = (issues) => {
const ve = {};
for (const issue of issues) {
const { path, message, unionErrors } = issue;
if (!path || path.length === 0) {
ve._errors = ve._errors ? [...ve._errors, message] : [message];
continue;
}
let ref = ve;
for (let i = 0; i < path.length - 1; i++) {
const k = getKey(path[i]);
if (!ref[k]) {
ref[k] = {};
}
ref = ref[k];
}
const key = getKey(path[path.length - 1]);
const issueMessage = getIssueMessage(issue);
ref[key] = ref[key]?._errors
? {
...structuredClone(ref[key]),
_errors: [...ref[key]._errors, issueMessage],
}
: { ...structuredClone(ref[key]), _errors: unionErrors ? issueMessage : [issueMessage] };
}
return ve;
};
var ActionServerValidationError = class extends Error {
validationErrors;
constructor(validationErrors) {
super("Server Action server validation error(s) occurred");
this.validationErrors = validationErrors;
}
};
var ActionValidationError = class extends Error {
validationErrors;
constructor(validationErrors, overriddenErrorMessage) {
super(overriddenErrorMessage ?? "Server Action validation error(s) occurred");
this.validationErrors = validationErrors;
}
};
var ActionBindArgsValidationError = class extends Error {
validationErrors;
constructor(validationErrors) {
super("Server Action bind args validation error(s) occurred");
this.validationErrors = validationErrors;
}
};
function returnValidationErrors(schema, validationErrors) {
throw new ActionServerValidationError(validationErrors);
}
function formatValidationErrors(validationErrors) {
return validationErrors;
}
function flattenValidationErrors(validationErrors) {
const flattened = {
formErrors: [],
fieldErrors: {},
};
for (const [key, value] of Object.entries(validationErrors ?? {})) {
if (key === "_errors" && Array.isArray(value)) {
flattened.formErrors = [...value];
} else {
if ("_errors" in value) {
flattened.fieldErrors[key] = [...value._errors];
}
}
}
return flattened;
}
var ActionMetadataValidationError = class extends Error {
validationErrors;
constructor(validationErrors) {
super("Invalid metadata input. Please be sure to pass metadata via `metadata` method before defining the action.");
this.name = "ActionMetadataError";
this.validationErrors = validationErrors;
}
};
var ActionOutputDataValidationError = class extends Error {
validationErrors;
constructor(validationErrors) {
super(
"Invalid action data (output). Please be sure to return data following the shape of the schema passed to `dataSchema` method."
);
this.name = "ActionOutputDataError";
this.validationErrors = validationErrors;
}
};
// src/action-builder.ts
function actionBuilder(args) {
const bindArgsSchemas = args.bindArgsSchemas ?? [];
function buildAction({ withState }) {
return {
action: (serverCodeFn, utils) => {
return async (...clientInputs) => {
let currentCtx = {};
const middlewareResult = { success: false };
let prevResult = {};
const parsedInputDatas = [];
const frameworkErrorHandler = new FrameworkErrorHandler();
if (withState) {
prevResult = clientInputs.splice(bindArgsSchemas.length, 1)[0];
}
if (bindArgsSchemas.length + 1 > clientInputs.length) {
clientInputs.push(void 0);
}
const executeMiddlewareStack = async (idx = 0) => {
if (frameworkErrorHandler.error) {
return;
}
const middlewareFn = args.middlewareFns[idx];
middlewareResult.ctx = currentCtx;
try {
if (idx === 0) {
if (args.metadataSchema) {
const parsedMd = await standardParse(args.metadataSchema, args.metadata);
if (parsedMd.issues) {
throw new ActionMetadataValidationError(buildValidationErrors(parsedMd.issues));
}
}
}
if (middlewareFn) {
await middlewareFn({
clientInput: clientInputs.at(-1),
// pass raw client input
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
ctx: currentCtx,
metadata: args.metadata,
next: async (nextOpts) => {
currentCtx = deepmerge(currentCtx, nextOpts?.ctx ?? {});
await executeMiddlewareStack(idx + 1);
return middlewareResult;
},
}).catch((e) => {
frameworkErrorHandler.handleError(e);
if (frameworkErrorHandler.error) {
middlewareResult.success = false;
middlewareResult.navigationKind = FrameworkErrorHandler.getNavigationKind(
frameworkErrorHandler.error
);
}
});
} else {
const parsedInputs = await Promise.all(
clientInputs.map(async (input, i) => {
if (i === clientInputs.length - 1) {
if (typeof args.inputSchemaFn === "undefined") {
return {
value: void 0,
};
}
return standardParse(await args.inputSchemaFn(), input);
}
return standardParse(bindArgsSchemas[i], input);
})
);
let hasBindValidationErrors = false;
const bindArgsValidationErrors = Array(parsedInputs.length - 1).fill({});
for (let i = 0; i < parsedInputs.length; i++) {
const parsedInput = parsedInputs[i];
if (!parsedInput.issues) {
parsedInputDatas.push(parsedInput.value);
} else {
if (i < parsedInputs.length - 1) {
bindArgsValidationErrors[i] = buildValidationErrors(parsedInput.issues);
hasBindValidationErrors = true;
} else {
const validationErrors = buildValidationErrors(parsedInput.issues);
middlewareResult.validationErrors = await Promise.resolve(
args.handleValidationErrorsShape(validationErrors, {
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
ctx: currentCtx,
metadata: args.metadata,
})
);
}
}
}
if (hasBindValidationErrors) {
throw new ActionBindArgsValidationError(bindArgsValidationErrors);
}
if (middlewareResult.validationErrors) {
return;
}
const scfArgs = [];
scfArgs[0] = {
parsedInput: parsedInputDatas.at(-1),
bindArgsParsedInputs: parsedInputDatas.slice(0, -1),
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
ctx: currentCtx,
metadata: args.metadata,
};
if (withState) {
scfArgs[1] = { prevResult: structuredClone(prevResult) };
}
const data = await serverCodeFn(...scfArgs).catch((e) => frameworkErrorHandler.handleError(e));
if (typeof args.outputSchema !== "undefined" && !frameworkErrorHandler.error) {
const parsedData = await standardParse(args.outputSchema, data);
if (parsedData.issues) {
throw new ActionOutputDataValidationError(buildValidationErrors(parsedData.issues));
}
}
if (frameworkErrorHandler.error) {
middlewareResult.success = false;
middlewareResult.navigationKind = FrameworkErrorHandler.getNavigationKind(
frameworkErrorHandler.error
);
} else {
middlewareResult.success = true;
middlewareResult.data = data;
}
middlewareResult.parsedInput = parsedInputDatas.at(-1);
middlewareResult.bindArgsParsedInputs = parsedInputDatas.slice(0, -1);
}
} catch (e) {
if (e instanceof ActionServerValidationError) {
const ve = e.validationErrors;
middlewareResult.validationErrors = await Promise.resolve(
args.handleValidationErrorsShape(ve, {
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
ctx: currentCtx,
metadata: args.metadata,
})
);
} else {
const error = isError(e) ? e : new Error(DEFAULT_SERVER_ERROR_MESSAGE);
const returnedError = await Promise.resolve(
args.handleServerError(error, {
clientInput: clientInputs.at(-1),
// pass raw client input
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
ctx: currentCtx,
metadata: args.metadata,
})
);
middlewareResult.serverError = returnedError;
}
}
};
await executeMiddlewareStack();
const callbackPromises = [];
if (frameworkErrorHandler.error) {
callbackPromises.push(
utils?.onNavigation?.({
metadata: args.metadata,
ctx: currentCtx,
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
navigationKind: FrameworkErrorHandler.getNavigationKind(frameworkErrorHandler.error),
})
);
callbackPromises.push(
utils?.onSettled?.({
metadata: args.metadata,
ctx: currentCtx,
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
result: {},
navigationKind: FrameworkErrorHandler.getNavigationKind(frameworkErrorHandler.error),
})
);
await Promise.all(callbackPromises);
throw frameworkErrorHandler.error;
}
const actionResult = {};
if (typeof middlewareResult.validationErrors !== "undefined") {
if (
winningBoolean(
args.throwValidationErrors,
typeof utils?.throwValidationErrors === "undefined" ? void 0 : Boolean(utils.throwValidationErrors)
)
) {
const overrideErrorMessageFn =
typeof utils?.throwValidationErrors === "object" && utils?.throwValidationErrors.overrideErrorMessage
? utils?.throwValidationErrors.overrideErrorMessage
: void 0;
throw new ActionValidationError(
middlewareResult.validationErrors,
await overrideErrorMessageFn?.(middlewareResult.validationErrors)
);
} else {
actionResult.validationErrors = middlewareResult.validationErrors;
}
}
if (typeof middlewareResult.serverError !== "undefined") {
if (utils?.throwServerError) {
throw middlewareResult.serverError;
} else {
actionResult.serverError = middlewareResult.serverError;
}
}
if (middlewareResult.success) {
if (typeof middlewareResult.data !== "undefined") {
actionResult.data = middlewareResult.data;
}
callbackPromises.push(
utils?.onSuccess?.({
metadata: args.metadata,
ctx: currentCtx,
data: actionResult.data,
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
parsedInput: parsedInputDatas.at(-1),
bindArgsParsedInputs: parsedInputDatas.slice(0, -1),
})
);
} else {
callbackPromises.push(
utils?.onError?.({
metadata: args.metadata,
ctx: currentCtx,
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
error: actionResult,
})
);
}
callbackPromises.push(
utils?.onSettled?.({
metadata: args.metadata,
ctx: currentCtx,
clientInput: clientInputs.at(-1),
bindArgsClientInputs: bindArgsSchemas.length ? clientInputs.slice(0, -1) : [],
result: actionResult,
})
);
await Promise.all(callbackPromises);
return actionResult;
};
},
};
}
return {
/**
* Define the action.
* @param serverCodeFn Code that will be executed on the **server side**
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#action--stateaction See docs for more information}
*/
action: buildAction({ withState: false }).action,
/**
* Define the stateful action. To be used with the [`useStateAction`](https://next-safe-action.dev/docs/execute-actions/hooks/usestateaction) hook.
* @param serverCodeFn Code that will be executed on the **server side**
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#action--stateaction See docs for more information}
*/
stateAction: buildAction({ withState: true }).action,
};
}
// src/safe-action-client.ts
var SafeActionClient = class _SafeActionClient {
#args;
constructor(args) {
this.#args = args;
}
/**
* Use a middleware function.
* @param middlewareFn Middleware function
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#use See docs for more information}
*/
use(middlewareFn) {
return new _SafeActionClient({
...this.#args,
middlewareFns: [...this.#args.middlewareFns, middlewareFn],
ctxType: {},
});
}
/**
* Define metadata for the action.
* @param data Metadata with the same type as the return value of the [`defineMetadataSchema`](https://next-safe-action.dev/docs/define-actions/create-the-client#definemetadataschema) optional initialization function
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#metadata See docs for more information}
*/
metadata(data) {
return new _SafeActionClient({
...this.#args,
metadata: data,
metadataProvided: true,
});
}
/**
* Define the input validation schema for the action.
* @param inputSchema Input validation schema
* @param utils Optional utils object
*
* {@link https://next-safe-action.dev/docs/define-actions/create-the-client#inputschema See docs for more information}
*/
inputSchema(inputSchema, utils) {
return new _SafeActionClient({
...this.#args,
// @ts-expect-error
inputSchemaFn:
inputSchema[Symbol.toStringTag] === "AsyncFunction"
? async () => {
const prevSchema = await this.#args.inputSchemaFn?.();
return inputSchema(prevSchema);
}
: async () => inputSchema,
handleValidationErrorsShape: utils?.handleValidationErrorsShape ?? this.#args.handleValidationErrorsShape,
});
}
/**
* @deprecated Alias for `inputSchema` method. Use that instead.
*/
schema = this.inputSchema;
/**
* Define the bind args input validation schema for the action.
* @param bindArgsSchemas Bind args input validation schemas
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#bindargsschemas See docs for more information}
*/
bindArgsSchemas(bindArgsSchemas) {
return new _SafeActionClient({
...this.#args,
bindArgsSchemas,
handleValidationErrorsShape: this.#args.handleValidationErrorsShape,
});
}
/**
* Define the output data validation schema for the action.
* @param schema Output data validation schema
*
* {@link https://next-safe-action.dev/docs/define-actions/create-the-client#outputschema See docs for more information}
*/
outputSchema(dataSchema) {
return new _SafeActionClient({
...this.#args,
outputSchema: dataSchema,
});
}
/**
* Define the action.
* @param serverCodeFn Code that will be executed on the **server side**
* @param [cb] Optional callbacks that will be called after action execution, on the server.
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#action--stateaction See docs for more information}
*/
action(serverCodeFn, utils) {
return actionBuilder(this.#args).action(serverCodeFn, utils);
}
/**
* Define the stateful action.
* To be used with the [`useStateAction`](https://next-safe-action.dev/docs/execute-actions/hooks/usestateaction) hook.
* @param serverCodeFn Code that will be executed on the **server side**
* @param [cb] Optional callbacks that will be called after action execution, on the server.
*
* {@link https://next-safe-action.dev/docs/define-actions/instance-methods#action--stateaction See docs for more information}
*/
stateAction(serverCodeFn, utils) {
return actionBuilder(this.#args).stateAction(serverCodeFn, utils);
}
};
// src/middleware.ts
var createMiddleware = () => {
return {
define: (middlewareFn) => middlewareFn,
};
};
// src/index.ts
var createSafeActionClient = (createOpts) => {
const handleServerError =
createOpts?.handleServerError ||
((e) => {
console.error("Action error:", e.message);
return DEFAULT_SERVER_ERROR_MESSAGE;
});
return new SafeActionClient({
middlewareFns: [async ({ next }) => next({ ctx: {} })],
handleServerError,
inputSchemaFn: void 0,
bindArgsSchemas: [],
outputSchema: void 0,
ctxType: {},
metadataSchema: createOpts?.defineMetadataSchema?.() ?? void 0,
metadata: void 0,
defaultValidationErrorsShape: createOpts?.defaultValidationErrorsShape ?? "formatted",
throwValidationErrors: Boolean(createOpts?.throwValidationErrors),
handleValidationErrorsShape: async (ve) =>
createOpts?.defaultValidationErrorsShape === "flattened"
? flattenValidationErrors(ve)
: formatValidationErrors(ve),
});
};
export {
ActionMetadataValidationError,
ActionOutputDataValidationError,
ActionValidationError,
DEFAULT_SERVER_ERROR_MESSAGE,
createMiddleware,
createSafeActionClient,
flattenValidationErrors,
formatValidationErrors,
returnValidationErrors,
};
//# sourceMappingURL=index.mjs.map