vite-elysia-forge 0.0.9 → 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/README.md CHANGED
@@ -61,16 +61,29 @@ bun run dev
61
61
 
62
62
  ### 3.1 Plugin Options
63
63
 
64
+ You can configure the plugin by passing an object with the following options:
65
+
66
+ | Option Key | Required | Default | Description |
67
+ | :-------------- | :------: | :----------------- | :--------------------------------------------------------------------- |
68
+ | `serverFile` | No | `"/server/api.ts"` | Path to your Elysia API module (relative to project root). |
69
+ | `ws` | No | `false` | Enable WebSocket support. Runs API as a separate process + Vite proxy. |
70
+ | `apiPrefix` | No | `"/api"` | Path prefix for API routes. Used for proxying in `ws` mode. |
71
+ | `backendPort` | No | `3001` | Port for the backend API server in `ws` mode. |
72
+ | `MAX_BODY_SIZE` | No | `1048576` (1MB) | Maximum allowed size for request bodies in bytes. |
73
+
64
74
  ```ts
65
75
  elysiaPlugin({
66
- // Path to your Elysia API module (relative to project root)
67
- serverFile?: string; // default: "/server/api.ts"
68
- })
76
+ serverFile: "/server/api.ts",
77
+ ws: true,
78
+ apiPrefix: "/api",
79
+ backendPort: 3001,
80
+ MAX_BODY_SIZE: 1024 * 1024, // 1MB
81
+ });
69
82
  ```
70
83
 
71
84
  ## 4. API Module Requirements
72
85
 
73
- Your API module must export an Elysia instance with a `handle(request: Request) => Promise<Response>` method.
86
+ Your API module must export an Elysia instance as `api`.
74
87
 
75
88
  ### 4.1 Basic Example
76
89
 
@@ -87,7 +100,53 @@ api.get("/users", () => ["user1", "user2"]);
87
100
  export default api;
88
101
  ```
89
102
 
90
- ## 5. Integration with @elysiajs/openapi
103
+ ### 4.2 WebSocket Example
104
+
105
+ ```ts
106
+ import { Elysia } from "elysia";
107
+
108
+ export const api = new Elysia({
109
+ prefix: "/api",
110
+ })
111
+ .get("/", () => "hello from elysia")
112
+ .ws("/ws", {
113
+ message(ws, message) {
114
+ ws.send(`Echo: ${message}`);
115
+ },
116
+ });
117
+
118
+ export default api;
119
+ ```
120
+
121
+ ## 5. WebSocket Support
122
+
123
+ By default, the plugin runs your API as middleware inside Vite's dev server. This works great for HTTP routes but **does not support WebSockets** (Elysia's `.ws()` routes).
124
+
125
+ To enable WebSocket support, set `ws: true`:
126
+
127
+ ```ts
128
+ elysiaPlugin({
129
+ serverFile: "./src/server/api.ts",
130
+ ws: true, // Enable WebSocket support
131
+ backendPort: 3001, // API runs on this port (default: 3001)
132
+ });
133
+ ```
134
+
135
+ ### 5.1 How WS Mode Works
136
+
137
+ When `ws: true`:
138
+
139
+ 1. The plugin spawns a **separate Bun process** that runs your API with `api.listen(backendPort)`.
140
+ 2. Vite is configured to **proxy** `/api` requests (including WebSocket upgrades) to that backend.
141
+ 3. On file changes, the backend process is **automatically restarted**.
142
+
143
+ This ensures full Bun runtime support for WebSockets, even if Vite itself runs under Node.js.
144
+
145
+ ### 5.2 Production
146
+
147
+ In production, the built server (`dist/server.js` or the compiled binary) runs your Elysia app directly with full WebSocket support—no proxy needed.
148
+
149
+ ## 6. Integration with @elysiajs/openapi
91
150
 
92
151
  To use the [@elysiajs/openapi plugin](https://elysiajs.com/patterns/openapi), add the following to your `tsconfig.json`:
93
152
 
@@ -100,7 +159,7 @@ To use the [@elysiajs/openapi plugin](https://elysiajs.com/patterns/openapi), ad
100
159
  }
101
160
  ```
102
161
 
103
- ### 5.1 Example with `fromTypes`
162
+ ### 6.1 Example with `fromTypes`
104
163
 
105
164
  It is recommended to pre-generate the declaration file (`.d.ts`) to provide type declaration to the generator.
106
165
 
@@ -115,12 +174,16 @@ const app = new Elysia().use(
115
174
  );
116
175
  ```
117
176
 
118
- ## 6. Production Deployment
177
+ ## 7. Production Deployment
119
178
 
120
- ### 6.1 Build Configuration
179
+ ### 7.1 Build Configuration
121
180
 
122
181
  Update your `package.json` scripts:
123
182
 
183
+ Pick **one** build mode.
184
+
185
+ Option A: build to `dist/server.js` (run with Bun):
186
+
124
187
  ```json
125
188
  {
126
189
  "scripts": {
@@ -131,13 +194,25 @@ Update your `package.json` scripts:
131
194
  }
132
195
  ```
133
196
 
197
+ Option B: build + compile to a standalone binary `dist/server`:
198
+
199
+ ```json
200
+ {
201
+ "scripts": {
202
+ "dev": "vite",
203
+ "build": "vite-elysia-forge build-compile",
204
+ "start": "./dist/server"
205
+ }
206
+ }
207
+ ```
208
+
134
209
  If your API is located elsewhere, specify the path:
135
210
 
136
211
  ```bash
137
212
  vite-elysia-forge build src/my-api.ts
138
213
  ```
139
214
 
140
- ### 6.2 Building for Production
215
+ ### 7.2 Building for Production
141
216
 
142
217
  Run the build command:
143
218
 
@@ -151,7 +226,17 @@ This command performs the following steps:
151
226
  2. Automatically generates a temporary entry file that imports your API from `src/server/api.ts`
152
227
  3. Bundles the server into a single file at `dist/server.js`
153
228
 
154
- ### 6.3 Starting the Production Server
229
+ ### 7.3 Building a Standalone Binary
230
+
231
+ If you want a single executable (no Bun runtime required on the target machine), set your `build` script to `vite-elysia-forge build-compile` (Option B above) and run:
232
+
233
+ ```bash
234
+ bun run build
235
+ ```
236
+
237
+ This runs the normal build and then compiles `dist/server.js` into a standalone binary at `dist/server`.
238
+
239
+ ### 7.4 Starting the Production Server
155
240
 
156
241
  Start the server with:
157
242
 
@@ -159,9 +244,9 @@ Start the server with:
159
244
  bun start
160
245
  ```
161
246
 
162
- ## 7. Troubleshooting
247
+ ## 8. Troubleshooting
163
248
 
164
- ### 7.1 "Bun is not defined" Error
249
+ ### 8.1 "Bun is not defined" Error
165
250
 
166
251
  If you encounter this error, ensure you are running Vite with the Bun runtime:
167
252
 
@@ -187,14 +272,50 @@ Or update your `dev` script in `package.json`:
187
272
  - **Node.js Compatibility:** While Bun has excellent Node.js compatibility, some Vite plugins that rely on obscure Node.js internals might behave unexpectedly.
188
273
  - **Performance:** Running Vite under Bun is generally faster, but you might encounter edge cases where optimization differs from Node.js.
189
274
 
190
- ### 7.2 Hot Reload Not Working
275
+ ### 8.2 Hot Reload Not Working
191
276
 
192
277
  Check that your file changes are within the dependency graph of your API module. The plugin uses Vite's dependency tracking to determine when to reload.
193
278
 
194
- ## 8. Authors
279
+ ### 8.3 WebSocket "adapter doesn't support" Error
280
+
281
+ If you see `Current adapter doesn't support WebSocket`, you need to enable WS mode:
282
+
283
+ ```ts
284
+ elysiaPlugin({
285
+ serverFile: "./src/server/api.ts",
286
+ ws: true,
287
+ });
288
+ ```
289
+
290
+ This spawns your API as a separate Bun process with full WebSocket support.
291
+
292
+ ### 8.4 "ReferenceError: process is not defined" with OpenAPI
293
+
294
+ If you use `@elysiajs/openapi` with `fromTypes` and see this error in the browser console:
295
+
296
+ \`\`\`
297
+ Uncaught ReferenceError: process is not defined
298
+ at fromTypes ...
299
+ \`\`\`
300
+
301
+ This happens because \`fromTypes\` relies on Node.js/Bun APIs that don't exist in the browser. It usually means you are importing your server file as a value in client-side code.
302
+
303
+ **Solution:** Use \`import type\` when importing your API instance for Eden Treaty.
304
+
305
+ \`\`\`ts
306
+ // ❌ Incorrect
307
+ import { api } from './server/api'
308
+ const client = treaty(api)
309
+
310
+ // ✅ Correct
311
+ import type { api } from './server/api'
312
+ const client = treaty<typeof api>('localhost:3000')
313
+ \`\`\`
314
+
315
+ ## 9. Authors
195
316
 
196
317
  - Chijioke Udokporo ([@chijiokeudokporo](https://github.com/chijioke-udokporo))
197
318
 
198
- ## 9. License
319
+ ## 10. License
199
320
 
200
321
  MIT
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
2
  declare function build(apiEntry?: string): Promise<void>;
3
+ declare function buildCompile(apiEntry?: string): Promise<void>;
3
4
 
4
- export { build };
5
+ export { build, buildCompile };
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env bun
2
- import {spawnSync}from'child_process';import {existsSync,mkdirSync,writeFileSync,unlinkSync,rmSync}from'fs';import {resolve,relative,sep}from'path';async function b(o="src/server/api.ts"){let c=resolve(process.cwd(),o);existsSync(c)||(console.error(`\u274C API entry file "${o}" not found.`),console.error(' By default, vite-elysia-forge looks for "src/server/api.ts".'),console.error(" If your API is located elsewhere, please specify the path:"),console.error(" $ vite-elysia-forge build <path-to-your-api-file>"),process.exit(1));let t=spawnSync("bun",["x","vite","build"],{stdio:"inherit",env:{...process.env,NODE_ENV:"production"}});t.status!==0&&(console.error("\u274C Vite build failed"),process.exit(t.status||1));let e=resolve(process.cwd(),".output");existsSync(e)||mkdirSync(e,{recursive:true});let s=resolve(e,".temp-prod.ts"),r=relative(e,c);r=r.split(sep).join("/"),r.startsWith(".")||(r="./"+r);let a=`
2
+ import {spawnSync}from'child_process';import {existsSync,mkdirSync,writeFileSync,unlinkSync,rmSync}from'fs';import {resolve,relative,sep}from'path';async function u(e="src/server/api.ts"){let r=resolve(process.cwd(),e);existsSync(r)||(console.error(`\u274C API entry file "${e}" not found.`),console.error(' By default, vite-elysia-forge looks for "src/server/api.ts".'),console.error(" If your API is located elsewhere, please specify the path:"),console.error(" $ vite-elysia-forge build <path-to-your-api-file>"),process.exit(1));let o=spawnSync("bun",["x","vite","build"],{stdio:"inherit",env:{...process.env,NODE_ENV:"production"}});o.status!==0&&(console.error("\u274C Vite build failed"),process.exit(o.status||1));let s=resolve(process.cwd(),".output");existsSync(s)||mkdirSync(s,{recursive:true});let i=resolve(s,".temp-prod.ts"),t=relative(s,r);t=t.split(sep).join("/"),t.startsWith(".")||(t="./"+t);let p=`
3
3
  import { startServer } from "vite-elysia-forge/production";
4
- import { api } from "${r}";
4
+ import { api } from ${JSON.stringify(t)};
5
5
 
6
6
  startServer({
7
7
  api,
8
8
  port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
9
9
  distDir: "dist",
10
10
  });
11
- `;writeFileSync(s,a);try{let i=await Bun.build({entrypoints:[s],outdir:"dist",target:"bun",minify:!0,naming:"server.js"});if(!i.success){console.error("\u274C Server build failed");for(let u of i.logs)console.error(u);process.exit(1);}}catch(i){console.error("\u274C Failed to build server. Ensure you are running this command with Bun."),console.error(i),process.exit(1);}finally{existsSync(s)&&unlinkSync(s),existsSync(e)&&rmSync(e,{recursive:true,force:true});}}if(import.meta.main){let o=process.argv.slice(2);if(o[0]==="build"){let t=o[1];b(t);}else console.log("Usage: vite-elysia-forge build [api-entry]"),console.log(" api-entry: Path to your API entry file (default: src/server/api.ts)");}export{b as build};
11
+ `;writeFileSync(i,p);try{let n=await Bun.build({entrypoints:[i],outdir:"dist",target:"bun",minify:!0,naming:"server.js"});if(!n.success){console.error("\u274C Server build failed");for(let d of n.logs)console.error(d);process.exit(1);}}catch(n){console.error("\u274C Failed to build server. Ensure you are running this command with Bun."),console.error(n),process.exit(1);}finally{existsSync(i)&&unlinkSync(i),existsSync(s)&&rmSync(s,{recursive:true,force:true});}}async function h(e="src/server/api.ts"){await u(e);let r=spawnSync("bun",["build","--compile","dist/server.js","--outfile","dist/server"],{stdio:"inherit",env:{...process.env,NODE_ENV:"production"}});r.status!==0&&(console.error("\u274C Bun compile failed"),process.exit(r.status||1));}if(import.meta.main){let e=process.argv.slice(2),r=e[0];if(r==="build"){let o=e[1];u(o);}else if(r==="build-compile"){let o=e[1];h(o);}else console.log("Usage: vite-elysia-forge <command> [api-entry]"),console.log("Commands:"),console.log(" build Build frontend + bundle server to dist/server.js"),console.log(" build-compile Build and compile a standalone server binary to dist/server"),console.log(""),console.log("api-entry: Path to your API entry file (default: src/server/api.ts)");}export{u as build,h as buildCompile};
package/dist/index.cjs CHANGED
@@ -1,2 +1,5 @@
1
- 'use strict';var path=require('path');function E({serverFile:g="/server/api.ts"}={}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=path.resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=E;
2
- module.exports=P;
1
+ 'use strict';var path=require('path'),child_process=require('child_process'),fs=require('fs');function F({serverFile:v="/server/api.ts",ws:d=false,apiPrefix:E="/api",backendPort:h=3001,MAX_BODY_SIZE:M=1024*1024}={}){return {name:"vite-elysia-forge",config:d?()=>({server:{proxy:{[E]:{target:`http://localhost:${h}`,changeOrigin:true,ws:true}}}}):void 0,async configureServer(o){let l=v,b=path.resolve(o.config.root,l.slice(1)),w=async()=>(await o.ssrLoadModule(l)).api,S=await w(),s=null,g=false,P=async()=>{if(d&&!g){g=true;try{s&&(s.kill("SIGTERM"),s=null);let e=path.resolve(o.config.root,"node_modules",".vite-elysia-forge"),t=path.resolve(e,"dev-server.ts"),a=path.resolve(o.config.root,l.startsWith("/")?l.slice(1):l),i=path.relative(e,a);i.startsWith(".")||(i="./"+i),fs.existsSync(e)||fs.mkdirSync(e,{recursive:!0});let c=`import { api } from ${JSON.stringify(i)};
2
+ api.listen(${h});
3
+ console.log("WebSocket server running at ws://localhost:${h}");
4
+ `;fs.writeFileSync(t,c),s=child_process.spawn("bun",["run",t],{stdio:["ignore","inherit","inherit"],cwd:o.config.root,env:{...process.env}}),s.on("error",n=>{console.error(`Failed to start API server: ${n.message}`);}),s.on("exit",n=>{n!==null&&n!==0&&console.error(`API server process exited with code ${n}`),s=null;});}finally{g=false;}}};d&&(await P(),o.httpServer?.once("close",()=>{s&&(s.kill("SIGTERM"),s=null);})),o.watcher.add(b),o.watcher.on("change",async e=>{let t=await o.moduleGraph.getModuleByUrl(l);if(!t)return;let a=o.moduleGraph.getModulesByFile(e);if(!a||a.size===0)return;let i=false,c=new Set,n=[...a];for(;n.length>0;){let r=n.shift();if(!(!r||!r.id||c.has(r.id))){if(c.add(r.id),r.id===t.id){i=true;break}for(let m of r.importers)n.push(m);}}if(i)try{o.moduleGraph.invalidateModule(t),S=await w(),console.log("Reloaded Elysia API module"),d&&await P();}catch(r){console.error(`Failed to reload Elysia API: ${r}`);}}),!d&&o.middlewares.use(async(e,t,a)=>{if(!e.url?.startsWith("/api"))return a();try{let i="http",c=e.headers.host||"localhost:3000",n=`${i}://${c}${e.url}`,r;if(e.method!=="GET"&&e.method!=="HEAD"){let u=[],f=0;for await(let $ of e){if(f+=$.length,f>M){t.statusCode=413,t.end("Payload Too Large");return}u.push($);}r=Buffer.concat(u).toString();}let m=new Request(n,{method:e.method,headers:e.headers,body:r}),y=await S.handle(m);t.statusCode=y.status,y.headers.forEach((u,f)=>{t.setHeader(f,u);});let k=await y.text();t.end(k);}catch(i){console.error(`Elysia error: ${i}`),t.statusCode=500,t.end("Internal Server Error");}});}}}var T=F;
5
+ module.exports=T;
package/dist/index.d.cts CHANGED
@@ -10,6 +10,34 @@ interface ConfigOptions {
10
10
  * @default "/server/api.ts"
11
11
  */
12
12
  serverFile?: string;
13
+ /**
14
+ * Enable WebSocket-capable mode by running the API as a real Bun/Elysia server
15
+ * on a separate port, and letting Vite proxy to it (including WS upgrades).
16
+ *
17
+ * When enabled, the plugin will:
18
+ * - start (and hot-restart) `api.listen(backendPort)`
19
+ * - configure Vite `server.proxy[apiPrefix]` with `ws: true`
20
+ *
21
+ * @default false
22
+ */
23
+ ws?: boolean;
24
+ /**
25
+ * Path prefix for API routes.
26
+ * Used for Vite proxy configuration in `ws` mode.
27
+ * @default "/api"
28
+ */
29
+ apiPrefix?: string;
30
+ /**
31
+ * The port to run the backend API server on in `ws` mode.
32
+ * @default 3001
33
+ */
34
+ backendPort?: number;
35
+ /**
36
+ * Maximum allowed size for request bodies in bytes.
37
+ * Requests exceeding this size will receive a 413 Payload Too Large response.
38
+ * @default 1048576 (1MB)
39
+ */
40
+ MAX_BODY_SIZE?: number;
13
41
  }
14
42
  /**
15
43
  * A Vite plugin that integrates ElysiaJS into the Vite development server.
@@ -20,6 +48,6 @@ interface ConfigOptions {
20
48
  * @param options - Configuration options for the plugin.
21
49
  * @returns A Vite plugin instance.
22
50
  */
23
- declare function elysiaPlugin({ serverFile }?: ConfigOptions): Plugin;
51
+ declare function elysiaPlugin({ serverFile, ws, apiPrefix, backendPort, MAX_BODY_SIZE, }?: ConfigOptions): Plugin;
24
52
 
25
53
  export { type ConfigOptions, elysiaPlugin as default };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,34 @@ interface ConfigOptions {
10
10
  * @default "/server/api.ts"
11
11
  */
12
12
  serverFile?: string;
13
+ /**
14
+ * Enable WebSocket-capable mode by running the API as a real Bun/Elysia server
15
+ * on a separate port, and letting Vite proxy to it (including WS upgrades).
16
+ *
17
+ * When enabled, the plugin will:
18
+ * - start (and hot-restart) `api.listen(backendPort)`
19
+ * - configure Vite `server.proxy[apiPrefix]` with `ws: true`
20
+ *
21
+ * @default false
22
+ */
23
+ ws?: boolean;
24
+ /**
25
+ * Path prefix for API routes.
26
+ * Used for Vite proxy configuration in `ws` mode.
27
+ * @default "/api"
28
+ */
29
+ apiPrefix?: string;
30
+ /**
31
+ * The port to run the backend API server on in `ws` mode.
32
+ * @default 3001
33
+ */
34
+ backendPort?: number;
35
+ /**
36
+ * Maximum allowed size for request bodies in bytes.
37
+ * Requests exceeding this size will receive a 413 Payload Too Large response.
38
+ * @default 1048576 (1MB)
39
+ */
40
+ MAX_BODY_SIZE?: number;
13
41
  }
14
42
  /**
15
43
  * A Vite plugin that integrates ElysiaJS into the Vite development server.
@@ -20,6 +48,6 @@ interface ConfigOptions {
20
48
  * @param options - Configuration options for the plugin.
21
49
  * @returns A Vite plugin instance.
22
50
  */
23
- declare function elysiaPlugin({ serverFile }?: ConfigOptions): Plugin;
51
+ declare function elysiaPlugin({ serverFile, ws, apiPrefix, backendPort, MAX_BODY_SIZE, }?: ConfigOptions): Plugin;
24
52
 
25
53
  export { type ConfigOptions, elysiaPlugin as default };
package/dist/index.js CHANGED
@@ -1,2 +1,5 @@
1
- import {resolve}from'path';function E({serverFile:g="/server/api.ts"}={}){return {name:"vite-elysia-forge",async configureServer(s){let l=g,y=resolve(s.config.root,l.slice(1)),f=async()=>(await s.ssrLoadModule(l)).api,p=await f();s.watcher.add(y),s.watcher.on("change",async e=>{let o=await s.moduleGraph.getModuleByUrl(l);if(!o)return;let i=s.moduleGraph.getModulesByFile(e);if(!i||i.size===0)return;let n=false,r=new Set,a=[...i];for(;a.length>0;){let t=a.shift();if(!(!t||!t.id||r.has(t.id))){if(r.add(t.id),t.id===o.id){n=true;break}for(let c of t.importers)a.push(c);}}if(n)try{s.moduleGraph.invalidateModule(o),p=await f(),console.log("[vite-elysia-forge] Reloaded Elysia API module");}catch(t){console.error(`[vite-elysia-forge] Failed to reload Elysia API: ${t}`);}}),s.middlewares.use(async(e,o,i)=>{if(!e.url?.startsWith("/api"))return i();try{let n="http",r=e.headers.host||"localhost:3000",a=`${n}://${r}${e.url}`,t;if(e.method!=="GET"&&e.method!=="HEAD"){let d=[];for await(let h of e)d.push(h);t=Buffer.concat(d).toString();}let c=new Request(a,{method:e.method,headers:e.headers,body:t}),u=await p.handle(c);o.statusCode=u.status,u.headers.forEach((d,h)=>{o.setHeader(h,d);});let m=await u.text();o.end(m);}catch(n){console.error(`[vite-elysia-forge] Elysia error: ${n}`),o.statusCode=500,o.end("Internal Server Error");}});}}}var P=E;
2
- export{P as default};
1
+ import {resolve,relative}from'path';import {spawn}from'child_process';import {existsSync,mkdirSync,writeFileSync}from'fs';function F({serverFile:v="/server/api.ts",ws:d=false,apiPrefix:E="/api",backendPort:h=3001,MAX_BODY_SIZE:M=1024*1024}={}){return {name:"vite-elysia-forge",config:d?()=>({server:{proxy:{[E]:{target:`http://localhost:${h}`,changeOrigin:true,ws:true}}}}):void 0,async configureServer(o){let l=v,b=resolve(o.config.root,l.slice(1)),w=async()=>(await o.ssrLoadModule(l)).api,S=await w(),s=null,g=false,P=async()=>{if(d&&!g){g=true;try{s&&(s.kill("SIGTERM"),s=null);let e=resolve(o.config.root,"node_modules",".vite-elysia-forge"),t=resolve(e,"dev-server.ts"),a=resolve(o.config.root,l.startsWith("/")?l.slice(1):l),i=relative(e,a);i.startsWith(".")||(i="./"+i),existsSync(e)||mkdirSync(e,{recursive:!0});let c=`import { api } from ${JSON.stringify(i)};
2
+ api.listen(${h});
3
+ console.log("WebSocket server running at ws://localhost:${h}");
4
+ `;writeFileSync(t,c),s=spawn("bun",["run",t],{stdio:["ignore","inherit","inherit"],cwd:o.config.root,env:{...process.env}}),s.on("error",n=>{console.error(`Failed to start API server: ${n.message}`);}),s.on("exit",n=>{n!==null&&n!==0&&console.error(`API server process exited with code ${n}`),s=null;});}finally{g=false;}}};d&&(await P(),o.httpServer?.once("close",()=>{s&&(s.kill("SIGTERM"),s=null);})),o.watcher.add(b),o.watcher.on("change",async e=>{let t=await o.moduleGraph.getModuleByUrl(l);if(!t)return;let a=o.moduleGraph.getModulesByFile(e);if(!a||a.size===0)return;let i=false,c=new Set,n=[...a];for(;n.length>0;){let r=n.shift();if(!(!r||!r.id||c.has(r.id))){if(c.add(r.id),r.id===t.id){i=true;break}for(let m of r.importers)n.push(m);}}if(i)try{o.moduleGraph.invalidateModule(t),S=await w(),console.log("Reloaded Elysia API module"),d&&await P();}catch(r){console.error(`Failed to reload Elysia API: ${r}`);}}),!d&&o.middlewares.use(async(e,t,a)=>{if(!e.url?.startsWith("/api"))return a();try{let i="http",c=e.headers.host||"localhost:3000",n=`${i}://${c}${e.url}`,r;if(e.method!=="GET"&&e.method!=="HEAD"){let u=[],f=0;for await(let $ of e){if(f+=$.length,f>M){t.statusCode=413,t.end("Payload Too Large");return}u.push($);}r=Buffer.concat(u).toString();}let m=new Request(n,{method:e.method,headers:e.headers,body:r}),y=await S.handle(m);t.statusCode=y.status,y.headers.forEach((u,f)=>{t.setHeader(f,u);});let k=await y.text();t.end(k);}catch(i){console.error(`Elysia error: ${i}`),t.statusCode=500,t.end("Internal Server Error");}});}}}var T=F;
5
+ export{T as default};