server-act 1.1.2 → 1.1.4

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Chung Wei Leong
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/dist/index.d.mts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { z } from 'zod';
2
2
 
3
+ declare const unsetMarker: unique symbol;
4
+ type UnsetMarker = typeof unsetMarker;
3
5
  type Prettify<T> = {
4
6
  [P in keyof T]: T[P];
5
7
  } & {};
6
- declare const unsetMarker: unique symbol;
7
- type UnsetMarker = typeof unsetMarker;
8
8
  type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
9
- type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker ? undefined : TParser extends z.ZodType ? TParser[TType extends 'in' ? '_input' : '_output'] : never;
9
+ type InferParserType<T, TType extends 'in' | 'out'> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends 'in' ? '_input' : '_output'] : T extends z.ZodType ? T[TType extends 'in' ? '_input' : '_output'] : never;
10
+ type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
10
11
  type InferContextType<T> = T extends UnsetMarker ? undefined : T;
11
12
  interface ActionParams<TInput = unknown, TContext = unknown> {
12
13
  _input: TInput;
@@ -32,8 +33,8 @@ interface ActionBuilder<TParams extends ActionParams> {
32
33
  */
33
34
  action: <TOutput>(action: (params: {
34
35
  ctx: InferContextType<TParams['_context']>;
35
- input: InferParserType<TParams['_input'], 'out'>;
36
- }) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
36
+ input: InferInputType<TParams['_input'], 'out'>;
37
+ }) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferInputType<TParams['_input'], 'in'>>) => Promise<TOutput>;
37
38
  /**
38
39
  * Create an action for React `useFormState`
39
40
  */
@@ -41,11 +42,11 @@ interface ActionBuilder<TParams extends ActionParams> {
41
42
  ctx: InferContextType<TParams['_context']>;
42
43
  prevState: any;
43
44
  } & ({
44
- input: InferParserType<TParams['_input'], 'out'>;
45
+ input: InferInputType<TParams['_input'], 'out'>;
45
46
  formErrors?: undefined;
46
47
  } | {
47
48
  input?: undefined;
48
- formErrors: z.ZodError<TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown> ? InferParserType<T, 'in'> : InferParserType<TParams['_input'], 'in'>>;
49
+ formErrors: z.ZodError<InferInputType<TParams['_input'], 'in'>>;
49
50
  })>) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
50
51
  }
51
52
  /**
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { z } from 'zod';
2
2
 
3
+ declare const unsetMarker: unique symbol;
4
+ type UnsetMarker = typeof unsetMarker;
3
5
  type Prettify<T> = {
4
6
  [P in keyof T]: T[P];
5
7
  } & {};
6
- declare const unsetMarker: unique symbol;
7
- type UnsetMarker = typeof unsetMarker;
8
8
  type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
9
- type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker ? undefined : TParser extends z.ZodType ? TParser[TType extends 'in' ? '_input' : '_output'] : never;
9
+ type InferParserType<T, TType extends 'in' | 'out'> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends 'in' ? '_input' : '_output'] : T extends z.ZodType ? T[TType extends 'in' ? '_input' : '_output'] : never;
10
+ type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
10
11
  type InferContextType<T> = T extends UnsetMarker ? undefined : T;
11
12
  interface ActionParams<TInput = unknown, TContext = unknown> {
12
13
  _input: TInput;
@@ -32,8 +33,8 @@ interface ActionBuilder<TParams extends ActionParams> {
32
33
  */
33
34
  action: <TOutput>(action: (params: {
34
35
  ctx: InferContextType<TParams['_context']>;
35
- input: InferParserType<TParams['_input'], 'out'>;
36
- }) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
36
+ input: InferInputType<TParams['_input'], 'out'>;
37
+ }) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferInputType<TParams['_input'], 'in'>>) => Promise<TOutput>;
37
38
  /**
38
39
  * Create an action for React `useFormState`
39
40
  */
@@ -41,11 +42,11 @@ interface ActionBuilder<TParams extends ActionParams> {
41
42
  ctx: InferContextType<TParams['_context']>;
42
43
  prevState: any;
43
44
  } & ({
44
- input: InferParserType<TParams['_input'], 'out'>;
45
+ input: InferInputType<TParams['_input'], 'out'>;
45
46
  formErrors?: undefined;
46
47
  } | {
47
48
  input?: undefined;
48
- formErrors: z.ZodError<TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown> ? InferParserType<T, 'in'> : InferParserType<TParams['_input'], 'in'>>;
49
+ formErrors: z.ZodError<InferInputType<TParams['_input'], 'in'>>;
49
50
  })>) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
50
51
  }
51
52
  /**
package/dist/index.js CHANGED
@@ -1,175 +1,108 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- serverAct: () => serverAct
34
- });
35
- module.exports = __toCommonJS(src_exports);
1
+ Object.defineProperty(exports, '__esModule', { value: true });
36
2
 
37
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
38
- var zod = __toESM(require("zod"));
39
-
40
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
41
- var identifierRegex = /[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*/u;
42
- function joinPath(path) {
43
- if (path.length === 1) {
44
- return path[0].toString();
45
- }
46
- return path.reduce((acc, item) => {
47
- if (typeof item === "number") {
48
- return acc + "[" + item.toString() + "]";
49
- }
50
- if (item.includes('"')) {
51
- return acc + '["' + escapeQuotes(item) + '"]';
3
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
4
+ try {
5
+ var info = gen[key](arg);
6
+ var value = info.value;
7
+ } catch (error) {
8
+ reject(error);
9
+ return;
52
10
  }
53
- if (!identifierRegex.test(item)) {
54
- return acc + '["' + item + '"]';
55
- }
56
- const separator = acc.length === 0 ? "" : ".";
57
- return acc + separator + item;
58
- }, "");
59
- }
60
- function escapeQuotes(str) {
61
- return str.replace(/"/g, '\\"');
62
- }
63
-
64
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
65
- function isNonEmptyArray(value) {
66
- return value.length !== 0;
67
- }
68
-
69
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
70
- var MAX_ISSUES_IN_MESSAGE = 99;
71
- var ISSUE_SEPARATOR = "; ";
72
- var UNION_SEPARATOR = ", or ";
73
- var PREFIX = "Validation error";
74
- var PREFIX_SEPARATOR = ": ";
75
- var ValidationError = class extends Error {
76
- details;
77
- name;
78
- constructor(message, details = []) {
79
- super(message);
80
- this.details = details;
81
- this.name = "ZodValidationError";
82
- }
83
- toString() {
84
- return this.message;
85
- }
86
- };
87
- function getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {
88
- if (issue.code === "invalid_union") {
89
- return issue.unionErrors.reduce((acc, zodError) => {
90
- const newIssues = zodError.issues.map((issue2) => getMessageFromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
91
- if (!acc.includes(newIssues)) {
92
- acc.push(newIssues);
93
- }
94
- return acc;
95
- }, []).join(unionSeparator);
96
- }
97
- if (isNonEmptyArray(issue.path)) {
98
- if (issue.path.length === 1) {
99
- const identifier = issue.path[0];
100
- if (typeof identifier === "number") {
101
- return `${issue.message} at index ${identifier}`;
102
- }
11
+ if (info.done) {
12
+ resolve(value);
13
+ } else {
14
+ Promise.resolve(value).then(_next, _throw);
103
15
  }
104
- return `${issue.message} at "${joinPath(issue.path)}"`;
105
- }
106
- return issue.message;
107
16
  }
108
- function conditionallyPrefixMessage(reason, prefix, prefixSeparator) {
109
- if (prefix !== null) {
110
- if (reason.length > 0) {
111
- return [prefix, reason].join(prefixSeparator);
112
- }
113
- return prefix;
114
- }
115
- if (reason.length > 0) {
116
- return reason;
117
- }
118
- return PREFIX;
17
+ function _async_to_generator(fn) {
18
+ return function() {
19
+ var self = this, args = arguments;
20
+ return new Promise(function(resolve, reject) {
21
+ var gen = fn.apply(self, args);
22
+ function _next(value) {
23
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
24
+ }
25
+ function _throw(err) {
26
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
27
+ }
28
+ _next(undefined);
29
+ });
30
+ };
119
31
  }
120
- function fromZodError(zodError, options = {}) {
121
- const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX } = options;
122
- const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
123
- const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);
124
- return new ValidationError(message, zodError.errors);
32
+ function _extends() {
33
+ _extends = Object.assign || function(target) {
34
+ for(var i = 1; i < arguments.length; i++){
35
+ var source = arguments[i];
36
+ for(var key in source){
37
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
38
+ target[key] = source[key];
39
+ }
40
+ }
41
+ }
42
+ return target;
43
+ };
44
+ return _extends.apply(this, arguments);
125
45
  }
126
-
127
- // src/index.ts
128
- var unsetMarker = Symbol("unsetMarker");
129
- var createNewServerActionBuilder = (def) => {
130
- return createServerActionBuilder(def);
46
+ const createNewServerActionBuilder = (def)=>{
47
+ return createServerActionBuilder(def);
131
48
  };
132
- var createServerActionBuilder = (initDef = {}) => {
133
- const _def = {
134
- input: void 0,
135
- middleware: void 0,
136
- ...initDef
137
- };
138
- return {
139
- middleware: (middleware) => createServerActionBuilder({ ..._def, middleware }),
140
- input: (input) => createNewServerActionBuilder({ ..._def, input }),
141
- action: (action) => {
142
- return async (input) => {
143
- var _a;
144
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
145
- if (_def.input) {
146
- const result = _def.input.safeParse(input);
147
- if (!result.success) {
148
- throw fromZodError(result.error);
149
- }
150
- }
151
- return await action({ ctx, input });
152
- };
153
- },
154
- formAction: (action) => {
155
- return async (prevState, formData) => {
156
- var _a;
157
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
158
- if (_def.input) {
159
- const result = _def.input.safeParse(formData);
160
- if (!result.success) {
161
- return await action({ ctx, prevState, formErrors: result.error });
162
- }
163
- return await action({ ctx, prevState, input: result.data });
49
+ const createServerActionBuilder = (initDef = {})=>{
50
+ const _def = _extends({
51
+ input: undefined,
52
+ middleware: undefined
53
+ }, initDef);
54
+ return {
55
+ middleware: (middleware)=>createNewServerActionBuilder(_extends({}, _def, {
56
+ middleware
57
+ })),
58
+ input: (input)=>createNewServerActionBuilder(_extends({}, _def, {
59
+ input
60
+ })),
61
+ action: (action)=>{
62
+ return /*#__PURE__*/ _async_to_generator(function*(input) {
63
+ const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
64
+ if (_def.input) {
65
+ const result = _def.input.safeParse(input);
66
+ if (!result.success) {
67
+ console.error('❌ Input validation error:', result.error.errors);
68
+ throw new Error('Input validation error');
69
+ }
70
+ }
71
+ return yield action({
72
+ ctx,
73
+ input
74
+ });
75
+ });
76
+ },
77
+ formAction: (action)=>{
78
+ return /*#__PURE__*/ _async_to_generator(function*(prevState, formData) {
79
+ const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
80
+ if (_def.input) {
81
+ const result = _def.input.safeParse(formData);
82
+ if (!result.success) {
83
+ return yield action({
84
+ ctx,
85
+ prevState,
86
+ formErrors: result.error
87
+ });
88
+ }
89
+ return yield action({
90
+ ctx,
91
+ prevState,
92
+ input: result.data
93
+ });
94
+ }
95
+ return yield action({
96
+ ctx,
97
+ prevState,
98
+ input: undefined
99
+ });
100
+ });
164
101
  }
165
- return await action({ ctx, prevState, input: void 0 });
166
- };
167
- }
168
- };
102
+ };
169
103
  };
170
- var serverAct = createServerActionBuilder();
171
- // Annotate the CommonJS export names for ESM import in node:
172
- 0 && (module.exports = {
173
- serverAct
174
- });
175
- //# sourceMappingURL=index.js.map
104
+ /**
105
+ * Server action builder
106
+ */ const serverAct = createServerActionBuilder();
107
+
108
+ exports.serverAct = serverAct;
package/dist/index.mjs CHANGED
@@ -1,138 +1,106 @@
1
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
2
- import * as zod from "zod";
3
-
4
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
5
- var identifierRegex = /[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*/u;
6
- function joinPath(path) {
7
- if (path.length === 1) {
8
- return path[0].toString();
9
- }
10
- return path.reduce((acc, item) => {
11
- if (typeof item === "number") {
12
- return acc + "[" + item.toString() + "]";
13
- }
14
- if (item.includes('"')) {
15
- return acc + '["' + escapeQuotes(item) + '"]';
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
+ try {
3
+ var info = gen[key](arg);
4
+ var value = info.value;
5
+ } catch (error) {
6
+ reject(error);
7
+ return;
16
8
  }
17
- if (!identifierRegex.test(item)) {
18
- return acc + '["' + item + '"]';
19
- }
20
- const separator = acc.length === 0 ? "" : ".";
21
- return acc + separator + item;
22
- }, "");
23
- }
24
- function escapeQuotes(str) {
25
- return str.replace(/"/g, '\\"');
26
- }
27
-
28
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
29
- function isNonEmptyArray(value) {
30
- return value.length !== 0;
31
- }
32
-
33
- // ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
34
- var MAX_ISSUES_IN_MESSAGE = 99;
35
- var ISSUE_SEPARATOR = "; ";
36
- var UNION_SEPARATOR = ", or ";
37
- var PREFIX = "Validation error";
38
- var PREFIX_SEPARATOR = ": ";
39
- var ValidationError = class extends Error {
40
- details;
41
- name;
42
- constructor(message, details = []) {
43
- super(message);
44
- this.details = details;
45
- this.name = "ZodValidationError";
46
- }
47
- toString() {
48
- return this.message;
49
- }
50
- };
51
- function getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {
52
- if (issue.code === "invalid_union") {
53
- return issue.unionErrors.reduce((acc, zodError) => {
54
- const newIssues = zodError.issues.map((issue2) => getMessageFromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
55
- if (!acc.includes(newIssues)) {
56
- acc.push(newIssues);
57
- }
58
- return acc;
59
- }, []).join(unionSeparator);
60
- }
61
- if (isNonEmptyArray(issue.path)) {
62
- if (issue.path.length === 1) {
63
- const identifier = issue.path[0];
64
- if (typeof identifier === "number") {
65
- return `${issue.message} at index ${identifier}`;
66
- }
9
+ if (info.done) {
10
+ resolve(value);
11
+ } else {
12
+ Promise.resolve(value).then(_next, _throw);
67
13
  }
68
- return `${issue.message} at "${joinPath(issue.path)}"`;
69
- }
70
- return issue.message;
71
14
  }
72
- function conditionallyPrefixMessage(reason, prefix, prefixSeparator) {
73
- if (prefix !== null) {
74
- if (reason.length > 0) {
75
- return [prefix, reason].join(prefixSeparator);
76
- }
77
- return prefix;
78
- }
79
- if (reason.length > 0) {
80
- return reason;
81
- }
82
- return PREFIX;
15
+ function _async_to_generator(fn) {
16
+ return function() {
17
+ var self = this, args = arguments;
18
+ return new Promise(function(resolve, reject) {
19
+ var gen = fn.apply(self, args);
20
+ function _next(value) {
21
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
+ }
23
+ function _throw(err) {
24
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
+ }
26
+ _next(undefined);
27
+ });
28
+ };
83
29
  }
84
- function fromZodError(zodError, options = {}) {
85
- const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX } = options;
86
- const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
87
- const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);
88
- return new ValidationError(message, zodError.errors);
30
+ function _extends() {
31
+ _extends = Object.assign || function(target) {
32
+ for(var i = 1; i < arguments.length; i++){
33
+ var source = arguments[i];
34
+ for(var key in source){
35
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
36
+ target[key] = source[key];
37
+ }
38
+ }
39
+ }
40
+ return target;
41
+ };
42
+ return _extends.apply(this, arguments);
89
43
  }
90
-
91
- // src/index.ts
92
- var unsetMarker = Symbol("unsetMarker");
93
- var createNewServerActionBuilder = (def) => {
94
- return createServerActionBuilder(def);
44
+ const createNewServerActionBuilder = (def)=>{
45
+ return createServerActionBuilder(def);
95
46
  };
96
- var createServerActionBuilder = (initDef = {}) => {
97
- const _def = {
98
- input: void 0,
99
- middleware: void 0,
100
- ...initDef
101
- };
102
- return {
103
- middleware: (middleware) => createServerActionBuilder({ ..._def, middleware }),
104
- input: (input) => createNewServerActionBuilder({ ..._def, input }),
105
- action: (action) => {
106
- return async (input) => {
107
- var _a;
108
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
109
- if (_def.input) {
110
- const result = _def.input.safeParse(input);
111
- if (!result.success) {
112
- throw fromZodError(result.error);
113
- }
47
+ const createServerActionBuilder = (initDef = {})=>{
48
+ const _def = _extends({
49
+ input: undefined,
50
+ middleware: undefined
51
+ }, initDef);
52
+ return {
53
+ middleware: (middleware)=>createNewServerActionBuilder(_extends({}, _def, {
54
+ middleware
55
+ })),
56
+ input: (input)=>createNewServerActionBuilder(_extends({}, _def, {
57
+ input
58
+ })),
59
+ action: (action)=>{
60
+ return /*#__PURE__*/ _async_to_generator(function*(input) {
61
+ const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
62
+ if (_def.input) {
63
+ const result = _def.input.safeParse(input);
64
+ if (!result.success) {
65
+ console.error('❌ Input validation error:', result.error.errors);
66
+ throw new Error('Input validation error');
67
+ }
68
+ }
69
+ return yield action({
70
+ ctx,
71
+ input
72
+ });
73
+ });
74
+ },
75
+ formAction: (action)=>{
76
+ return /*#__PURE__*/ _async_to_generator(function*(prevState, formData) {
77
+ const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
78
+ if (_def.input) {
79
+ const result = _def.input.safeParse(formData);
80
+ if (!result.success) {
81
+ return yield action({
82
+ ctx,
83
+ prevState,
84
+ formErrors: result.error
85
+ });
86
+ }
87
+ return yield action({
88
+ ctx,
89
+ prevState,
90
+ input: result.data
91
+ });
92
+ }
93
+ return yield action({
94
+ ctx,
95
+ prevState,
96
+ input: undefined
97
+ });
98
+ });
114
99
  }
115
- return await action({ ctx, input });
116
- };
117
- },
118
- formAction: (action) => {
119
- return async (prevState, formData) => {
120
- var _a;
121
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
122
- if (_def.input) {
123
- const result = _def.input.safeParse(formData);
124
- if (!result.success) {
125
- return await action({ ctx, prevState, formErrors: result.error });
126
- }
127
- return await action({ ctx, prevState, input: result.data });
128
- }
129
- return await action({ ctx, prevState, input: void 0 });
130
- };
131
- }
132
- };
100
+ };
133
101
  };
134
- var serverAct = createServerActionBuilder();
135
- export {
136
- serverAct
137
- };
138
- //# sourceMappingURL=index.mjs.map
102
+ /**
103
+ * Server action builder
104
+ */ const serverAct = createServerActionBuilder();
105
+
106
+ export { serverAct };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-act",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "homepage": "https://github.com/chungweileong94/server-act#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,15 +11,25 @@
11
11
  },
12
12
  "main": "dist/index.js",
13
13
  "module": "dist/index.mjs",
14
- "types": "dist/index.d.ts",
14
+ "types": "./dist/index.d.ts",
15
15
  "exports": {
16
16
  ".": {
17
- "types": "./dist/index.d.ts",
18
- "import": "./dist/index.mjs",
19
- "require": "./dist/index.js"
20
- },
21
- "./package.json": "./package.json"
17
+ "import": {
18
+ "types": "./dist/index.d.mts",
19
+ "default": "./dist/index.mjs"
20
+ },
21
+ "require": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ }
25
+ }
22
26
  },
27
+ "files": [
28
+ "dist",
29
+ "package.json",
30
+ "LICENSE",
31
+ "README.md"
32
+ ],
23
33
  "keywords": [
24
34
  "next",
25
35
  "nextjs",
@@ -34,21 +44,26 @@
34
44
  "author": "chungweileong94",
35
45
  "license": "MIT",
36
46
  "devDependencies": {
47
+ "bunchee": "^4.3.3",
37
48
  "eslint": "^8.49.0",
38
49
  "eslint-config-whiteroom": "^3.3.0",
39
50
  "prettier": "^3.0.3",
40
- "tsup": "^7.2.0",
41
51
  "typescript": "^5.2.2",
42
52
  "zod": "^3.22.2",
43
- "zod-form-data": "^2.0.2",
44
- "zod-validation-error": "^1.5.0"
53
+ "zod-form-data": "^2.0.2"
45
54
  },
46
55
  "peerDependencies": {
47
56
  "typescript": "^5.2.2",
48
57
  "zod": "^3.22.2"
49
58
  },
59
+ "peerDependenciesMeta": {
60
+ "typescript": {
61
+ "optional": true
62
+ }
63
+ },
50
64
  "scripts": {
51
- "build": "tsup",
65
+ "build": "bunchee",
66
+ "dev": "bunchee -w",
52
67
  "test": "vitest run",
53
68
  "lint": "eslint src --ext .ts"
54
69
  }
package/.eslintrc.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "parserOptions": {
3
- "project": "./tsconfig.json"
4
- },
5
- "extends": [
6
- "whiteroom"
7
- ],
8
- "ignorePatterns": [
9
- "dist/**"
10
- ]
11
- }
package/.prettierrc.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "arrowParens": "always",
3
- "bracketSpacing": false,
4
- "htmlWhitespaceSensitivity": "css",
5
- "insertPragma": false,
6
- "bracketSameLine": false,
7
- "jsxSingleQuote": false,
8
- "printWidth": 120,
9
- "proseWrap": "preserve",
10
- "quoteProps": "as-needed",
11
- "semi": true,
12
- "singleQuote": true,
13
- "trailingComma": "all",
14
- "useTabs": false
15
- }
@@ -1,22 +0,0 @@
1
-
2
- > server-act@1.1.2 build /home/runner/work/server-act/server-act/packages/server-act
3
- > tsup
4
-
5
- CLI Building entry: ./src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v7.2.0
8
- CLI Using tsup config: /home/runner/work/server-act/server-act/packages/server-act/tsup.config.ts
9
- CLI Target: node16
10
- CLI Cleaning output folder
11
- ESM Build start
12
- CJS Build start
13
- ESM dist/index.mjs 4.59 KB
14
- ESM dist/index.mjs.map 11.97 KB
15
- ESM ⚡️ Build success in 29ms
16
- CJS dist/index.js 6.18 KB
17
- CJS dist/index.js.map 12.02 KB
18
- CJS ⚡️ Build success in 30ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 1345ms
21
- DTS dist/index.d.mts 2.17 KB
22
- DTS dist/index.d.ts 2.17 KB
package/CHANGELOG.md DELETED
@@ -1,74 +0,0 @@
1
- # server-act
2
-
3
- ## 1.1.2
4
-
5
- ### Patch Changes
6
-
7
- - a832b11: Improve form errors type infer
8
-
9
- ## 1.1.1
10
-
11
- ### Patch Changes
12
-
13
- - 8d5b6e5: Fixed zod error type in `formAction` when using FormData
14
-
15
- ## 1.1.0
16
-
17
- ### Minor Changes
18
-
19
- - 48b9164: Remove formData parsing for `formAction`
20
-
21
- ## 1.0.0
22
-
23
- ### Major Changes
24
-
25
- - b4318a8: Get `formAction` out of experimental!
26
-
27
- ## 0.0.10
28
-
29
- ### Patch Changes
30
-
31
- - a2ab457: Fixed form action doc
32
-
33
- ## 0.0.9
34
-
35
- ### Patch Changes
36
-
37
- - d8682f2: Documentation for experimental form action
38
-
39
- ## 0.0.8
40
-
41
- ### Patch Changes
42
-
43
- - 566261e: Change form action error to ZodError
44
- - ead7149: Prettify form action params type
45
-
46
- ## 0.0.7
47
-
48
- ### Patch Changes
49
-
50
- - 50e2853: New experimental form action
51
-
52
- ## 0.0.6
53
-
54
- ### Patch Changes
55
-
56
- - fedd1d4: Update README
57
-
58
- ## 0.0.5
59
-
60
- ### Patch Changes
61
-
62
- - 7e5d9c9: Support middleware
63
-
64
- ## 0.0.1
65
-
66
- ### Patch Changes
67
-
68
- - 01d52a7: First Release!
69
-
70
- ## 0.0.1
71
-
72
- ### Patch Changes
73
-
74
- - First Release!
package/README.md DELETED
@@ -1,141 +0,0 @@
1
- # Server-Act
2
-
3
- [![npm version](https://badge.fury.io/js/server-act.svg)](https://badge.fury.io/js/server-act)
4
-
5
- A simple React server action builder that provides input validation with zod.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- # npm
11
- npm install server-act zod
12
-
13
- # yarn
14
- yarn add server-act zod
15
-
16
- # pnpm
17
- pnpm add server-act zod
18
- ```
19
-
20
- ## Usage
21
-
22
- ```ts
23
- // action.ts
24
- "use server";
25
-
26
- import { serverAct } from "server-act";
27
- import { z } from "zod";
28
-
29
- export const sayHelloAction = serverAct
30
- .input(
31
- z.object({
32
- name: z.string(),
33
- })
34
- )
35
- .action(async ({ input }) => {
36
- return `Hello, ${input.name}`;
37
- });
38
- ```
39
-
40
- ```tsx
41
- // client-component.tsx
42
- "use client";
43
-
44
- import { sayHelloAction } from "./action";
45
-
46
- export const ClientComponent = () => {
47
- const onClick = () => {
48
- const message = await sayHelloAction({ name: "John" });
49
- console.log(message); // Hello, John
50
- };
51
-
52
- return (
53
- <div>
54
- <button onClick={onClick}>Trigger action</button>
55
- </div>
56
- );
57
- };
58
- ```
59
-
60
- ### With Middleware
61
-
62
- ```ts
63
- // action.ts
64
- "use server";
65
-
66
- import { serverAct } from "server-act";
67
- import { z } from "zod";
68
-
69
- export const sayHelloAction = serverAct
70
- .middleware(() => {
71
- const userId = "...";
72
- return { userId };
73
- })
74
- .input(
75
- z.object({
76
- name: z.string(),
77
- })
78
- )
79
- .action(async ({ ctx, input }) => {
80
- console.log("User ID", ctx.userId);
81
- return `Hello, ${input.name}`;
82
- });
83
- ```
84
-
85
- ### `useFormState` Support
86
-
87
- > `useFormState` Documentation:
88
- >
89
- > - https://nextjs.org/docs/app/building-your-application/data-fetching/forms-and-mutations#error-handling
90
- > - https://react.dev/reference/react-dom/hooks/useFormState
91
-
92
- We recommend using [zod-form-data](https://www.npmjs.com/package/zod-form-data) for input validation.
93
-
94
- ```ts
95
- // action.ts;
96
- "use server";
97
-
98
- import { serverAct } from "server-act";
99
- import { z } from "zod";
100
- import { zfd } from "zod-form-data";
101
-
102
- export const sayHelloAction = serverAct
103
- .middleware(requestTimeMiddleware)
104
- .input(
105
- zfd.formData({
106
- name: zfd.text(
107
- z
108
- .string({ required_error: `You haven't told me your name` })
109
- .nonempty({ message: "You need to tell me your name!" })
110
- ),
111
- })
112
- )
113
- .formAction(async ({ input, formErrors, ctx }) => {
114
- if (formErrors) {
115
- return { formErrors: formErrors.formErrors.fieldErrors };
116
- }
117
- return { message: `Hello, ${input.name}!` };
118
- });
119
- ```
120
-
121
- ```tsx
122
- // client-component.tsx
123
- "use client";
124
-
125
- import { sayHelloAction } from "./action";
126
-
127
- export const ClientComponent = () => {
128
- const [state, dispatch] = useFormState(sayHelloAction, { formErrors: {} });
129
-
130
- return (
131
- <form action={dispatch}>
132
- <input name="name" required />
133
- {state.formErrors?.name?.map((error) => <p key={error}>{error}</p>)}
134
-
135
- <button type="submit">Submit</button>
136
-
137
- {!!state.message && <p>{state.message}</p>}
138
- </form>
139
- );
140
- };
141
- ```
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\ntype Prettify<T> = {\n [P in keyof T]: T[P];\n // eslint-disable-next-line @typescript-eslint/ban-types\n} & {};\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ninterface ActionParams<TInput = unknown, TContext = unknown> {\n _input: TInput;\n _context: TContext;\n}\n\ninterface ActionBuilder<TParams extends ActionParams> {\n /**\n * Middleware allows you to run code before the action, its return value will pass as context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n /**\n * Create an action for React `useFormState`\n */\n formAction: <TState>(\n action: (\n params: Prettify<\n {\n ctx: InferContextType<TParams['_context']>;\n prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.\n } & (\n | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}\n | {\n input?: undefined;\n formErrors: z.ZodError<\n TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown>\n ? InferParserType<T, 'in'>\n : InferParserType<TParams['_input'], 'in'>\n >;\n }\n )\n >,\n ) => Promise<TState>,\n ) => (prevState: TState, formData: FormData) => Promise<TState>;\n}\ntype AnyActionBuilder = ActionBuilder<any>;\n\ninterface ActionBuilderDef<TParams extends ActionParams<any>> {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n}\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n formAction: (action) => {\n return async (prevState, formData) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(formData);\n if (!result.success) {\n return await action({ctx, prevState, formErrors: result.error});\n }\n return await action({ctx, prevState, input: result.data});\n }\n return await action({ctx, prevState, input: undefined});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n","import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nconst MAX_ISSUES_IN_MESSAGE = 99;\nconst ISSUE_SEPARATOR = '; ';\nconst UNION_SEPARATOR = ', or ';\nconst PREFIX = 'Validation error';\nconst PREFIX_SEPARATOR = ': ';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nfunction conditionallyPrefixMessage(reason, prefix, prefixSeparator) {\n if (prefix !== null) {\n if (reason.length > 0) {\n return [prefix, reason].join(prefixSeparator);\n }\n return prefix;\n }\n if (reason.length > 0) {\n return reason;\n }\n return PREFIX;\n}\nexport function fromZodIssue(issue, options = {}) {\n const { issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = getMessageFromZodIssue(issue, issueSeparator, unionSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, [issue]);\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\nexport const errorMap = (issue, ctx) => {\n const error = fromZodIssue({\n ...issue,\n message: issue.message ?? ctx.defaultError,\n });\n return {\n message: error.message,\n };\n};\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n"],"mappings":"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","names":["issue"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js","../src/index.ts"],"sourcesContent":["import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nconst MAX_ISSUES_IN_MESSAGE = 99;\nconst ISSUE_SEPARATOR = '; ';\nconst UNION_SEPARATOR = ', or ';\nconst PREFIX = 'Validation error';\nconst PREFIX_SEPARATOR = ': ';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nfunction conditionallyPrefixMessage(reason, prefix, prefixSeparator) {\n if (prefix !== null) {\n if (reason.length > 0) {\n return [prefix, reason].join(prefixSeparator);\n }\n return prefix;\n }\n if (reason.length > 0) {\n return reason;\n }\n return PREFIX;\n}\nexport function fromZodIssue(issue, options = {}) {\n const { issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = getMessageFromZodIssue(issue, issueSeparator, unionSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, [issue]);\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\nexport const errorMap = (issue, ctx) => {\n const error = fromZodIssue({\n ...issue,\n message: issue.message ?? ctx.defaultError,\n });\n return {\n message: error.message,\n };\n};\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\ntype Prettify<T> = {\n [P in keyof T]: T[P];\n // eslint-disable-next-line @typescript-eslint/ban-types\n} & {};\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ninterface ActionParams<TInput = unknown, TContext = unknown> {\n _input: TInput;\n _context: TContext;\n}\n\ninterface ActionBuilder<TParams extends ActionParams> {\n /**\n * Middleware allows you to run code before the action, its return value will pass as context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n /**\n * Create an action for React `useFormState`\n */\n formAction: <TState>(\n action: (\n params: Prettify<\n {\n ctx: InferContextType<TParams['_context']>;\n prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.\n } & (\n | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}\n | {\n input?: undefined;\n formErrors: z.ZodError<\n TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown>\n ? InferParserType<T, 'in'>\n : InferParserType<TParams['_input'], 'in'>\n >;\n }\n )\n >,\n ) => Promise<TState>,\n ) => (prevState: TState, formData: FormData) => Promise<TState>;\n}\ntype AnyActionBuilder = ActionBuilder<any>;\n\ninterface ActionBuilderDef<TParams extends ActionParams<any>> {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n}\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n formAction: (action) => {\n return async (prevState, formData) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(formData);\n if (!result.success) {\n return await action({ctx, prevState, formErrors: result.error});\n }\n return await action({ctx, prevState, input: result.data});\n }\n return await action({ctx, prevState, input: undefined});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n"],"mappings":"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","names":["issue"]}
package/src/index.test.ts DELETED
@@ -1,110 +0,0 @@
1
- import {test, expect, expectTypeOf, vi, beforeEach, describe} from 'vitest';
2
- import {z} from 'zod';
3
- import {zfd} from 'zod-form-data';
4
-
5
- import {serverAct} from '.';
6
-
7
- describe.concurrent('action', () => {
8
- test('should able to create action without input', async () => {
9
- const action = serverAct.action(async () => Promise.resolve('bar'));
10
-
11
- expectTypeOf(action).parameter(0).toBeUndefined();
12
- expectTypeOf(action).returns.resolves.toBeString();
13
- await expect(action()).resolves.toBe('bar');
14
- });
15
-
16
- test('should able to create action with input', async () => {
17
- const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
18
-
19
- expectTypeOf(action).parameter(0).toBeString();
20
- expectTypeOf(action).returns.resolves.toBeString();
21
- await expect(action('foo')).resolves.toBe('bar');
22
- });
23
-
24
- test('should throw error if the input is invalid', async () => {
25
- const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
26
-
27
- expectTypeOf(action).parameter(0).toBeString();
28
- expectTypeOf(action).returns.resolves.toBeString();
29
-
30
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
31
- // @ts-ignore
32
- await expect(action(1)).rejects.toThrowError();
33
- });
34
-
35
- describe('middleware should be called once', () => {
36
- const middlewareSpy = vi.fn(() => {
37
- return {prefix: 'best'};
38
- });
39
-
40
- beforeEach(() => {
41
- vi.restoreAllMocks();
42
- });
43
-
44
- test('without input', async () => {
45
- const action = serverAct.middleware(middlewareSpy).action(async ({ctx}) => Promise.resolve(`${ctx.prefix}-bar`));
46
-
47
- expectTypeOf(action).returns.resolves.toBeString();
48
- await expect(action()).resolves.toBe('best-bar');
49
- expect(middlewareSpy).toBeCalledTimes(1);
50
- });
51
-
52
- test('with input', async () => {
53
- const actionWithInput = serverAct
54
- .middleware(middlewareSpy)
55
- .input(z.string())
56
- .action(async ({ctx, input}) => Promise.resolve(`${ctx.prefix}-${input}-bar`));
57
-
58
- expectTypeOf(actionWithInput).parameter(0).toBeString();
59
- expectTypeOf(actionWithInput).returns.resolves.toBeString();
60
- await expect(actionWithInput('foo')).resolves.toBe('best-foo-bar');
61
- expect(middlewareSpy).toBeCalledTimes(1);
62
- });
63
- });
64
- });
65
-
66
- describe.concurrent('formAction', () => {
67
- test('should able to create form action without input', async () => {
68
- const action = serverAct.formAction(async () => Promise.resolve('bar'));
69
-
70
- expectTypeOf(action).parameter(0).toBeString();
71
- expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
72
- expectTypeOf(action).returns.resolves.toBeString();
73
-
74
- const formData = new FormData();
75
- await expect(action('foo', formData)).resolves.toMatchObject('bar');
76
- });
77
-
78
- test('should able to create form action with input', async () => {
79
- const action = serverAct.input(zfd.formData({foo: zfd.text()})).formAction(async () => Promise.resolve('bar'));
80
-
81
- expectTypeOf(action).parameter(0).toBeString();
82
- expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
83
- expectTypeOf(action).returns.resolves.toBeString();
84
-
85
- const formData = new FormData();
86
- formData.append('foo', 'bar');
87
- await expect(action('foo', formData)).resolves.toMatchObject('bar');
88
- });
89
-
90
- test('should return form errors if the input is invalid', async () => {
91
- const action = serverAct
92
- .input(zfd.formData({foo: zfd.text(z.string({required_error: 'Required'}))}))
93
- .formAction(async ({formErrors}) => {
94
- if (formErrors) {
95
- return formErrors;
96
- }
97
- return Promise.resolve('bar');
98
- });
99
-
100
- expectTypeOf(action).parameter(0).toMatchTypeOf<string | z.ZodError<{foo: string}>>();
101
- expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
102
-
103
- const formData = new FormData();
104
- formData.append('bar', 'foo');
105
-
106
- const result = await action('foo', formData);
107
- expect(result).toBeInstanceOf(z.ZodError);
108
- expect(result).toHaveProperty('formErrors.fieldErrors', {foo: ['Required']});
109
- });
110
- });
package/src/index.ts DELETED
@@ -1,130 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- import {type z} from 'zod';
4
- import {fromZodError} from 'zod-validation-error';
5
-
6
- type Prettify<T> = {
7
- [P in keyof T]: T[P];
8
- // eslint-disable-next-line @typescript-eslint/ban-types
9
- } & {};
10
-
11
- const unsetMarker = Symbol('unsetMarker');
12
- type UnsetMarker = typeof unsetMarker;
13
-
14
- type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
15
-
16
- type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker
17
- ? undefined
18
- : TParser extends z.ZodType
19
- ? TParser[TType extends 'in' ? '_input' : '_output']
20
- : never;
21
-
22
- type InferContextType<T> = T extends UnsetMarker ? undefined : T;
23
-
24
- interface ActionParams<TInput = unknown, TContext = unknown> {
25
- _input: TInput;
26
- _context: TContext;
27
- }
28
-
29
- interface ActionBuilder<TParams extends ActionParams> {
30
- /**
31
- * Middleware allows you to run code before the action, its return value will pass as context to the action.
32
- */
33
- middleware: <TContext>(
34
- middleware: () => Promise<TContext> | TContext,
35
- ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;
36
- /**
37
- * Input validation for the action.
38
- */
39
- input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;
40
- /**
41
- * Create an action.
42
- */
43
- action: <TOutput>(
44
- action: (params: {
45
- ctx: InferContextType<TParams['_context']>;
46
- input: InferParserType<TParams['_input'], 'out'>;
47
- }) => Promise<TOutput>,
48
- ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
49
- /**
50
- * Create an action for React `useFormState`
51
- */
52
- formAction: <TState>(
53
- action: (
54
- params: Prettify<
55
- {
56
- ctx: InferContextType<TParams['_context']>;
57
- prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.
58
- } & (
59
- | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}
60
- | {
61
- input?: undefined;
62
- formErrors: z.ZodError<
63
- TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown>
64
- ? InferParserType<T, 'in'>
65
- : InferParserType<TParams['_input'], 'in'>
66
- >;
67
- }
68
- )
69
- >,
70
- ) => Promise<TState>,
71
- ) => (prevState: TState, formData: FormData) => Promise<TState>;
72
- }
73
- type AnyActionBuilder = ActionBuilder<any>;
74
-
75
- interface ActionBuilderDef<TParams extends ActionParams<any>> {
76
- input: TParams['_input'];
77
- middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;
78
- }
79
- type AnyActionBuilderDef = ActionBuilderDef<any>;
80
-
81
- const createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {
82
- return createServerActionBuilder(def);
83
- };
84
-
85
- const createServerActionBuilder = (
86
- initDef: Partial<AnyActionBuilderDef> = {},
87
- ): ActionBuilder<{
88
- _input: UnsetMarker;
89
- _context: UnsetMarker;
90
- }> => {
91
- const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {
92
- input: undefined,
93
- middleware: undefined,
94
- ...initDef,
95
- };
96
- return {
97
- middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,
98
- input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,
99
- action: (action) => {
100
- return async (input) => {
101
- const ctx = await _def.middleware?.();
102
- if (_def.input) {
103
- const result = _def.input.safeParse(input);
104
- if (!result.success) {
105
- throw fromZodError(result.error);
106
- }
107
- }
108
- return await action({ctx, input});
109
- };
110
- },
111
- formAction: (action) => {
112
- return async (prevState, formData) => {
113
- const ctx = await _def.middleware?.();
114
- if (_def.input) {
115
- const result = _def.input.safeParse(formData);
116
- if (!result.success) {
117
- return await action({ctx, prevState, formErrors: result.error});
118
- }
119
- return await action({ctx, prevState, input: result.data});
120
- }
121
- return await action({ctx, prevState, input: undefined});
122
- };
123
- },
124
- };
125
- };
126
-
127
- /**
128
- * Server action builder
129
- */
130
- export const serverAct = createServerActionBuilder();
package/tsconfig.json DELETED
@@ -1,30 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "display": "Strictest",
4
- "_version": "2.0.0",
5
- "compilerOptions": {
6
- "lib": [
7
- "ES2020",
8
- "DOM",
9
- "DOM.Iterable"
10
- ],
11
- "module": "NodeNext",
12
- "moduleResolution": "NodeNext",
13
- "outDir": "./dist",
14
- "strict": true,
15
- "allowUnusedLabels": false,
16
- "allowUnreachableCode": false,
17
- "exactOptionalPropertyTypes": true,
18
- "noFallthroughCasesInSwitch": true,
19
- "noImplicitOverride": true,
20
- "noImplicitReturns": true,
21
- "noPropertyAccessFromIndexSignature": true,
22
- "noUncheckedIndexedAccess": true,
23
- "noUnusedLocals": true,
24
- "noUnusedParameters": true,
25
- "checkJs": true,
26
- "esModuleInterop": true,
27
- "skipLibCheck": true,
28
- "forceConsistentCasingInFileNames": true
29
- }
30
- }
package/tsup.config.ts DELETED
@@ -1,11 +0,0 @@
1
- import {defineConfig} from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: ['./src/index.ts'],
5
- outDir: 'dist',
6
- splitting: false,
7
- sourcemap: true,
8
- clean: true,
9
- dts: true,
10
- format: ['esm', 'cjs'],
11
- });