server-act 0.0.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/.eslintrc.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "parserOptions": {
3
+ "project": "./tsconfig.json"
4
+ },
5
+ "extends": [
6
+ "whiteroom"
7
+ ],
8
+ "ignorePatterns": [
9
+ "dist/**"
10
+ ]
11
+ }
@@ -0,0 +1,15 @@
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
+ }
@@ -0,0 +1,21 @@
1
+
2
+ > server-act@0.0.4 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 v6.7.0
8
+ CLI Using tsup config: /home/runner/work/server-act/server-act/packages/server-act/tsup.config.ts
9
+ CLI Target: node14
10
+ CLI Cleaning output folder
11
+ ESM Build start
12
+ CJS Build start
13
+ CJS dist/index.js 4.95 KB
14
+ CJS dist/index.js.map 7.71 KB
15
+ CJS ⚡️ Build success in 25ms
16
+ ESM dist/index.mjs 3.36 KB
17
+ ESM dist/index.mjs.map 7.66 KB
18
+ ESM ⚡️ Build success in 25ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 690ms
21
+ DTS dist/index.d.ts 956.00 B
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # server-act
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 01d52a7: First Release!
8
+
9
+ ## 0.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - First Release!
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Server-Act
2
+
3
+ ![npm](https://img.shields.io/npm/v/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
+
28
+ const sayHelloAction = serverAct
29
+ .input(
30
+ z.object({
31
+ name: z.string(),
32
+ })
33
+ )
34
+ .action(async ({ name }) => {
35
+ return `Hello, ${name}`;
36
+ });
37
+ ```
38
+
39
+ ```tsx
40
+ // client-component.tsx
41
+ "use client";
42
+
43
+ import { sayHelloAction } from "./action";
44
+
45
+ export const ClientComponent = () => {
46
+ const onClick = () => {
47
+ const message = await sayHelloAction({ name: "John" });
48
+ console.log(message); // Hello, John
49
+ };
50
+
51
+ return (
52
+ <div>
53
+ <button onClick={onClick}>Trigger action</button>
54
+ </div>
55
+ );
56
+ };
57
+ ```
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const unsetMarker: unique symbol;
4
+ type UnsetMarker = typeof unsetMarker;
5
+ type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
6
+ type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker ? undefined : TParser extends z.ZodType ? TParser[TType extends 'in' ? '_input' : '_output'] : never;
7
+ type ActionParams<TInput = unknown> = {
8
+ _input: TInput;
9
+ };
10
+ type ActionBuilder<TParams extends ActionParams> = {
11
+ input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{
12
+ _input: TParser;
13
+ }>;
14
+ action: <TOutput>(action: (params: {
15
+ input: InferParserType<TParams['_input'], 'out'>;
16
+ }) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
17
+ };
18
+ /**
19
+ * Server action builder
20
+ */
21
+ declare const serverAct: ActionBuilder<{
22
+ _input: UnsetMarker;
23
+ }>;
24
+
25
+ export { serverAct };
package/dist/index.js ADDED
@@ -0,0 +1,140 @@
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);
36
+
37
+ // ../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
38
+ var zod = __toESM(require("zod"));
39
+
40
+ // ../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/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) + '"]';
52
+ }
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.3.0_zod@3.21.4/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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
70
+ var ValidationError = class extends Error {
71
+ details;
72
+ name;
73
+ constructor(message, details = []) {
74
+ super(message);
75
+ this.details = details;
76
+ this.name = "ZodValidationError";
77
+ }
78
+ toString() {
79
+ return this.message;
80
+ }
81
+ };
82
+ function fromZodIssue(issue, issueSeparator, unionSeparator) {
83
+ if (issue.code === "invalid_union") {
84
+ return issue.unionErrors.reduce((acc, zodError) => {
85
+ const newIssues = zodError.issues.map((issue2) => fromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
86
+ if (!acc.includes(newIssues)) {
87
+ acc.push(newIssues);
88
+ }
89
+ return acc;
90
+ }, []).join(unionSeparator);
91
+ }
92
+ if (isNonEmptyArray(issue.path)) {
93
+ if (issue.path.length === 1) {
94
+ const identifier = issue.path[0];
95
+ if (typeof identifier === "number") {
96
+ return `${issue.message} at index ${identifier}`;
97
+ }
98
+ }
99
+ return `${issue.message} at "${joinPath(issue.path)}"`;
100
+ }
101
+ return issue.message;
102
+ }
103
+ function fromZodError(zodError, options = {}) {
104
+ const { maxIssuesInMessage = 99, issueSeparator = "; ", unionSeparator = ", or ", prefixSeparator = ": ", prefix = "Validation error" } = options;
105
+ const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
106
+ const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;
107
+ return new ValidationError(message, zodError.errors);
108
+ }
109
+
110
+ // src/index.ts
111
+ var unsetMarker = Symbol("unsetMarker");
112
+ var createNewServerActionBuilder = (def) => {
113
+ return createServerActionBuilder(def);
114
+ };
115
+ var createServerActionBuilder = (initDef = {}) => {
116
+ const _def = {
117
+ input: void 0,
118
+ ...initDef
119
+ };
120
+ return {
121
+ input: (input) => createNewServerActionBuilder({ ..._def, input }),
122
+ action: (action) => {
123
+ return async (input) => {
124
+ if (_def.input) {
125
+ const result = _def.input.safeParse(input);
126
+ if (!result.success) {
127
+ throw fromZodError(result.error);
128
+ }
129
+ }
130
+ return await action({ input });
131
+ };
132
+ }
133
+ };
134
+ };
135
+ var serverAct = createServerActionBuilder();
136
+ // Annotate the CommonJS export names for ESM import in node:
137
+ 0 && (module.exports = {
138
+ serverAct
139
+ });
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\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 ActionParams<TInput = unknown> = {\n _input: TInput;\n};\n\ntype ActionBuilder<TParams extends ActionParams> = {\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser}>;\n action: <TOutput>(\n action: (params: {input: InferParserType<TParams['_input'], 'out'>}) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n};\ntype AnyActionBuilder = ActionBuilder<any>;\n\ntype ActionBuilderDef<TParams extends ActionParams<any>> = {\n input: TParams['_input'];\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}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined}> = {\n input: undefined,\n ...initDef,\n };\n return {\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\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({input});\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';\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 fromZodIssue(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) => fromZodIssue(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}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = 99, issueSeparator = '; ', unionSeparator = ', or ', prefixSeparator = ': ', prefix = 'Validation error', } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;\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}\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"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,103 @@
1
+ // ../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
2
+ import * as zod from "zod";
3
+
4
+ // ../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/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) + '"]';
16
+ }
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.3.0_zod@3.21.4/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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
34
+ var ValidationError = class extends Error {
35
+ details;
36
+ name;
37
+ constructor(message, details = []) {
38
+ super(message);
39
+ this.details = details;
40
+ this.name = "ZodValidationError";
41
+ }
42
+ toString() {
43
+ return this.message;
44
+ }
45
+ };
46
+ function fromZodIssue(issue, issueSeparator, unionSeparator) {
47
+ if (issue.code === "invalid_union") {
48
+ return issue.unionErrors.reduce((acc, zodError) => {
49
+ const newIssues = zodError.issues.map((issue2) => fromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
50
+ if (!acc.includes(newIssues)) {
51
+ acc.push(newIssues);
52
+ }
53
+ return acc;
54
+ }, []).join(unionSeparator);
55
+ }
56
+ if (isNonEmptyArray(issue.path)) {
57
+ if (issue.path.length === 1) {
58
+ const identifier = issue.path[0];
59
+ if (typeof identifier === "number") {
60
+ return `${issue.message} at index ${identifier}`;
61
+ }
62
+ }
63
+ return `${issue.message} at "${joinPath(issue.path)}"`;
64
+ }
65
+ return issue.message;
66
+ }
67
+ function fromZodError(zodError, options = {}) {
68
+ const { maxIssuesInMessage = 99, issueSeparator = "; ", unionSeparator = ", or ", prefixSeparator = ": ", prefix = "Validation error" } = options;
69
+ const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
70
+ const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;
71
+ return new ValidationError(message, zodError.errors);
72
+ }
73
+
74
+ // src/index.ts
75
+ var unsetMarker = Symbol("unsetMarker");
76
+ var createNewServerActionBuilder = (def) => {
77
+ return createServerActionBuilder(def);
78
+ };
79
+ var createServerActionBuilder = (initDef = {}) => {
80
+ const _def = {
81
+ input: void 0,
82
+ ...initDef
83
+ };
84
+ return {
85
+ input: (input) => createNewServerActionBuilder({ ..._def, input }),
86
+ action: (action) => {
87
+ return async (input) => {
88
+ if (_def.input) {
89
+ const result = _def.input.safeParse(input);
90
+ if (!result.success) {
91
+ throw fromZodError(result.error);
92
+ }
93
+ }
94
+ return await action({ input });
95
+ };
96
+ }
97
+ };
98
+ };
99
+ var serverAct = createServerActionBuilder();
100
+ export {
101
+ serverAct
102
+ };
103
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/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';\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 fromZodIssue(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) => fromZodIssue(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}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = 99, issueSeparator = '; ', unionSeparator = ', or ', prefixSeparator = ': ', prefix = 'Validation error', } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;\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}\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-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\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 ActionParams<TInput = unknown> = {\n _input: TInput;\n};\n\ntype ActionBuilder<TParams extends ActionParams> = {\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser}>;\n action: <TOutput>(\n action: (params: {input: InferParserType<TParams['_input'], 'out'>}) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n};\ntype AnyActionBuilder = ActionBuilder<any>;\n\ntype ActionBuilderDef<TParams extends ActionParams<any>> = {\n input: TParams['_input'];\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}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined}> = {\n input: undefined,\n ...initDef,\n };\n return {\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\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({input});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n"],"mappings":"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","names":["issue"]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "server-act",
3
+ "version": "0.0.4",
4
+ "homepage": "https://github.com/chungweileong94/server-act#readme",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/chungweileong94/server-act.git"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/chungweileong94/server-act/issues"
11
+ },
12
+ "main": "dist/index.js",
13
+ "module": "dist/index.mjs",
14
+ "types": "dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.mjs",
19
+ "require": "./dist/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "keywords": [
24
+ "next",
25
+ "nextjs",
26
+ "react",
27
+ "react server component",
28
+ "react server action",
29
+ "rsc",
30
+ "server component",
31
+ "server action",
32
+ "action"
33
+ ],
34
+ "author": "chungweileong94",
35
+ "license": "MIT",
36
+ "devDependencies": {
37
+ "eslint": "^8.39.0",
38
+ "eslint-config-whiteroom": "^3.1.0",
39
+ "prettier": "^2.8.8",
40
+ "tsup": "^6.7.0",
41
+ "typescript": "^5.0.4",
42
+ "zod": "^3.21.4",
43
+ "zod-validation-error": "^1.3.0"
44
+ },
45
+ "peerDependencies": {
46
+ "typescript": "^5.0.4",
47
+ "zod": "^3.21.4"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "test": "vitest run",
52
+ "lint": "eslint src --ext .ts"
53
+ }
54
+ }
@@ -0,0 +1,21 @@
1
+ import {test, expect} from 'vitest';
2
+ import z from 'zod';
3
+
4
+ import {serverAct} from '.';
5
+
6
+ test('should able to create action without input', async () => {
7
+ const action = serverAct.action(async () => Promise.resolve('bar'));
8
+ await expect(action()).resolves.toBe('bar');
9
+ });
10
+
11
+ test('should able to create action with input', async () => {
12
+ const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
13
+ await expect(action('foo')).resolves.toBe('bar');
14
+ });
15
+
16
+ test('should throw error if the input is invalid', async () => {
17
+ const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
18
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
19
+ // @ts-ignore
20
+ await expect(action(1)).rejects.toThrowError();
21
+ });
package/src/index.ts ADDED
@@ -0,0 +1,65 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import {type z} from 'zod';
3
+ import {fromZodError} from 'zod-validation-error';
4
+
5
+ const unsetMarker = Symbol('unsetMarker');
6
+ type UnsetMarker = typeof unsetMarker;
7
+
8
+ type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
9
+
10
+ type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker
11
+ ? undefined
12
+ : TParser extends z.ZodType
13
+ ? TParser[TType extends 'in' ? '_input' : '_output']
14
+ : never;
15
+
16
+ type ActionParams<TInput = unknown> = {
17
+ _input: TInput;
18
+ };
19
+
20
+ type ActionBuilder<TParams extends ActionParams> = {
21
+ input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser}>;
22
+ action: <TOutput>(
23
+ action: (params: {input: InferParserType<TParams['_input'], 'out'>}) => Promise<TOutput>,
24
+ ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
25
+ };
26
+ type AnyActionBuilder = ActionBuilder<any>;
27
+
28
+ type ActionBuilderDef<TParams extends ActionParams<any>> = {
29
+ input: TParams['_input'];
30
+ };
31
+ type AnyActionBuilderDef = ActionBuilderDef<any>;
32
+
33
+ const createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {
34
+ return createServerActionBuilder(def);
35
+ };
36
+
37
+ const createServerActionBuilder = (
38
+ initDef: Partial<AnyActionBuilderDef> = {},
39
+ ): ActionBuilder<{
40
+ _input: UnsetMarker;
41
+ }> => {
42
+ const _def: ActionBuilderDef<{_input: z.ZodType | undefined}> = {
43
+ input: undefined,
44
+ ...initDef,
45
+ };
46
+ return {
47
+ input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,
48
+ action: (action) => {
49
+ return async (input) => {
50
+ if (_def.input) {
51
+ const result = _def.input.safeParse(input);
52
+ if (!result.success) {
53
+ throw fromZodError(result.error);
54
+ }
55
+ }
56
+ return await action({input});
57
+ };
58
+ },
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Server action builder
64
+ */
65
+ export const serverAct = createServerActionBuilder();
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "display": "Strictest",
4
+ "_version": "2.0.0",
5
+ "compilerOptions": {
6
+ "lib": [
7
+ "ES2020"
8
+ ],
9
+ "moduleResolution": "nodenext",
10
+ "outDir": "./dist",
11
+ "strict": true,
12
+ "allowUnusedLabels": false,
13
+ "allowUnreachableCode": false,
14
+ "exactOptionalPropertyTypes": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "noImplicitOverride": true,
17
+ "noImplicitReturns": true,
18
+ "noPropertyAccessFromIndexSignature": true,
19
+ "noUncheckedIndexedAccess": true,
20
+ "noUnusedLocals": true,
21
+ "noUnusedParameters": true,
22
+ "checkJs": true,
23
+ "esModuleInterop": true,
24
+ "skipLibCheck": true,
25
+ "forceConsistentCasingInFileNames": true
26
+ }
27
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,11 @@
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
+ });