@kellanjs/actioncraft 0.0.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.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/actioncraft.d.ts +89 -0
- package/dist/actioncraft.js +344 -0
- package/dist/actioncraft.js.map +1 -0
- package/dist/core/callbacks.d.ts +6 -0
- package/dist/core/callbacks.js +20 -0
- package/dist/core/callbacks.js.map +1 -0
- package/dist/core/errors.d.ts +28 -0
- package/dist/core/errors.js +101 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/logging.d.ts +6 -0
- package/dist/core/logging.js +8 -0
- package/dist/core/logging.js.map +1 -0
- package/dist/core/transformation.d.ts +17 -0
- package/dist/core/transformation.js +43 -0
- package/dist/core/transformation.js.map +1 -0
- package/dist/core/validation.d.ts +16 -0
- package/dist/core/validation.js +70 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/error.d.ts +16 -0
- package/dist/error.js +22 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/standard-schema.d.ts +71 -0
- package/dist/standard-schema.js +16 -0
- package/dist/standard-schema.js.map +1 -0
- package/dist/types/actions.d.ts +120 -0
- package/dist/types/actions.js +2 -0
- package/dist/types/actions.js.map +1 -0
- package/dist/types/config.d.ts +80 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/errors.d.ts +207 -0
- package/dist/types/errors.js +21 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/inference.d.ts +20 -0
- package/dist/types/inference.js +2 -0
- package/dist/types/inference.js.map +1 -0
- package/dist/types/result.d.ts +72 -0
- package/dist/types/result.js +62 -0
- package/dist/types/result.js.map +1 -0
- package/dist/types/schemas.d.ts +33 -0
- package/dist/types/schemas.js +2 -0
- package/dist/types/schemas.js.map +1 -0
- package/dist/types/shared.d.ts +75 -0
- package/dist/types/shared.js +2 -0
- package/dist/types/shared.js.map +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +44 -0
- package/dist/utils.js.map +1 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Lanny Kenneth Lung
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
⚠️ Under Construction
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ActionImpl, CraftedAction, InferDataFromActionImpl, ActionImplParams } from "./types/actions.js";
|
|
2
|
+
import type { CrafterConfig, CrafterSchemas, CrafterErrors, CrafterCallbacks } from "./types/config.js";
|
|
3
|
+
import type { InferResult } from "./types/inference.js";
|
|
4
|
+
/**
|
|
5
|
+
* Builder class for creating type-safe server actions with validation, error handling, and callbacks.
|
|
6
|
+
*/
|
|
7
|
+
declare class Crafter<TConfig extends CrafterConfig, TSchemas extends CrafterSchemas, TErrors extends CrafterErrors, TCallbacks extends CrafterCallbacks<TConfig, TSchemas, TErrors, TData>, TData> {
|
|
8
|
+
private readonly _config;
|
|
9
|
+
private readonly _schemas;
|
|
10
|
+
private readonly _errors;
|
|
11
|
+
private readonly _callbacks;
|
|
12
|
+
private readonly _actionImpl?;
|
|
13
|
+
constructor(config: TConfig, schemas: TSchemas, errors: TErrors, callbacks: TCallbacks, actionImpl?: ActionImpl<TConfig, TSchemas, TErrors, TData>);
|
|
14
|
+
/**
|
|
15
|
+
* Defines validation schemas for input, output, and bind arguments.
|
|
16
|
+
* Resets previously defined actions and callbacks.
|
|
17
|
+
*/
|
|
18
|
+
schemas<TNewSchemas extends CrafterSchemas>(schemas: TNewSchemas): Crafter<TConfig, TNewSchemas, TErrors, Record<string, never>, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* Defines error functions for returning typed errors from actions.
|
|
21
|
+
* Resets previously defined actions and callbacks.
|
|
22
|
+
*/
|
|
23
|
+
errors<const TNewErrors extends CrafterErrors>(errors: TNewErrors): Crafter<TConfig, TSchemas, TNewErrors, Record<string, never>, unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Defines the action implementation function containing business logic.
|
|
26
|
+
* Resets previously defined callbacks.
|
|
27
|
+
*/
|
|
28
|
+
action<TFn extends (params: ActionImplParams<TConfig, TSchemas, TErrors, TData>) => Promise<unknown>>(fn: TFn): Crafter<TConfig, TSchemas, TErrors, Record<string, never>, InferDataFromActionImpl<TFn>>;
|
|
29
|
+
/**
|
|
30
|
+
* Defines lifecycle callbacks for action execution.
|
|
31
|
+
* Must be called after action() for correct type inference.
|
|
32
|
+
*/
|
|
33
|
+
callbacks<TNewCallbacks extends CrafterCallbacks<TConfig, TSchemas, TErrors, TData>>(callbacks: TNewCallbacks): Crafter<TConfig, TSchemas, TErrors, TNewCallbacks, TData>;
|
|
34
|
+
/**
|
|
35
|
+
* Builds and returns the final executable action function.
|
|
36
|
+
*/
|
|
37
|
+
craft(): CraftedAction<TConfig, TSchemas, TErrors, TData>;
|
|
38
|
+
/** Orchestrates action execution including validation, business logic, callbacks, and result formatting. */
|
|
39
|
+
private _runAction;
|
|
40
|
+
/**
|
|
41
|
+
* Extracts bind arguments, previous state, and input from raw action arguments.
|
|
42
|
+
*/
|
|
43
|
+
private _extractActionArgs;
|
|
44
|
+
/**
|
|
45
|
+
* Transforms internal Result objects to client-facing action result format.
|
|
46
|
+
*/
|
|
47
|
+
private _toActionResult;
|
|
48
|
+
/**
|
|
49
|
+
* Handles uncaught exceptions during action execution.
|
|
50
|
+
*/
|
|
51
|
+
private _handleThrownError;
|
|
52
|
+
/**
|
|
53
|
+
* Validates input using the shared helper.
|
|
54
|
+
*/
|
|
55
|
+
private _validateInput;
|
|
56
|
+
/**
|
|
57
|
+
* Validates bound arguments using the configured bind schemas.
|
|
58
|
+
*/
|
|
59
|
+
private _validateBindArgs;
|
|
60
|
+
/**
|
|
61
|
+
* Validates output data using the configured output schema.
|
|
62
|
+
*/
|
|
63
|
+
private _validateOutput;
|
|
64
|
+
/**
|
|
65
|
+
* Executes appropriate lifecycle callbacks based on the action result.
|
|
66
|
+
*/
|
|
67
|
+
private _executeCallbacks;
|
|
68
|
+
/**
|
|
69
|
+
* Creates error functions that return Result objects when called by action implementations.
|
|
70
|
+
*/
|
|
71
|
+
private _buildErrorFunctions;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new Crafter instance for building type-safe server actions.
|
|
75
|
+
*/
|
|
76
|
+
export declare function create<TConfig extends CrafterConfig = CrafterConfig>(config?: TConfig): Crafter<TConfig, Record<string, never>, Record<string, never>, Record<string, never>, unknown>;
|
|
77
|
+
/**
|
|
78
|
+
* Creates an appropriate initial state for any action based on its configuration.
|
|
79
|
+
*
|
|
80
|
+
* For useActionState actions: returns StatefulApiResult with error and values
|
|
81
|
+
* For functional format actions: returns Result.err() with error
|
|
82
|
+
* For regular actions: returns ApiResult with error
|
|
83
|
+
*
|
|
84
|
+
* Usage:
|
|
85
|
+
* - useActionState: const [state, action] = useActionState(myAction, initial(myAction))
|
|
86
|
+
* - useState: const [state, setState] = useState(initial(myAction))
|
|
87
|
+
*/
|
|
88
|
+
export declare function initial<TAction>(action: TAction): InferResult<TAction>;
|
|
89
|
+
export {};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { safeExecuteCallback } from "./core/callbacks.js";
|
|
2
|
+
import { createUnhandledErrorResult, createImplicitReturnErrorResult, } from "./core/errors.js";
|
|
3
|
+
import { log } from "./core/logging.js";
|
|
4
|
+
import { serializeRawInput, convertToClientError, } from "./core/transformation.js";
|
|
5
|
+
import { validateInput, validateBindArgs, validateOutput, } from "./core/validation.js";
|
|
6
|
+
import { EXTERNAL_ERROR_TYPES, } from "./types/errors.js";
|
|
7
|
+
import { err, isOk, isResultOk, isResultErr, isErr } from "./types/result.js";
|
|
8
|
+
import { unstable_rethrow } from "next/navigation.js";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// CRAFTER CLASS - TYPE-SAFE ACTION BUILDER
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Builder class for creating type-safe server actions with validation, error handling, and callbacks.
|
|
14
|
+
*/
|
|
15
|
+
class Crafter {
|
|
16
|
+
_config;
|
|
17
|
+
_schemas;
|
|
18
|
+
_errors;
|
|
19
|
+
_callbacks;
|
|
20
|
+
_actionImpl;
|
|
21
|
+
constructor(config, schemas, errors, callbacks, actionImpl) {
|
|
22
|
+
this._config = config;
|
|
23
|
+
this._schemas = schemas;
|
|
24
|
+
this._errors = errors;
|
|
25
|
+
this._callbacks = callbacks;
|
|
26
|
+
this._actionImpl = actionImpl;
|
|
27
|
+
}
|
|
28
|
+
// --------------------------------------------------------------------------
|
|
29
|
+
// FLUENT API METHODS
|
|
30
|
+
// --------------------------------------------------------------------------
|
|
31
|
+
/**
|
|
32
|
+
* Defines validation schemas for input, output, and bind arguments.
|
|
33
|
+
* Resets previously defined actions and callbacks.
|
|
34
|
+
*/
|
|
35
|
+
schemas(schemas) {
|
|
36
|
+
return new Crafter(this._config, schemas, this._errors, {}, undefined);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Defines error functions for returning typed errors from actions.
|
|
40
|
+
* Resets previously defined actions and callbacks.
|
|
41
|
+
*/
|
|
42
|
+
errors(errors) {
|
|
43
|
+
return new Crafter(this._config, this._schemas, errors, {}, undefined);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Defines the action implementation function containing business logic.
|
|
47
|
+
* Resets previously defined callbacks.
|
|
48
|
+
*/
|
|
49
|
+
action(fn) {
|
|
50
|
+
return new Crafter(this._config, this._schemas, this._errors, {}, fn);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Defines lifecycle callbacks for action execution.
|
|
54
|
+
* Must be called after action() for correct type inference.
|
|
55
|
+
*/
|
|
56
|
+
callbacks(callbacks) {
|
|
57
|
+
return new Crafter(this._config, this._schemas, this._errors, callbacks, this._actionImpl);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Builds and returns the final executable action function.
|
|
61
|
+
*/
|
|
62
|
+
craft() {
|
|
63
|
+
if (!this._actionImpl) {
|
|
64
|
+
throw new Error("Action implementation is not defined. Call .action() before calling .craft().");
|
|
65
|
+
}
|
|
66
|
+
const craftedAction = (...args) => {
|
|
67
|
+
return this._runAction(args);
|
|
68
|
+
};
|
|
69
|
+
// Attach the action's config for runtime inspection (used by `initial()`)
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
craftedAction.__ac_config = this._config;
|
|
72
|
+
return craftedAction;
|
|
73
|
+
}
|
|
74
|
+
// --------------------------------------------------------------------------
|
|
75
|
+
// ACTION EXECUTION
|
|
76
|
+
// --------------------------------------------------------------------------
|
|
77
|
+
/** Orchestrates action execution including validation, business logic, callbacks, and result formatting. */
|
|
78
|
+
async _runAction(args) {
|
|
79
|
+
// We know this exists because craft() verifies it
|
|
80
|
+
const actionImpl = this._actionImpl;
|
|
81
|
+
// Extract bindArgs, prevState, and input from the raw args
|
|
82
|
+
const { bindArgs, prevState, input: rawInput, } = this._extractActionArgs(args);
|
|
83
|
+
// Check for custom error handler
|
|
84
|
+
const handleThrownErrorFn = this._config.handleThrownError
|
|
85
|
+
? (error) => err(this._config.handleThrownError(error))
|
|
86
|
+
: null;
|
|
87
|
+
// Create callback metadata passed to all callbacks
|
|
88
|
+
const callbackMetadata = {
|
|
89
|
+
rawInput,
|
|
90
|
+
prevState,
|
|
91
|
+
validatedInput: undefined, // Set after validation
|
|
92
|
+
validatedBindArgs: undefined, // Set after validation
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
// Validate input and return on failure
|
|
96
|
+
const inputValidation = await this._validateInput(rawInput);
|
|
97
|
+
if (!isOk(inputValidation)) {
|
|
98
|
+
await this._executeCallbacks(inputValidation, callbackMetadata);
|
|
99
|
+
return this._toActionResult(inputValidation, rawInput);
|
|
100
|
+
}
|
|
101
|
+
// Update metadata with validated input
|
|
102
|
+
callbackMetadata.validatedInput = inputValidation.value;
|
|
103
|
+
// Validate bound arguments and return on failure
|
|
104
|
+
const bindArgsValidation = await this._validateBindArgs(bindArgs);
|
|
105
|
+
if (!isOk(bindArgsValidation)) {
|
|
106
|
+
await this._executeCallbacks(bindArgsValidation, callbackMetadata);
|
|
107
|
+
return this._toActionResult(bindArgsValidation, rawInput);
|
|
108
|
+
}
|
|
109
|
+
// Update metadata with validated bind args
|
|
110
|
+
callbackMetadata.validatedBindArgs = bindArgsValidation.value;
|
|
111
|
+
// Execute the user's action implementation
|
|
112
|
+
const actionImplResult = await actionImpl({
|
|
113
|
+
input: inputValidation.value,
|
|
114
|
+
bindArgs: bindArgsValidation.value,
|
|
115
|
+
errors: this._buildErrorFunctions(),
|
|
116
|
+
metadata: { rawInput, prevState },
|
|
117
|
+
});
|
|
118
|
+
// Return on `undefined` (implicit return error)
|
|
119
|
+
if (actionImplResult === undefined) {
|
|
120
|
+
const implicitReturnError = createImplicitReturnErrorResult();
|
|
121
|
+
await this._executeCallbacks(implicitReturnError, callbackMetadata);
|
|
122
|
+
return this._toActionResult(implicitReturnError, rawInput);
|
|
123
|
+
}
|
|
124
|
+
let finalResult;
|
|
125
|
+
// Process different return types from the action
|
|
126
|
+
if (isResultErr(actionImplResult)) {
|
|
127
|
+
finalResult = actionImplResult;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const outputData = isResultOk(actionImplResult)
|
|
131
|
+
? actionImplResult.value
|
|
132
|
+
: actionImplResult;
|
|
133
|
+
finalResult = await this._validateOutput(outputData);
|
|
134
|
+
}
|
|
135
|
+
// Execute callbacks and return final result
|
|
136
|
+
await this._executeCallbacks(finalResult, callbackMetadata);
|
|
137
|
+
// Use validated input for the values field on a successful run
|
|
138
|
+
const inputForValues = isOk(finalResult)
|
|
139
|
+
? this._schemas.inputSchema
|
|
140
|
+
? inputValidation.value
|
|
141
|
+
: rawInput
|
|
142
|
+
: rawInput;
|
|
143
|
+
return this._toActionResult(finalResult, inputForValues);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
// Re-throw Next.js framework errors
|
|
147
|
+
unstable_rethrow(error);
|
|
148
|
+
// Handle unexpected thrown errors
|
|
149
|
+
try {
|
|
150
|
+
const errorResult = this._handleThrownError(error, handleThrownErrorFn);
|
|
151
|
+
await this._executeCallbacks(errorResult, callbackMetadata);
|
|
152
|
+
return this._toActionResult(errorResult, rawInput);
|
|
153
|
+
}
|
|
154
|
+
catch (handlerError) {
|
|
155
|
+
// If we catch another error here, then we're done
|
|
156
|
+
log(this._config.logger, "warn", "Error handling failure - both primary error and error handler threw", { primaryError: error, handlerError });
|
|
157
|
+
return this._toActionResult(createUnhandledErrorResult(), rawInput);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extracts bind arguments, previous state, and input from raw action arguments.
|
|
163
|
+
*/
|
|
164
|
+
_extractActionArgs(args) {
|
|
165
|
+
const numBindSchemas = this._schemas.bindSchemas?.length ?? 0;
|
|
166
|
+
if (this._config.useActionState) {
|
|
167
|
+
return {
|
|
168
|
+
bindArgs: args.slice(0, numBindSchemas),
|
|
169
|
+
prevState: args[numBindSchemas],
|
|
170
|
+
input: args[numBindSchemas + 1],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
bindArgs: args.slice(0, numBindSchemas),
|
|
175
|
+
// When useActionState is disabled the prevState parameter is never
|
|
176
|
+
// present, so we cast to never (or undefined) to satisfy the type.
|
|
177
|
+
prevState: undefined,
|
|
178
|
+
input: args[numBindSchemas],
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// --------------------------------------------------------------------------
|
|
182
|
+
// RESULT TRANSFORMATION
|
|
183
|
+
// --------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* Transforms internal Result objects to client-facing action result format.
|
|
186
|
+
*/
|
|
187
|
+
_toActionResult(result, inputForValues) {
|
|
188
|
+
// Convert internal errors to client-facing errors
|
|
189
|
+
const clientResult = isOk(result) ? result : err(convertToClientError(result.error));
|
|
190
|
+
// Handle useActionState format (always returns StatefulApiResult)
|
|
191
|
+
if (this._config.useActionState) {
|
|
192
|
+
if (isOk(clientResult)) {
|
|
193
|
+
const successValues = this._schemas.inputSchema
|
|
194
|
+
? inputForValues
|
|
195
|
+
: serializeRawInput(inputForValues);
|
|
196
|
+
return {
|
|
197
|
+
success: true,
|
|
198
|
+
data: clientResult.value,
|
|
199
|
+
values: successValues,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
success: false,
|
|
204
|
+
error: clientResult.error,
|
|
205
|
+
values: serializeRawInput(inputForValues),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const format = this._config.resultFormat ?? "api";
|
|
209
|
+
// Return functional format if configured
|
|
210
|
+
if (format === "functional") {
|
|
211
|
+
return clientResult;
|
|
212
|
+
}
|
|
213
|
+
// Default API format
|
|
214
|
+
if (isOk(clientResult)) {
|
|
215
|
+
return {
|
|
216
|
+
success: true,
|
|
217
|
+
data: clientResult.value,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: clientResult.error,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
// --------------------------------------------------------------------------
|
|
226
|
+
// ERROR HANDLING
|
|
227
|
+
// --------------------------------------------------------------------------
|
|
228
|
+
/**
|
|
229
|
+
* Handles uncaught exceptions during action execution.
|
|
230
|
+
*/
|
|
231
|
+
_handleThrownError(error, customHandler) {
|
|
232
|
+
const caughtErrorResult = customHandler
|
|
233
|
+
? customHandler(error)
|
|
234
|
+
: createUnhandledErrorResult();
|
|
235
|
+
return caughtErrorResult;
|
|
236
|
+
}
|
|
237
|
+
// --------------------------------------------------------------------------
|
|
238
|
+
// VALIDATION
|
|
239
|
+
// --------------------------------------------------------------------------
|
|
240
|
+
/**
|
|
241
|
+
* Validates input using the shared helper.
|
|
242
|
+
*/
|
|
243
|
+
_validateInput(rawInput) {
|
|
244
|
+
return validateInput(this._schemas, this._config, rawInput);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Validates bound arguments using the configured bind schemas.
|
|
248
|
+
*/
|
|
249
|
+
_validateBindArgs(bindArgs) {
|
|
250
|
+
return validateBindArgs(this._schemas, this._config, bindArgs);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Validates output data using the configured output schema.
|
|
254
|
+
*/
|
|
255
|
+
_validateOutput(data) {
|
|
256
|
+
return validateOutput(this._schemas, this._config, data);
|
|
257
|
+
}
|
|
258
|
+
// --------------------------------------------------------------------------
|
|
259
|
+
// CALLBACKS
|
|
260
|
+
// --------------------------------------------------------------------------
|
|
261
|
+
/**
|
|
262
|
+
* Executes appropriate lifecycle callbacks based on the action result.
|
|
263
|
+
*/
|
|
264
|
+
async _executeCallbacks(result, metadata) {
|
|
265
|
+
const callbacks = this._callbacks;
|
|
266
|
+
// Success path
|
|
267
|
+
if (isOk(result)) {
|
|
268
|
+
await safeExecuteCallback(callbacks.onSuccess
|
|
269
|
+
? () => callbacks.onSuccess({ data: result.value, metadata })
|
|
270
|
+
: undefined, "onSuccess", (level, msg, details) => log(this._config.logger, level, msg, details));
|
|
271
|
+
}
|
|
272
|
+
// Error path
|
|
273
|
+
if (isErr(result)) {
|
|
274
|
+
await safeExecuteCallback(callbacks.onError
|
|
275
|
+
? () => callbacks.onError({ error: result.error, metadata })
|
|
276
|
+
: undefined, "onError", (level, msg, details) => log(this._config.logger, level, msg, details));
|
|
277
|
+
}
|
|
278
|
+
// onSettled always runs, regardless of result
|
|
279
|
+
const finalResult = this._toActionResult(result);
|
|
280
|
+
await safeExecuteCallback(callbacks.onSettled
|
|
281
|
+
? () => callbacks.onSettled({ result: finalResult, metadata })
|
|
282
|
+
: undefined, "onSettled", (level, msg, details) => log(this._config.logger, level, msg, details));
|
|
283
|
+
}
|
|
284
|
+
// --------------------------------------------------------------------------
|
|
285
|
+
// UTILITY METHODS
|
|
286
|
+
// --------------------------------------------------------------------------
|
|
287
|
+
/**
|
|
288
|
+
* Creates error functions that return Result objects when called by action implementations.
|
|
289
|
+
*/
|
|
290
|
+
_buildErrorFunctions() {
|
|
291
|
+
const errorFns = {};
|
|
292
|
+
for (const [key, errorDefFn] of Object.entries(this._errors)) {
|
|
293
|
+
errorFns[key] = ((...args) => err(errorDefFn(...args)));
|
|
294
|
+
}
|
|
295
|
+
return errorFns;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// ============================================================================
|
|
299
|
+
// PUBLIC API EXPORTS
|
|
300
|
+
// ============================================================================
|
|
301
|
+
/**
|
|
302
|
+
* Creates a new Crafter instance for building type-safe server actions.
|
|
303
|
+
*/
|
|
304
|
+
export function create(config) {
|
|
305
|
+
return new Crafter(config ?? {}, {}, {}, {}, undefined);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Creates an appropriate initial state for any action based on its configuration.
|
|
309
|
+
*
|
|
310
|
+
* For useActionState actions: returns StatefulApiResult with error and values
|
|
311
|
+
* For functional format actions: returns Result.err() with error
|
|
312
|
+
* For regular actions: returns ApiResult with error
|
|
313
|
+
*
|
|
314
|
+
* Usage:
|
|
315
|
+
* - useActionState: const [state, action] = useActionState(myAction, initial(myAction))
|
|
316
|
+
* - useState: const [state, setState] = useState(initial(myAction))
|
|
317
|
+
*/
|
|
318
|
+
export function initial(action) {
|
|
319
|
+
const error = {
|
|
320
|
+
type: EXTERNAL_ERROR_TYPES.INITIAL_STATE,
|
|
321
|
+
message: "No action has been executed yet",
|
|
322
|
+
};
|
|
323
|
+
// Attempt to read the ActionCraft config attached during craft()
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
325
|
+
const cfg = action?.__ac_config;
|
|
326
|
+
// Functional format -> Result<_, _>
|
|
327
|
+
if (cfg?.resultFormat === "functional") {
|
|
328
|
+
return err(error);
|
|
329
|
+
}
|
|
330
|
+
// useActionState enabled -> StatefulApiResult
|
|
331
|
+
if (cfg?.useActionState) {
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
error,
|
|
335
|
+
values: undefined,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Default ApiResult shape
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
error,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=actioncraft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actioncraft.js","sourceRoot":"","sources":["../src/actioncraft.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executes a callback function safely.
|
|
3
|
+
* Any error thrown by the callback is caught and logged (if a logFn is supplied)
|
|
4
|
+
* so that it never interrupts the main action flow.
|
|
5
|
+
*/
|
|
6
|
+
export declare function safeExecuteCallback(callback: (() => Promise<void> | void) | undefined, callbackName: string, logFn?: (level: "error" | "warn", message: string, details?: unknown) => void): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executes a callback function safely.
|
|
3
|
+
* Any error thrown by the callback is caught and logged (if a logFn is supplied)
|
|
4
|
+
* so that it never interrupts the main action flow.
|
|
5
|
+
*/
|
|
6
|
+
export async function safeExecuteCallback(callback, callbackName,
|
|
7
|
+
// Logger accepts (level, message, details?)
|
|
8
|
+
logFn) {
|
|
9
|
+
if (!callback)
|
|
10
|
+
return;
|
|
11
|
+
try {
|
|
12
|
+
await callback();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (logFn) {
|
|
16
|
+
logFn("error", `Error in ${callbackName} callback`, error);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=callbacks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callbacks.js","sourceRoot":"","sources":["../../src/core/callbacks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAkD,EAClD,YAAoB;AACpB,4CAA4C;AAC5C,KAA6E;IAE7E,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtB,IAAI,CAAC;QACH,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,OAAO,EAAE,YAAY,YAAY,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "../standard-schema.js";
|
|
2
|
+
import { EXTERNAL_ERROR_TYPES, INTERNAL_ERROR_TYPES } from "../types/errors.js";
|
|
3
|
+
import type { UnhandledError, ImplicitReturnError, InternalLogicError, ValidationErrorFormat } from "../types/errors.js";
|
|
4
|
+
import type { Result } from "../types/result.js";
|
|
5
|
+
export declare const UNHANDLED_ERROR: UnhandledError;
|
|
6
|
+
export declare const IMPLICIT_RETURN_ERROR: ImplicitReturnError;
|
|
7
|
+
/**
|
|
8
|
+
* Creates internal logic errors with custom messages.
|
|
9
|
+
*/
|
|
10
|
+
export declare const createInternalLogicError: (message: string) => InternalLogicError;
|
|
11
|
+
/**
|
|
12
|
+
* Creates Result objects for unhandled errors.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createUnhandledErrorResult<TData = never, TError = UnhandledError>(): Result<TData, TError>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates Result objects for implicit return errors.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createImplicitReturnErrorResult<TData = never, TError = ImplicitReturnError>(): Result<TData, TError>;
|
|
19
|
+
/**
|
|
20
|
+
* Formats validation issues into structured error objects based on the configured format.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatValidationIssues(issues: readonly StandardSchemaV1.Issue[], format: "flattened" | "nested"): ValidationErrorFormat;
|
|
23
|
+
type ValidationErrorType = typeof EXTERNAL_ERROR_TYPES.INPUT_VALIDATION | typeof EXTERNAL_ERROR_TYPES.BIND_ARGS_VALIDATION | typeof INTERNAL_ERROR_TYPES.OUTPUT_VALIDATION;
|
|
24
|
+
/**
|
|
25
|
+
* Creates validation error objects.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createValidationError<TError>(type: ValidationErrorType, message: string, errorStructure: ValidationErrorFormat): TError;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { EXTERNAL_ERROR_TYPES, INTERNAL_ERROR_TYPES } from "../types/errors.js";
|
|
2
|
+
import { err } from "../types/result.js";
|
|
3
|
+
// ===========================================================================
|
|
4
|
+
// CONSTANTS
|
|
5
|
+
// ===========================================================================
|
|
6
|
+
export const UNHANDLED_ERROR = {
|
|
7
|
+
type: EXTERNAL_ERROR_TYPES.UNHANDLED,
|
|
8
|
+
message: "An unhandled error occurred",
|
|
9
|
+
};
|
|
10
|
+
export const IMPLICIT_RETURN_ERROR = {
|
|
11
|
+
type: INTERNAL_ERROR_TYPES.IMPLICIT_RETURN,
|
|
12
|
+
message: "Action implementation must return a value",
|
|
13
|
+
};
|
|
14
|
+
// ===========================================================================
|
|
15
|
+
// FACTORY HELPERS
|
|
16
|
+
// ===========================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Creates internal logic errors with custom messages.
|
|
19
|
+
*/
|
|
20
|
+
export const createInternalLogicError = (message) => ({
|
|
21
|
+
type: INTERNAL_ERROR_TYPES.INTERNAL_LOGIC,
|
|
22
|
+
message,
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Creates Result objects for unhandled errors.
|
|
26
|
+
*/
|
|
27
|
+
export function createUnhandledErrorResult() {
|
|
28
|
+
return err({ ...UNHANDLED_ERROR });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates Result objects for implicit return errors.
|
|
32
|
+
*/
|
|
33
|
+
export function createImplicitReturnErrorResult() {
|
|
34
|
+
return err({ ...IMPLICIT_RETURN_ERROR });
|
|
35
|
+
}
|
|
36
|
+
// ===========================================================================
|
|
37
|
+
// VALIDATION-ERROR STRUCTURING HELPERS
|
|
38
|
+
// ===========================================================================
|
|
39
|
+
/**
|
|
40
|
+
* Normalises Standard Schema path segments to string|number for serialization.
|
|
41
|
+
*/
|
|
42
|
+
function _normalisePath(path) {
|
|
43
|
+
if (!path)
|
|
44
|
+
return [];
|
|
45
|
+
return path
|
|
46
|
+
.map((segment) => {
|
|
47
|
+
if (typeof segment === "symbol")
|
|
48
|
+
return undefined;
|
|
49
|
+
if (typeof segment === "object" && segment !== null && "key" in segment) {
|
|
50
|
+
const key = segment.key;
|
|
51
|
+
return typeof key === "symbol" ? undefined : key;
|
|
52
|
+
}
|
|
53
|
+
return segment;
|
|
54
|
+
})
|
|
55
|
+
.filter((p) => p !== undefined);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Formats validation issues into structured error objects based on the configured format.
|
|
59
|
+
*/
|
|
60
|
+
export function formatValidationIssues(issues, format) {
|
|
61
|
+
if (format === "nested") {
|
|
62
|
+
const formErrors = [];
|
|
63
|
+
const fieldErrors = {};
|
|
64
|
+
for (const issue of issues) {
|
|
65
|
+
const currentPath = _normalisePath(issue.path);
|
|
66
|
+
if (currentPath.length === 0) {
|
|
67
|
+
formErrors.push(issue.message);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const pathKey = currentPath.join(".");
|
|
71
|
+
if (!fieldErrors[pathKey])
|
|
72
|
+
fieldErrors[pathKey] = [];
|
|
73
|
+
fieldErrors[pathKey].push(issue.message);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { formErrors, fieldErrors };
|
|
77
|
+
}
|
|
78
|
+
// Default to 'flattened'
|
|
79
|
+
return {
|
|
80
|
+
issues: issues.map(({ path, message }) => ({
|
|
81
|
+
path: _normalisePath(path),
|
|
82
|
+
message,
|
|
83
|
+
})),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function _buildFlattenedValidationError(type, message, issues) {
|
|
87
|
+
return { type, message, issues };
|
|
88
|
+
}
|
|
89
|
+
function _buildNestedValidationError(type, message, formErrors, fieldErrors) {
|
|
90
|
+
return { type, message, formErrors, fieldErrors };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Creates validation error objects.
|
|
94
|
+
*/
|
|
95
|
+
export function createValidationError(type, message, errorStructure) {
|
|
96
|
+
if ("issues" in errorStructure) {
|
|
97
|
+
return _buildFlattenedValidationError(type, message, errorStructure.issues);
|
|
98
|
+
}
|
|
99
|
+
return _buildNestedValidationError(type, message, errorStructure.formErrors, errorStructure.fieldErrors);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CrafterConfig } from "../types/config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight wrapper around the optional logger in `CrafterConfig`.
|
|
4
|
+
*/
|
|
5
|
+
export type Logger = NonNullable<CrafterConfig["logger"]>;
|
|
6
|
+
export declare function log(logger: CrafterConfig["logger"], level: "error" | "warn", message: string, details?: unknown): void;
|