@kellanjs/actioncraft
Version:
Fluent, type-safe builder for Next.js server actions.
101 lines • 3.55 kB
JavaScript
import { EXTERNAL_ERROR_TYPES, INTERNAL_ERROR_TYPES } from "../types/errors.js";
import { err } from "../types/result.js";
// ===========================================================================
// CONSTANTS
// ===========================================================================
export const UNHANDLED_ERROR = {
type: EXTERNAL_ERROR_TYPES.UNHANDLED,
message: "An unhandled error occurred",
};
export const IMPLICIT_RETURN_ERROR = {
type: INTERNAL_ERROR_TYPES.IMPLICIT_RETURN,
message: "Action handler must return a value",
};
// ===========================================================================
// FACTORY HELPERS
// ===========================================================================
/**
* Creates internal logic errors with custom messages.
*/
export const createInternalLogicError = (message) => ({
type: INTERNAL_ERROR_TYPES.INTERNAL_LOGIC,
message,
});
/**
* Creates Result objects for unhandled errors.
*/
export function createUnhandledErrorResult(actionId) {
return err({ ...UNHANDLED_ERROR }, actionId);
}
/**
* Creates Result objects for implicit return errors.
*/
export function createImplicitReturnErrorResult(actionId) {
return err({ ...IMPLICIT_RETURN_ERROR }, actionId);
}
// ===========================================================================
// VALIDATION-ERROR STRUCTURING HELPERS
// ===========================================================================
/**
* Normalises Standard Schema path segments to string|number for serialization.
*/
function _normalisePath(path) {
if (!path)
return [];
return path
.map((segment) => {
if (typeof segment === "symbol")
return undefined;
if (typeof segment === "object" && segment !== null && "key" in segment) {
const key = segment.key;
return typeof key === "symbol" ? undefined : key;
}
return segment;
})
.filter((p) => p !== undefined);
}
/**
* Formats validation issues into structured error objects based on the configured format.
*/
export function formatValidationIssues(issues, format) {
if (format === "nested") {
const formErrors = [];
const fieldErrors = {};
for (const issue of issues) {
const currentPath = _normalisePath(issue.path);
if (currentPath.length === 0) {
formErrors.push(issue.message);
}
else {
const pathKey = currentPath.join(".");
if (!fieldErrors[pathKey])
fieldErrors[pathKey] = [];
fieldErrors[pathKey].push(issue.message);
}
}
return { formErrors, fieldErrors };
}
// Default to 'flattened'
return {
issues: issues.map(({ path, message }) => ({
path: _normalisePath(path),
message,
})),
};
}
function _buildFlattenedValidationError(type, message, issues) {
return { type, message, issues };
}
function _buildNestedValidationError(type, message, formErrors, fieldErrors) {
return { type, message, formErrors, fieldErrors };
}
/**
* Creates validation error objects.
*/
export function createValidationError(type, message, errorStructure) {
if ("issues" in errorStructure) {
return _buildFlattenedValidationError(type, message, errorStructure.issues);
}
return _buildNestedValidationError(type, message, errorStructure.formErrors, errorStructure.fieldErrors);
}
//# sourceMappingURL=errors.js.map