server-act 1.1.3 → 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,74 +1,108 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ Object.defineProperty(exports, '__esModule', { value: true });
19
2
 
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- serverAct: () => serverAct
24
- });
25
- module.exports = __toCommonJS(src_exports);
26
- var unsetMarker = Symbol("unsetMarker");
27
- var createNewServerActionBuilder = (def) => {
28
- return createServerActionBuilder(def);
29
- };
30
- var createServerActionBuilder = (initDef = {}) => {
31
- const _def = {
32
- input: void 0,
33
- middleware: void 0,
34
- ...initDef
35
- };
36
- return {
37
- middleware: (middleware) => createServerActionBuilder({ ..._def, middleware }),
38
- input: (input) => createNewServerActionBuilder({ ..._def, input }),
39
- action: (action) => {
40
- return async (input) => {
41
- var _a;
42
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
43
- if (_def.input) {
44
- const result = _def.input.safeParse(input);
45
- if (!result.success) {
46
- console.error("\u274C Input validation error:", result.error.errors);
47
- throw new Error("Input validation error");
48
- }
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;
10
+ }
11
+ if (info.done) {
12
+ resolve(value);
13
+ } else {
14
+ Promise.resolve(value).then(_next, _throw);
15
+ }
16
+ }
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
+ };
31
+ }
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
+ }
49
41
  }
50
- return await action({ ctx, input });
51
- };
52
- },
53
- formAction: (action) => {
54
- return async (prevState, formData) => {
55
- var _a;
56
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
57
- if (_def.input) {
58
- const result = _def.input.safeParse(formData);
59
- if (!result.success) {
60
- return await action({ ctx, prevState, formErrors: result.error });
61
- }
62
- return await action({ ctx, prevState, input: result.data });
42
+ return target;
43
+ };
44
+ return _extends.apply(this, arguments);
45
+ }
46
+ const createNewServerActionBuilder = (def)=>{
47
+ return createServerActionBuilder(def);
48
+ };
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
+ });
63
101
  }
64
- return await action({ ctx, prevState, input: void 0 });
65
- };
66
- }
67
- };
102
+ };
68
103
  };
69
- var serverAct = createServerActionBuilder();
70
- // Annotate the CommonJS export names for ESM import in node:
71
- 0 && (module.exports = {
72
- serverAct
73
- });
74
- //# sourceMappingURL=index.js.map
104
+ /**
105
+ * Server action builder
106
+ */ const serverAct = createServerActionBuilder();
107
+
108
+ exports.serverAct = serverAct;
package/dist/index.mjs CHANGED
@@ -1,49 +1,106 @@
1
- // src/index.ts
2
- var unsetMarker = Symbol("unsetMarker");
3
- var createNewServerActionBuilder = (def) => {
4
- return createServerActionBuilder(def);
5
- };
6
- var createServerActionBuilder = (initDef = {}) => {
7
- const _def = {
8
- input: void 0,
9
- middleware: void 0,
10
- ...initDef
11
- };
12
- return {
13
- middleware: (middleware) => createServerActionBuilder({ ..._def, middleware }),
14
- input: (input) => createNewServerActionBuilder({ ..._def, input }),
15
- action: (action) => {
16
- return async (input) => {
17
- var _a;
18
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
19
- if (_def.input) {
20
- const result = _def.input.safeParse(input);
21
- if (!result.success) {
22
- console.error("\u274C Input validation error:", result.error.errors);
23
- throw new Error("Input validation error");
24
- }
25
- }
26
- return await action({ ctx, input });
27
- };
28
- },
29
- formAction: (action) => {
30
- return async (prevState, formData) => {
31
- var _a;
32
- const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
33
- if (_def.input) {
34
- const result = _def.input.safeParse(formData);
35
- if (!result.success) {
36
- return await action({ ctx, prevState, formErrors: result.error });
37
- }
38
- return await action({ ctx, prevState, input: result.data });
39
- }
40
- return await action({ ctx, prevState, input: void 0 });
41
- };
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;
42
8
  }
43
- };
9
+ if (info.done) {
10
+ resolve(value);
11
+ } else {
12
+ Promise.resolve(value).then(_next, _throw);
13
+ }
14
+ }
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
+ };
29
+ }
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);
43
+ }
44
+ const createNewServerActionBuilder = (def)=>{
45
+ return createServerActionBuilder(def);
44
46
  };
45
- var serverAct = createServerActionBuilder();
46
- export {
47
- serverAct
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
+ });
99
+ }
100
+ };
48
101
  };
49
- //# 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.3",
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,10 +44,10 @@
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
53
  "zod-form-data": "^2.0.2"
@@ -52,7 +62,8 @@
52
62
  }
53
63
  },
54
64
  "scripts": {
55
- "build": "tsup",
65
+ "build": "bunchee",
66
+ "dev": "bunchee -w",
56
67
  "test": "vitest run",
57
68
  "lint": "eslint src --ext .ts"
58
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.3 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 1.56 KB
14
- ESM dist/index.mjs.map 5.50 KB
15
- ESM ⚡️ Build success in 12ms
16
- CJS dist/index.js 2.53 KB
17
- CJS dist/index.js.map 5.54 KB
18
- CJS ⚡️ Build success in 12ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 999ms
21
- DTS dist/index.d.mts 2.17 KB
22
- DTS dist/index.d.ts 2.17 KB
package/CHANGELOG.md DELETED
@@ -1,80 +0,0 @@
1
- # server-act
2
-
3
- ## 1.1.3
4
-
5
- ### Patch Changes
6
-
7
- - [#14](https://github.com/chungweileong94/server-act/pull/14) [`8bb348e`](https://github.com/chungweileong94/server-act/commit/8bb348ee0ed7a60a2498a37cab86c7271c205752) Thanks [@chungweileong94](https://github.com/chungweileong94)! - Remove `zod-validation-error` dependency
8
-
9
- ## 1.1.2
10
-
11
- ### Patch Changes
12
-
13
- - a832b11: Improve form errors type infer
14
-
15
- ## 1.1.1
16
-
17
- ### Patch Changes
18
-
19
- - 8d5b6e5: Fixed zod error type in `formAction` when using FormData
20
-
21
- ## 1.1.0
22
-
23
- ### Minor Changes
24
-
25
- - 48b9164: Remove formData parsing for `formAction`
26
-
27
- ## 1.0.0
28
-
29
- ### Major Changes
30
-
31
- - b4318a8: Get `formAction` out of experimental!
32
-
33
- ## 0.0.10
34
-
35
- ### Patch Changes
36
-
37
- - a2ab457: Fixed form action doc
38
-
39
- ## 0.0.9
40
-
41
- ### Patch Changes
42
-
43
- - d8682f2: Documentation for experimental form action
44
-
45
- ## 0.0.8
46
-
47
- ### Patch Changes
48
-
49
- - 566261e: Change form action error to ZodError
50
- - ead7149: Prettify form action params type
51
-
52
- ## 0.0.7
53
-
54
- ### Patch Changes
55
-
56
- - 50e2853: New experimental form action
57
-
58
- ## 0.0.6
59
-
60
- ### Patch Changes
61
-
62
- - fedd1d4: Update README
63
-
64
- ## 0.0.5
65
-
66
- ### Patch Changes
67
-
68
- - 7e5d9c9: Support middleware
69
-
70
- ## 0.0.1
71
-
72
- ### Patch Changes
73
-
74
- - 01d52a7: First Release!
75
-
76
- ## 0.0.1
77
-
78
- ### Patch Changes
79
-
80
- - 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"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\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 console.error('❌ Input validation error:', result.error.errors);\n throw new Error('Input validation 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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,IAAM,cAAc,OAAO,aAAa;AAsExC,IAAM,+BAA+B,CAAC,QAAsC;AAC1E,SAAO,0BAA0B,GAAG;AACtC;AAEA,IAAM,4BAA4B,CAChC,UAAwC,CAAC,MAIrC;AACJ,QAAM,OAA+E;AAAA,IACnF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACA,SAAO;AAAA,IACL,YAAY,CAAC,eAAe,0BAA0B,EAAC,GAAG,MAAM,WAAU,CAAC;AAAA,IAC3E,OAAO,CAAC,UAAU,6BAA6B,EAAC,GAAG,MAAM,MAAK,CAAC;AAAA,IAC/D,QAAQ,CAAC,WAAW;AAClB,aAAO,OAAO,UAAU;AAlG9B;AAmGQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,cAAI,CAAC,OAAO,SAAS;AACnB,oBAAQ,MAAM,kCAA6B,OAAO,MAAM,MAAM;AAC9D,kBAAM,IAAI,MAAM,wBAAwB;AAAA,UAC1C;AAAA,QACF;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,MAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,IACA,YAAY,CAAC,WAAW;AACtB,aAAO,OAAO,WAAW,aAAa;AA/G5C;AAgHQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,QAAQ;AAC5C,cAAI,CAAC,OAAO,SAAS;AACnB,mBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,YAAY,OAAO,MAAK,CAAC;AAAA,UAChE;AACA,iBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAO,KAAI,CAAC;AAAA,QAC1D;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAS,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,YAAY,0BAA0B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\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 console.error('❌ Input validation error:', result.error.errors);\n throw new Error('Input validation 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":";AASA,IAAM,cAAc,OAAO,aAAa;AAsExC,IAAM,+BAA+B,CAAC,QAAsC;AAC1E,SAAO,0BAA0B,GAAG;AACtC;AAEA,IAAM,4BAA4B,CAChC,UAAwC,CAAC,MAIrC;AACJ,QAAM,OAA+E;AAAA,IACnF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACA,SAAO;AAAA,IACL,YAAY,CAAC,eAAe,0BAA0B,EAAC,GAAG,MAAM,WAAU,CAAC;AAAA,IAC3E,OAAO,CAAC,UAAU,6BAA6B,EAAC,GAAG,MAAM,MAAK,CAAC;AAAA,IAC/D,QAAQ,CAAC,WAAW;AAClB,aAAO,OAAO,UAAU;AAlG9B;AAmGQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,cAAI,CAAC,OAAO,SAAS;AACnB,oBAAQ,MAAM,kCAA6B,OAAO,MAAM,MAAM;AAC9D,kBAAM,IAAI,MAAM,wBAAwB;AAAA,UAC1C;AAAA,QACF;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,MAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,IACA,YAAY,CAAC,WAAW;AACtB,aAAO,OAAO,WAAW,aAAa;AA/G5C;AAgHQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,QAAQ;AAC5C,cAAI,CAAC,OAAO,SAAS;AACnB,mBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,YAAY,OAAO,MAAK,CAAC;AAAA,UAChE;AACA,iBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAO,KAAI,CAAC;AAAA,QAC1D;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAS,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,YAAY,0BAA0B;","names":[]}
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
-
5
- type Prettify<T> = {
6
- [P in keyof T]: T[P];
7
- // eslint-disable-next-line @typescript-eslint/ban-types
8
- } & {};
9
-
10
- const unsetMarker = Symbol('unsetMarker');
11
- type UnsetMarker = typeof unsetMarker;
12
-
13
- type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
14
-
15
- type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker
16
- ? undefined
17
- : TParser extends z.ZodType
18
- ? TParser[TType extends 'in' ? '_input' : '_output']
19
- : never;
20
-
21
- type InferContextType<T> = T extends UnsetMarker ? undefined : T;
22
-
23
- interface ActionParams<TInput = unknown, TContext = unknown> {
24
- _input: TInput;
25
- _context: TContext;
26
- }
27
-
28
- interface ActionBuilder<TParams extends ActionParams> {
29
- /**
30
- * Middleware allows you to run code before the action, its return value will pass as context to the action.
31
- */
32
- middleware: <TContext>(
33
- middleware: () => Promise<TContext> | TContext,
34
- ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;
35
- /**
36
- * Input validation for the action.
37
- */
38
- input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;
39
- /**
40
- * Create an action.
41
- */
42
- action: <TOutput>(
43
- action: (params: {
44
- ctx: InferContextType<TParams['_context']>;
45
- input: InferParserType<TParams['_input'], 'out'>;
46
- }) => Promise<TOutput>,
47
- ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
48
- /**
49
- * Create an action for React `useFormState`
50
- */
51
- formAction: <TState>(
52
- action: (
53
- params: Prettify<
54
- {
55
- ctx: InferContextType<TParams['_context']>;
56
- prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.
57
- } & (
58
- | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}
59
- | {
60
- input?: undefined;
61
- formErrors: z.ZodError<
62
- TParams['_input'] extends z.ZodEffects<infer T, unknown, unknown>
63
- ? InferParserType<T, 'in'>
64
- : InferParserType<TParams['_input'], 'in'>
65
- >;
66
- }
67
- )
68
- >,
69
- ) => Promise<TState>,
70
- ) => (prevState: TState, formData: FormData) => Promise<TState>;
71
- }
72
- type AnyActionBuilder = ActionBuilder<any>;
73
-
74
- interface ActionBuilderDef<TParams extends ActionParams<any>> {
75
- input: TParams['_input'];
76
- middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;
77
- }
78
- type AnyActionBuilderDef = ActionBuilderDef<any>;
79
-
80
- const createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {
81
- return createServerActionBuilder(def);
82
- };
83
-
84
- const createServerActionBuilder = (
85
- initDef: Partial<AnyActionBuilderDef> = {},
86
- ): ActionBuilder<{
87
- _input: UnsetMarker;
88
- _context: UnsetMarker;
89
- }> => {
90
- const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {
91
- input: undefined,
92
- middleware: undefined,
93
- ...initDef,
94
- };
95
- return {
96
- middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,
97
- input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,
98
- action: (action) => {
99
- return async (input) => {
100
- const ctx = await _def.middleware?.();
101
- if (_def.input) {
102
- const result = _def.input.safeParse(input);
103
- if (!result.success) {
104
- console.error('❌ Input validation error:', result.error.errors);
105
- throw new Error('Input validation 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
- });