vite-plugin-server-actions 0.1.0 → 1.0.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/index.d.ts ADDED
@@ -0,0 +1,200 @@
1
+ import type { Plugin } from "vite";
2
+ import type { RequestHandler } from "express";
3
+ import type { z } from "zod";
4
+
5
+ export interface ValidationOptions {
6
+ /**
7
+ * Enable validation for server actions
8
+ * @default false
9
+ */
10
+ enabled?: boolean;
11
+
12
+ /**
13
+ * Validation adapter to use
14
+ * @default "zod"
15
+ */
16
+ adapter?: "zod";
17
+ }
18
+
19
+ export interface OpenAPIOptions {
20
+ /**
21
+ * Enable OpenAPI documentation generation
22
+ * @default false
23
+ */
24
+ enabled?: boolean;
25
+
26
+ /**
27
+ * OpenAPI specification info
28
+ */
29
+ info?: {
30
+ title?: string;
31
+ version?: string;
32
+ description?: string;
33
+ };
34
+
35
+ /**
36
+ * Path to serve the Swagger UI documentation
37
+ * @default "/api/docs"
38
+ */
39
+ docsPath?: string;
40
+
41
+ /**
42
+ * Path to serve the OpenAPI JSON specification
43
+ * @default "/api/openapi.json"
44
+ */
45
+ specPath?: string;
46
+
47
+ /**
48
+ * Enable Swagger UI
49
+ * @default true when OpenAPI is enabled
50
+ */
51
+ swaggerUI?: boolean;
52
+ }
53
+
54
+ export interface ServerActionOptions {
55
+ /**
56
+ * Custom API prefix for server action endpoints
57
+ * @default "/api"
58
+ */
59
+ apiPrefix?: string;
60
+
61
+ /**
62
+ * Include patterns for server action files
63
+ * @default ["**\/*.server.js"]
64
+ */
65
+ include?: string | string[];
66
+
67
+ /**
68
+ * Exclude patterns for server action files
69
+ * @default []
70
+ */
71
+ exclude?: string | string[];
72
+
73
+ /**
74
+ * Middleware to run before server action handlers
75
+ * Can be a single middleware or array of middleware
76
+ */
77
+ middleware?: RequestHandler | RequestHandler[];
78
+
79
+ /**
80
+ * Transform function for module names (internal use)
81
+ * @param filePath - The file path relative to project root
82
+ * @returns The module name to use internally
83
+ */
84
+ moduleNameTransform?: (filePath: string) => string;
85
+
86
+ /**
87
+ * Transform function for API routes
88
+ * @param filePath - The file path relative to project root
89
+ * @param functionName - The exported function name
90
+ * @returns The API route path (without prefix)
91
+ * @default Clean hierarchical paths (removes src/ and .server.js)
92
+ */
93
+ routeTransform?: (filePath: string, functionName: string) => string;
94
+
95
+ /**
96
+ * Validation configuration
97
+ */
98
+ validation?: ValidationOptions;
99
+
100
+ /**
101
+ * OpenAPI documentation configuration
102
+ */
103
+ openAPI?: OpenAPIOptions;
104
+ }
105
+
106
+ export interface ServerActionsPlugin extends Plugin {
107
+ name: "vite-plugin-server-actions";
108
+ }
109
+
110
+ /**
111
+ * Creates a Vite plugin that enables server actions
112
+ * @param options - Configuration options for the plugin
113
+ * @returns Vite plugin instance
114
+ */
115
+ declare function serverActions(options?: ServerActionOptions): ServerActionsPlugin;
116
+
117
+ /**
118
+ * Built-in middleware for server actions
119
+ */
120
+ export declare const middleware: {
121
+ /**
122
+ * Logging middleware that displays server action calls with formatted JSON output
123
+ */
124
+ logging: RequestHandler;
125
+ };
126
+
127
+ /**
128
+ * Path transformation utilities
129
+ */
130
+ export declare const pathUtils: {
131
+ /**
132
+ * Creates clean hierarchical routes: "actions/todo/create"
133
+ * @param filePath - The file path relative to project root
134
+ * @param functionName - The exported function name
135
+ * @returns Clean route path
136
+ */
137
+ createCleanRoute: (filePath: string, functionName: string) => string;
138
+
139
+ /**
140
+ * Creates legacy underscore-separated routes: "src_actions_todo/create"
141
+ * @param filePath - The file path relative to project root
142
+ * @param functionName - The exported function name
143
+ * @returns Legacy route path
144
+ */
145
+ createLegacyRoute: (filePath: string, functionName: string) => string;
146
+
147
+ /**
148
+ * Creates minimal routes: "actions/todo.server/create"
149
+ * @param filePath - The file path relative to project root
150
+ * @param functionName - The exported function name
151
+ * @returns Minimal route path
152
+ */
153
+ createMinimalRoute: (filePath: string, functionName: string) => string;
154
+
155
+ /**
156
+ * Creates module names for internal use
157
+ * @param filePath - The file path relative to project root
158
+ * @returns Module name
159
+ */
160
+ createModuleName: (filePath: string) => string;
161
+ };
162
+
163
+ // Validation exports
164
+ export interface ValidationAdapter {
165
+ validate(schema: any, data: any): Promise<any>;
166
+ getSchemaType(schema: any): string;
167
+ }
168
+
169
+ export declare class ZodAdapter implements ValidationAdapter {
170
+ validate(schema: z.ZodSchema<any>, data: any): Promise<any>;
171
+ getSchemaType(schema: z.ZodSchema<any>): string;
172
+ }
173
+
174
+ export declare class SchemaDiscovery {
175
+ constructor();
176
+ registerSchema(moduleName: string, functionName: string, schema: any): void;
177
+ getSchema(moduleName: string, functionName: string): any;
178
+ getAllSchemas(): Map<string, any>;
179
+ discoverFromModule(module: any, moduleName: string): void;
180
+ }
181
+
182
+ export declare const adapters: {
183
+ zod: ZodAdapter;
184
+ };
185
+
186
+ export declare function createValidationMiddleware(options: {
187
+ schemaDiscovery: SchemaDiscovery;
188
+ }): RequestHandler;
189
+
190
+ // OpenAPI exports
191
+ export declare class OpenAPIGenerator {
192
+ constructor(options?: { info?: any });
193
+ generateSpec(serverFunctions: Map<string, any>, schemaDiscovery: SchemaDiscovery, options?: any): any;
194
+ }
195
+
196
+ export declare function setupOpenAPIEndpoints(app: any, options: any): void;
197
+
198
+ export declare function createSwaggerMiddleware(spec: any): RequestHandler;
199
+
200
+ export default serverActions;
package/package.json CHANGED
@@ -1,39 +1,104 @@
1
1
  {
2
2
  "name": "vite-plugin-server-actions",
3
- "description": "Automatically proxy imported backend functions to a server endpoint in Vite",
4
- "version": "0.1.0",
5
- "type": "module",
3
+ "version": "1.0.0",
4
+ "description": "Server actions for Vite - call backend functions directly from your frontend with automatic API generation, TypeScript support, and zero configuration",
6
5
  "keywords": [
6
+ "vite",
7
7
  "vite-plugin",
8
+ "server-actions",
8
9
  "server",
9
- "actions"
10
+ "backend",
11
+ "api",
12
+ "rpc",
13
+ "typescript",
14
+ "openapi",
15
+ "swagger",
16
+ "validation",
17
+ "zod",
18
+ "full-stack",
19
+ "serverless",
20
+ "functions",
21
+ "middleware",
22
+ "express"
10
23
  ],
11
- "license": "MIT",
12
24
  "homepage": "https://github.com/HelgeSverre/vite-plugin-server-actions",
13
- "repository": {
14
- "type": "git",
15
- "url": "https://github.com/HelgeSverre/vite-plugin-server-actions"
16
- },
17
25
  "bugs": {
18
26
  "url": "https://github.com/HelgeSverre/vite-plugin-server-actions/issues"
19
27
  },
20
- "readme": "README.md",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/HelgeSverre/vite-plugin-server-actions.git"
31
+ },
32
+ "license": "MIT",
21
33
  "author": {
22
34
  "name": "Helge Sverre",
23
35
  "email": "helge.sverre@gmail.com",
24
36
  "url": "https://helgesver.re"
25
37
  },
38
+ "type": "module",
26
39
  "main": "src/index.js",
40
+ "types": "index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "import": "./src/index.js",
44
+ "types": "./index.d.ts"
45
+ }
46
+ },
47
+ "files": [
48
+ "src",
49
+ "index.d.ts",
50
+ "README.md",
51
+ "LICENSE"
52
+ ],
53
+ "engines": {
54
+ "node": ">=16.0.0"
55
+ },
27
56
  "scripts": {
57
+ "example:svelte:build": "npm run build --prefix examples/svelte-todo-app",
58
+ "example:svelte:dev": "npm run dev --prefix examples/svelte-todo-app",
59
+ "example:vue:build": "npm run build --prefix examples/vue-todo-app",
60
+ "example:vue:dev": "npm run dev --prefix examples/vue-todo-app",
61
+ "example:react:build": "npm run build --prefix examples/react-todo-app",
62
+ "example:react:dev": "npm run dev --prefix examples/react-todo-app",
28
63
  "format": "npx prettier --write src/ README.md",
29
- "sort": "npx sort-package-json"
64
+ "lint": "eslint src/",
65
+ "lint:fix": "eslint src/ --fix",
66
+ "sort": "npx sort-package-json",
67
+ "test": "vitest",
68
+ "test:run": "vitest run",
69
+ "test:e2e": "playwright test",
70
+ "test:e2e:ui": "playwright test --ui",
71
+ "typecheck": "tsc --noEmit",
72
+ "check": "npm run test:run && npm run lint && npm run typecheck",
73
+ "prepublishOnly": "npm run check"
30
74
  },
31
- "devDependencies": {
75
+ "dependencies": {
76
+ "@asteasolutions/zod-to-openapi": "^7.3.4",
32
77
  "express": "^4.21.0",
33
- "prettier": "^3.3.3",
34
- "vitest": "^0.34.0"
78
+ "minimatch": "^10.0.3",
79
+ "rollup": "^4.0.0",
80
+ "swagger-ui-express": "^5.0.0",
81
+ "zod": "^3.22.4"
82
+ },
83
+ "devDependencies": {
84
+ "@apidevtools/swagger-parser": "^12.0.0",
85
+ "@eslint/js": "^9.29.0",
86
+ "@playwright/test": "^1.53.1",
87
+ "@stoplight/spectral-core": "^1.20.0",
88
+ "@stoplight/spectral-rulesets": "^1.22.0",
89
+ "@types/express": "^5.0.3",
90
+ "@types/node": "^24.0.3",
91
+ "@types/swagger-ui-express": "^4.1.6",
92
+ "@vitest/runner": "^3.2.4",
93
+ "eslint": "^9.29.0",
94
+ "playwright": "^1.53.1",
95
+ "prettier": "^3.6.0",
96
+ "typescript": "^5.8.3",
97
+ "vite": "^6.3.5",
98
+ "vitest": "^3.2.4"
35
99
  },
36
100
  "peerDependencies": {
37
- "vite": "^2.0.0 || ^3.0.0 || ^4.0.0"
38
- }
101
+ "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
102
+ },
103
+ "readme": "README.md"
39
104
  }
@@ -0,0 +1,101 @@
1
+ import { createRequire } from "module";
2
+ import { pathToFileURL } from "url";
3
+
4
+ /**
5
+ * Extract schemas from server modules during build time
6
+ */
7
+ export async function extractSchemas(serverFunctions) {
8
+ const schemas = {};
9
+
10
+ for (const [moduleName, { id, functions }] of serverFunctions) {
11
+ schemas[moduleName] = {};
12
+
13
+ try {
14
+ // Import the module to get schemas
15
+ const moduleUrl = pathToFileURL(id).href;
16
+ const module = await import(moduleUrl);
17
+
18
+ // Extract schemas from exported functions
19
+ for (const functionName of functions) {
20
+ if (module[functionName] && module[functionName].schema) {
21
+ // We need to serialize the Zod schema
22
+ // For now, we'll store a reference that can be imported
23
+ schemas[moduleName][functionName] = {
24
+ hasSchema: true,
25
+ // We'll need to generate import statements for these
26
+ };
27
+ }
28
+ }
29
+ } catch (error) {
30
+ console.warn(`Failed to extract schemas from ${id}: ${error.message}`);
31
+ }
32
+ }
33
+
34
+ return schemas;
35
+ }
36
+
37
+ /**
38
+ * Generate validation setup code for production
39
+ */
40
+ export function generateValidationCode(options, serverFunctions) {
41
+ if (!options.validation?.enabled) {
42
+ return {
43
+ imports: "",
44
+ setup: "",
45
+ middlewareFactory: "",
46
+ };
47
+ }
48
+
49
+ // Generate imports
50
+ const imports = `
51
+ import { createValidationMiddleware, SchemaDiscovery } from '../../../src/validation.js';
52
+ `;
53
+
54
+ // Generate schema imports from the bundled actions
55
+ const schemaImports = Array.from(serverFunctions.entries())
56
+ .map(([moduleName, { functions }]) => {
57
+ return functions.map((fn) => `// Import schema for ${moduleName}.${fn} if it exists`).join("\n");
58
+ })
59
+ .join("\n");
60
+
61
+ // Generate setup code
62
+ const setup = `
63
+ // Setup validation
64
+ const schemaDiscovery = new SchemaDiscovery();
65
+ const validationMiddleware = createValidationMiddleware({ schemaDiscovery });
66
+
67
+ // Register schemas from server actions
68
+ ${Array.from(serverFunctions.entries())
69
+ .map(([moduleName, { functions }]) => {
70
+ return functions
71
+ .map(
72
+ (fn) => `
73
+ if (serverActions.${moduleName}.${fn}.schema) {
74
+ schemaDiscovery.registerSchema('${moduleName}', '${fn}', serverActions.${moduleName}.${fn}.schema);
75
+ }`,
76
+ )
77
+ .join("\n");
78
+ })
79
+ .join("\n")}
80
+ `;
81
+
82
+ // Generate middleware factory
83
+ const middlewareFactory = `
84
+ function createContextualValidationMiddleware(moduleName, functionName) {
85
+ return (req, res, next) => {
86
+ req.validationContext = {
87
+ moduleName,
88
+ functionName,
89
+ schema: serverActions[moduleName]?.[functionName]?.schema
90
+ };
91
+ return validationMiddleware(req, res, next);
92
+ };
93
+ }
94
+ `;
95
+
96
+ return {
97
+ imports: imports + schemaImports,
98
+ setup,
99
+ middlewareFactory,
100
+ };
101
+ }