nuxt-safe-action 0.2.1 → 0.4.0
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/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -40,7 +40,7 @@ const module$1 = defineNuxtModule({
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
logger.info(
|
|
43
|
-
`Found ${actionFiles.length} action file(s): ${actionFiles.map((a) => a.name).join(", ")}`
|
|
43
|
+
`Found ${actionFiles.length} action file(s): ${actionFiles.map((a) => `${a.method.toUpperCase()} ${a.name}`).join(", ")}`
|
|
44
44
|
);
|
|
45
45
|
nitroConfig.virtual = nitroConfig.virtual || {};
|
|
46
46
|
nitroConfig.handlers = nitroConfig.handlers || [];
|
|
@@ -49,7 +49,7 @@ const module$1 = defineNuxtModule({
|
|
|
49
49
|
nitroConfig.virtual[virtualKey] = generateHandlerCode(action);
|
|
50
50
|
nitroConfig.handlers.push({
|
|
51
51
|
route: `/api/_actions/${action.name}`,
|
|
52
|
-
method:
|
|
52
|
+
method: action.method,
|
|
53
53
|
handler: virtualKey
|
|
54
54
|
});
|
|
55
55
|
}
|
|
@@ -73,14 +73,15 @@ const module$1 = defineNuxtModule({
|
|
|
73
73
|
];
|
|
74
74
|
for (const action of actionFiles) {
|
|
75
75
|
const exportName = toCamelCase(action.name);
|
|
76
|
-
const
|
|
76
|
+
const fileBasename = action.method === "post" ? action.name : `${action.name}.${action.method}`;
|
|
77
|
+
const relativePath = posix.join("../..", "server", actionsDir, fileBasename);
|
|
77
78
|
lines.push(`import type _action_${exportName} from '${relativePath}'`);
|
|
78
79
|
}
|
|
79
80
|
lines.push("");
|
|
80
81
|
for (const action of actionFiles) {
|
|
81
82
|
const exportName = toCamelCase(action.name);
|
|
82
83
|
lines.push(
|
|
83
|
-
`export const ${exportName}: SafeActionReference<(typeof _action_${exportName})['_types']['input'], (typeof _action_${exportName})['_types']['output'], (typeof _action_${exportName})['_types']['serverError']> = Object.freeze({ __safeActionPath: '${action.name}' }) as any`
|
|
84
|
+
`export const ${exportName}: SafeActionReference<(typeof _action_${exportName})['_types']['input'], (typeof _action_${exportName})['_types']['output'], (typeof _action_${exportName})['_types']['serverError']> = Object.freeze({ __safeActionPath: '${action.name}', __safeActionMethod: '${action.method.toUpperCase()}' }) as any`
|
|
84
85
|
);
|
|
85
86
|
}
|
|
86
87
|
return lines.join("\n") + "\n";
|
|
@@ -97,6 +98,17 @@ const module$1 = defineNuxtModule({
|
|
|
97
98
|
nuxt.options.alias["#safe-action/actions"] = join(nuxt.options.buildDir, "safe-action/actions");
|
|
98
99
|
}
|
|
99
100
|
});
|
|
101
|
+
const HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
|
|
102
|
+
function parseMethodSuffix(filename) {
|
|
103
|
+
const dotIndex = filename.lastIndexOf(".");
|
|
104
|
+
if (dotIndex > 0) {
|
|
105
|
+
const suffix = filename.slice(dotIndex + 1).toLowerCase();
|
|
106
|
+
if (HTTP_METHODS.includes(suffix)) {
|
|
107
|
+
return { name: filename.slice(0, dotIndex), method: suffix };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { name: filename, method: "post" };
|
|
111
|
+
}
|
|
100
112
|
function scanActionFiles(dir, prefix = "") {
|
|
101
113
|
const results = [];
|
|
102
114
|
if (!existsSync(dir)) return results;
|
|
@@ -106,13 +118,27 @@ function scanActionFiles(dir, prefix = "") {
|
|
|
106
118
|
if (entry.isDirectory()) {
|
|
107
119
|
results.push(...scanActionFiles(fullPath, prefix ? `${prefix}/${entry.name}` : entry.name));
|
|
108
120
|
} else if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts") && entry.name !== "index.ts") {
|
|
109
|
-
const
|
|
110
|
-
|
|
121
|
+
const raw = basename(entry.name, ".ts");
|
|
122
|
+
const { name: parsedName, method } = parseMethodSuffix(raw);
|
|
123
|
+
const name = prefix ? `${prefix}/${parsedName}` : parsedName;
|
|
124
|
+
results.push({ name, filePath: fullPath, method });
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
127
|
return results;
|
|
114
128
|
}
|
|
115
129
|
function generateHandlerCode(action) {
|
|
130
|
+
if (action.method === "get") {
|
|
131
|
+
return `
|
|
132
|
+
import { defineEventHandler, getQuery } from 'h3'
|
|
133
|
+
import action from '${action.filePath}'
|
|
134
|
+
|
|
135
|
+
export default defineEventHandler(async (event) => {
|
|
136
|
+
const query = getQuery(event)
|
|
137
|
+
const rawInput = query.input ? JSON.parse(query.input) : undefined
|
|
138
|
+
return action._execute(rawInput, event)
|
|
139
|
+
})
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
116
142
|
return `
|
|
117
143
|
import { defineEventHandler, readBody } from 'h3'
|
|
118
144
|
import action from '${action.filePath}'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ref, computed, readonly } from "vue";
|
|
2
2
|
export function useAction(action, callbacks) {
|
|
3
3
|
const actionPath = action.__safeActionPath;
|
|
4
|
+
const actionMethod = action.__safeActionMethod || "POST";
|
|
4
5
|
const data = ref();
|
|
5
6
|
const serverError = ref();
|
|
6
7
|
const validationErrors = ref();
|
|
@@ -11,13 +12,9 @@ export function useAction(action, callbacks) {
|
|
|
11
12
|
status.value = "executing";
|
|
12
13
|
callbacks?.onExecute?.({ input });
|
|
13
14
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
method: "POST",
|
|
18
|
-
body: input
|
|
19
|
-
}
|
|
20
|
-
);
|
|
15
|
+
const fetchOptions = actionMethod === "GET" ? { method: "GET" } : { method: actionMethod, body: input };
|
|
16
|
+
const url = actionMethod === "GET" && input != null ? `/api/_actions/${actionPath}?input=${encodeURIComponent(JSON.stringify(input))}` : `/api/_actions/${actionPath}`;
|
|
17
|
+
const result = await $fetch(url, fetchOptions);
|
|
21
18
|
if (result.data !== void 0) {
|
|
22
19
|
data.value = result.data;
|
|
23
20
|
status.value = "hasSucceeded";
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -21,7 +21,6 @@ export interface SafeAction<TInput = unknown, TOutput = unknown, TServerError =
|
|
|
21
21
|
output: TOutput;
|
|
22
22
|
serverError: TServerError;
|
|
23
23
|
};
|
|
24
|
-
/** used by the generated Nitro handler */
|
|
25
24
|
_execute: (rawInput: unknown, event: H3Event) => Promise<ActionResult<TOutput, TServerError>>;
|
|
26
25
|
}
|
|
27
26
|
export interface SafeActionReference<TInput = unknown, TOutput = unknown, TServerError = string> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-safe-action",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Type-safe and validated server actions for Nuxt",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"zod": "^3.24.0"
|
|
81
81
|
},
|
|
82
82
|
"peerDependencies": {
|
|
83
|
-
"zod": "^3.20.0"
|
|
83
|
+
"zod": "^3.20.0 || ^4.0.0"
|
|
84
84
|
},
|
|
85
85
|
"peerDependenciesMeta": {
|
|
86
86
|
"zod": {
|