@donkeylabs/adapter-sveltekit 2.0.14 → 2.0.16

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/vite.js ADDED
@@ -0,0 +1,611 @@
1
+ /**
2
+ * Vite plugin for @donkeylabs/adapter-sveltekit dev server integration
3
+ *
4
+ * Supports two modes:
5
+ * - `bun --bun run dev`: Single-process mode (in-process, one port)
6
+ * - `bun run dev`: Subprocess mode (two processes, proxy)
7
+ */
8
+ import { spawn, exec } from "node:child_process";
9
+ import { resolve, join } from "node:path";
10
+ import { watch, existsSync } from "node:fs";
11
+ import { promisify } from "node:util";
12
+ const execAsync = promisify(exec);
13
+ import http from "node:http";
14
+ // Check if running with Bun runtime (bun --bun)
15
+ const isBunRuntime = typeof globalThis.Bun !== "undefined";
16
+ /**
17
+ * Get the global app server instance for SSR direct calls.
18
+ * This allows hooks to access the server without HTTP.
19
+ */
20
+ export function getDevServer() {
21
+ return globalThis.__donkeylabs_dev_server__;
22
+ }
23
+ function setDevServer(server) {
24
+ globalThis.__donkeylabs_dev_server__ = server;
25
+ }
26
+ /**
27
+ * Vite plugin that integrates @donkeylabs/server with the dev server.
28
+ *
29
+ * - With `bun --bun run dev`: Runs in-process (single port, recommended)
30
+ * - With `bun run dev`: Spawns subprocess (two ports, fallback)
31
+ *
32
+ * @example
33
+ * // vite.config.ts
34
+ * import { donkeylabsDev } from "@donkeylabs/adapter-sveltekit/vite";
35
+ *
36
+ * export default defineConfig({
37
+ * plugins: [
38
+ * donkeylabsDev({ serverEntry: "./src/server/index.ts" }),
39
+ * sveltekit()
40
+ * ]
41
+ * });
42
+ */
43
+ export function donkeylabsDev(options = {}) {
44
+ const { serverEntry = "./src/server/index.ts", backendPort = 3001, watchTypes = true, watchDir = "./src/server", hotReloadRoutes = true, routePatterns = ["**/routes/**/*.ts", "**/routes/**/*.js"], } = options;
45
+ // State for subprocess mode
46
+ let backendProcess = null;
47
+ let backendReady = false;
48
+ // State for in-process mode
49
+ let appServer = null;
50
+ let serverReady = false;
51
+ let viteServer = null;
52
+ // State for file watcher
53
+ let fileWatcher = null;
54
+ let isGenerating = false;
55
+ let lastGenerationTime = 0;
56
+ let debounceTimer = null;
57
+ // State for hot reload
58
+ let hotReloadTimer = null;
59
+ const HOT_RELOAD_DEBOUNCE_MS = 100;
60
+ const COOLDOWN_MS = 2000;
61
+ const DEBOUNCE_MS = 500;
62
+ // Patterns to ignore (generated files)
63
+ const IGNORED_PATTERNS = [/schema\.ts$/, /\.d\.ts$/, /api\.ts$/];
64
+ // Check if a file matches route patterns
65
+ function isRouteFile(filename) {
66
+ return routePatterns.some((pattern) => {
67
+ // Simple glob matching for common patterns
68
+ const regexPattern = pattern
69
+ .replace(/\*\*/g, ".*")
70
+ .replace(/\*/g, "[^/]*")
71
+ .replace(/\./g, "\\.");
72
+ return new RegExp(regexPattern).test(filename);
73
+ });
74
+ }
75
+ // Hot reload a route file
76
+ async function hotReloadRoute(filepath) {
77
+ if (!appServer || !serverReady || !viteServer || !hotReloadRoutes)
78
+ return;
79
+ console.log("\x1b[36m[donkeylabs-dev]\x1b[0m Hot reloading route:", filepath);
80
+ try {
81
+ // Invalidate the module in Vite's cache
82
+ const mod = viteServer.moduleGraph.getModuleById(filepath);
83
+ if (mod) {
84
+ viteServer.moduleGraph.invalidateModule(mod);
85
+ }
86
+ // Re-import the module with cache busting
87
+ const timestamp = Date.now();
88
+ const moduleUrl = `${filepath}?t=${timestamp}`;
89
+ // Import the fresh module
90
+ const freshModule = await viteServer.ssrLoadModule(moduleUrl);
91
+ // Find the router export (could be named 'router', 'default', or end with 'Router')
92
+ let newRouter = freshModule.router || freshModule.default;
93
+ if (!newRouter) {
94
+ for (const key of Object.keys(freshModule)) {
95
+ if (key.endsWith("Router") && typeof freshModule[key]?.getRoutes === "function") {
96
+ newRouter = freshModule[key];
97
+ break;
98
+ }
99
+ }
100
+ }
101
+ if (newRouter && typeof newRouter.getRoutes === "function") {
102
+ // Get the router prefix
103
+ const prefix = newRouter.getPrefix?.() || "";
104
+ if (prefix) {
105
+ appServer.reloadRouter(prefix, newRouter);
106
+ console.log("\x1b[32m[donkeylabs-dev]\x1b[0m Route hot reload complete:", prefix);
107
+ }
108
+ else {
109
+ // If no prefix, rebuild all routes
110
+ appServer.rebuildRouteMap();
111
+ console.log("\x1b[32m[donkeylabs-dev]\x1b[0m Route map rebuilt");
112
+ }
113
+ }
114
+ else {
115
+ console.warn("\x1b[33m[donkeylabs-dev]\x1b[0m No router export found in:", filepath);
116
+ }
117
+ }
118
+ catch (err) {
119
+ console.error("\x1b[31m[donkeylabs-dev]\x1b[0m Hot reload error:", err.message);
120
+ }
121
+ }
122
+ function debouncedHotReload(filepath) {
123
+ if (hotReloadTimer)
124
+ clearTimeout(hotReloadTimer);
125
+ hotReloadTimer = setTimeout(() => hotReloadRoute(filepath), HOT_RELOAD_DEBOUNCE_MS);
126
+ }
127
+ function shouldIgnoreFile(filename) {
128
+ return IGNORED_PATTERNS.some((pattern) => pattern.test(filename));
129
+ }
130
+ async function regenerateTypes() {
131
+ const now = Date.now();
132
+ if (now - lastGenerationTime < COOLDOWN_MS || isGenerating)
133
+ return;
134
+ isGenerating = true;
135
+ lastGenerationTime = now;
136
+ console.log("\x1b[36m[donkeylabs-dev]\x1b[0m Server files changed, regenerating types...");
137
+ try {
138
+ await execAsync("bun run gen:types");
139
+ console.log("\x1b[32m[donkeylabs-dev]\x1b[0m Types regenerated successfully");
140
+ }
141
+ catch (e) {
142
+ console.error("\x1b[31m[donkeylabs-dev]\x1b[0m Error regenerating types:", e.message);
143
+ }
144
+ finally {
145
+ isGenerating = false;
146
+ lastGenerationTime = Date.now();
147
+ }
148
+ }
149
+ async function ensureTypesGenerated() {
150
+ // Check if the client file exists (common locations)
151
+ const clientPaths = [
152
+ resolve(process.cwd(), "src/lib/api.ts"),
153
+ resolve(process.cwd(), "src/api.ts"),
154
+ ];
155
+ const clientExists = clientPaths.some((p) => existsSync(p));
156
+ if (clientExists)
157
+ return;
158
+ console.log("\x1b[36m[donkeylabs-dev]\x1b[0m Generated client not found, running initial type generation...");
159
+ isGenerating = true;
160
+ try {
161
+ await execAsync("bun run gen:types");
162
+ console.log("\x1b[32m[donkeylabs-dev]\x1b[0m Initial types generated successfully");
163
+ }
164
+ catch (e) {
165
+ console.warn("\x1b[33m[donkeylabs-dev]\x1b[0m Initial type generation failed:", e.message);
166
+ console.warn("\x1b[33m[donkeylabs-dev]\x1b[0m Run 'bun run gen:types' manually to generate types");
167
+ }
168
+ finally {
169
+ isGenerating = false;
170
+ lastGenerationTime = Date.now();
171
+ }
172
+ }
173
+ function debouncedRegenerate() {
174
+ if (debounceTimer)
175
+ clearTimeout(debounceTimer);
176
+ debounceTimer = setTimeout(regenerateTypes, DEBOUNCE_MS);
177
+ }
178
+ function startFileWatcher() {
179
+ if (fileWatcher)
180
+ return;
181
+ if (!watchTypes && !hotReloadRoutes)
182
+ return;
183
+ const watchPath = resolve(process.cwd(), watchDir);
184
+ try {
185
+ fileWatcher = watch(watchPath, { recursive: true }, (_eventType, filename) => {
186
+ if (!filename)
187
+ return;
188
+ if (!filename.endsWith(".ts") && !filename.endsWith(".js"))
189
+ return;
190
+ if (shouldIgnoreFile(filename))
191
+ return;
192
+ const fullPath = join(watchPath, filename);
193
+ // Check if this is a route file for hot reload
194
+ if (hotReloadRoutes && isRouteFile(filename)) {
195
+ debouncedHotReload(fullPath);
196
+ }
197
+ // Also trigger type regeneration
198
+ if (watchTypes) {
199
+ debouncedRegenerate();
200
+ }
201
+ });
202
+ const features = [
203
+ watchTypes ? "type generation" : null,
204
+ hotReloadRoutes ? "hot reload" : null,
205
+ ].filter(Boolean).join(", ");
206
+ console.log(`\x1b[36m[donkeylabs-dev]\x1b[0m Watching ${watchDir} for ${features}...`);
207
+ }
208
+ catch (err) {
209
+ console.warn(`\x1b[33m[donkeylabs-dev]\x1b[0m Could not watch ${watchDir}:`, err);
210
+ }
211
+ }
212
+ function stopFileWatcher() {
213
+ if (debounceTimer)
214
+ clearTimeout(debounceTimer);
215
+ if (hotReloadTimer)
216
+ clearTimeout(hotReloadTimer);
217
+ if (fileWatcher) {
218
+ fileWatcher.close();
219
+ fileWatcher = null;
220
+ }
221
+ }
222
+ return {
223
+ name: "donkeylabs-dev",
224
+ enforce: "pre",
225
+ // Read PORT env variable and configure Vite's server port
226
+ config(config) {
227
+ const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : undefined;
228
+ if (envPort && !isNaN(envPort)) {
229
+ console.log(`[donkeylabs-dev] Using PORT=${envPort} from environment`);
230
+ return {
231
+ server: {
232
+ ...config.server,
233
+ port: envPort,
234
+ },
235
+ };
236
+ }
237
+ },
238
+ async configureServer(server) {
239
+ const serverEntryResolved = resolve(process.cwd(), serverEntry);
240
+ // Store vite server reference for hot reload
241
+ viteServer = server;
242
+ // Ensure types are generated on first start (if client file doesn't exist)
243
+ await ensureTypesGenerated();
244
+ // Start file watcher for auto type regeneration and hot reload
245
+ startFileWatcher();
246
+ if (isBunRuntime) {
247
+ // ========== IN-PROCESS MODE (bun --bun run dev) ==========
248
+ // Import and initialize server directly - no subprocess, no proxy
249
+ console.log("[donkeylabs-dev] Starting in-process mode (Bun runtime detected)");
250
+ // Log the actual URL once Vite's server starts listening
251
+ server.httpServer?.on("listening", () => {
252
+ const address = server.httpServer?.address();
253
+ if (address && typeof address === "object") {
254
+ const host = address.address === "::" || address.address === "0.0.0.0" ? "localhost" : address.address;
255
+ console.log(`[donkeylabs-dev] Ready at http://${host}:${address.port}`);
256
+ }
257
+ });
258
+ try {
259
+ const serverModule = await import(/* @vite-ignore */ serverEntryResolved);
260
+ appServer = serverModule.server || serverModule.default;
261
+ if (!appServer) {
262
+ throw new Error("No server export found in " + serverEntry);
263
+ }
264
+ // Initialize without starting HTTP server
265
+ await appServer.initialize();
266
+ serverReady = true;
267
+ // Set global reference for SSR direct calls (uses globalThis for cross-module sharing)
268
+ setDevServer(appServer);
269
+ console.log("[donkeylabs-dev] Server initialized (in-process mode)");
270
+ }
271
+ catch (err) {
272
+ console.error("[donkeylabs-dev] Failed to initialize server:", err);
273
+ throw err;
274
+ }
275
+ // Return middleware setup function
276
+ return () => {
277
+ // In-process request handler
278
+ const inProcessMiddleware = async (req, res, next) => {
279
+ const url = req.url || "/";
280
+ const urlObj = new URL(url, "http://localhost");
281
+ const pathname = urlObj.pathname;
282
+ // Handle SSE endpoint
283
+ if (req.method === "GET" && pathname === "/sse") {
284
+ if (!serverReady || !appServer)
285
+ return next();
286
+ const channels = urlObj.searchParams.get("channels")?.split(",").filter(Boolean) || [];
287
+ const lastEventId = req.headers["last-event-id"] || undefined;
288
+ const { client, response } = appServer.getCore().sse.addClient({ lastEventId });
289
+ for (const channel of channels) {
290
+ appServer.getCore().sse.subscribe(client.id, channel);
291
+ }
292
+ // Set SSE headers
293
+ res.writeHead(200, {
294
+ "Content-Type": "text/event-stream",
295
+ "Cache-Control": "no-cache",
296
+ "Connection": "keep-alive",
297
+ "Access-Control-Allow-Origin": "*",
298
+ });
299
+ // Stream SSE data
300
+ const reader = response.body?.getReader();
301
+ let sseClosed = false;
302
+ req.on("close", () => {
303
+ sseClosed = true;
304
+ reader?.cancel().catch(() => { });
305
+ appServer.getCore().sse.removeClient(client.id);
306
+ });
307
+ if (reader) {
308
+ const pump = async () => {
309
+ try {
310
+ while (!sseClosed) {
311
+ const { done, value } = await reader.read();
312
+ if (done || sseClosed)
313
+ break;
314
+ res.write(value);
315
+ }
316
+ }
317
+ catch {
318
+ // Connection closed
319
+ }
320
+ };
321
+ pump();
322
+ }
323
+ return; // Don't call next()
324
+ }
325
+ // Handle API routes (GET or POST for route names like /routeName.action)
326
+ if ((req.method === "GET" || req.method === "POST") && /^\/[a-zA-Z][a-zA-Z0-9_.]*$/.test(pathname)) {
327
+ if (!serverReady || !appServer)
328
+ return next();
329
+ const routeName = pathname.slice(1);
330
+ if (!appServer.hasRoute(routeName))
331
+ return next();
332
+ // Build a proper Request object to pass to handleRequest
333
+ const buildRequest = async () => {
334
+ const fullUrl = `http://localhost${url}`;
335
+ const headers = new Headers();
336
+ for (const [key, value] of Object.entries(req.headers)) {
337
+ if (typeof value === "string") {
338
+ headers.set(key, value);
339
+ }
340
+ else if (Array.isArray(value)) {
341
+ for (const v of value)
342
+ headers.append(key, v);
343
+ }
344
+ }
345
+ if (req.method === "POST") {
346
+ // Collect body for POST
347
+ const chunks = [];
348
+ for await (const chunk of req) {
349
+ chunks.push(chunk);
350
+ }
351
+ const body = Buffer.concat(chunks);
352
+ return new Request(fullUrl, {
353
+ method: "POST",
354
+ headers,
355
+ body,
356
+ });
357
+ }
358
+ return new Request(fullUrl, { method: "GET", headers });
359
+ };
360
+ try {
361
+ const request = await buildRequest();
362
+ const ip = req.socket?.remoteAddress || "127.0.0.1";
363
+ // Use handleRequest which properly handles all handler types (typed, raw, stream, sse, html)
364
+ const response = await appServer.handleRequest(request, routeName, ip, { corsHeaders: { "Access-Control-Allow-Origin": "*" } });
365
+ if (!response) {
366
+ return next();
367
+ }
368
+ // Stream the response back
369
+ res.statusCode = response.status;
370
+ for (const [key, value] of response.headers) {
371
+ res.setHeader(key, value);
372
+ }
373
+ // Flush headers immediately for streaming responses
374
+ if (typeof res.flushHeaders === "function") {
375
+ res.flushHeaders();
376
+ }
377
+ // Handle body streaming (non-blocking for continuous streams like MJPEG)
378
+ if (response.body) {
379
+ const reader = response.body.getReader();
380
+ let closed = false;
381
+ // Handle client disconnect
382
+ req.on("close", () => {
383
+ closed = true;
384
+ reader.cancel().catch(() => { });
385
+ });
386
+ // Pump without awaiting - allows continuous streams
387
+ const pump = async () => {
388
+ try {
389
+ while (!closed) {
390
+ const { done, value } = await reader.read();
391
+ if (done || closed) {
392
+ if (!closed)
393
+ res.end();
394
+ break;
395
+ }
396
+ // Write and check if client is still connected
397
+ const canContinue = res.write(value);
398
+ if (!canContinue && !closed) {
399
+ // Backpressure - wait for drain
400
+ await new Promise(resolve => res.once("drain", resolve));
401
+ }
402
+ }
403
+ }
404
+ catch {
405
+ if (!closed)
406
+ res.end();
407
+ }
408
+ };
409
+ pump(); // Don't await - let it run in background
410
+ }
411
+ else {
412
+ res.end();
413
+ }
414
+ }
415
+ catch (err) {
416
+ console.error("[donkeylabs-dev] Request error:", err);
417
+ res.statusCode = err.status || 500;
418
+ res.setHeader("Content-Type", "application/json");
419
+ res.end(JSON.stringify({ error: err.message || "Internal error" }));
420
+ }
421
+ return; // Don't call next()
422
+ }
423
+ next();
424
+ };
425
+ // CORS preflight
426
+ const corsMiddleware = (req, res, next) => {
427
+ if (req.method === "OPTIONS") {
428
+ res.setHeader("Access-Control-Allow-Origin", "*");
429
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
430
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
431
+ res.statusCode = 204;
432
+ res.end();
433
+ return;
434
+ }
435
+ next();
436
+ };
437
+ // Add to front of middleware stack
438
+ const stack = server.middlewares.stack;
439
+ if (stack && Array.isArray(stack)) {
440
+ stack.unshift({ route: "", handle: corsMiddleware });
441
+ stack.unshift({ route: "", handle: inProcessMiddleware });
442
+ }
443
+ else {
444
+ server.middlewares.use(inProcessMiddleware);
445
+ server.middlewares.use(corsMiddleware);
446
+ }
447
+ };
448
+ }
449
+ else {
450
+ // ========== SUBPROCESS MODE (bun run dev) ==========
451
+ // Spawn backend as separate process and proxy requests
452
+ console.log(`[donkeylabs-dev] Starting subprocess mode (backend on port ${backendPort})`);
453
+ const bootstrapCode = `
454
+ const serverModule = await import("${serverEntryResolved}");
455
+ const server = serverModule.server || serverModule.default;
456
+
457
+ if (!server) {
458
+ console.error("[donkeylabs-backend] No server export found");
459
+ process.exit(1);
460
+ }
461
+
462
+ server.port = ${backendPort};
463
+ await server.start();
464
+ console.log("[donkeylabs-backend] Server ready on port ${backendPort}");
465
+ `;
466
+ backendProcess = spawn("bun", ["--eval", bootstrapCode], {
467
+ stdio: ["pipe", "pipe", "pipe"],
468
+ env: { ...process.env, NODE_ENV: "development" },
469
+ });
470
+ backendProcess.stdout?.on("data", (data) => {
471
+ const msg = data.toString().trim();
472
+ if (msg) {
473
+ console.log(msg);
474
+ if (msg.includes("Server ready") || msg.includes("Server running")) {
475
+ backendReady = true;
476
+ }
477
+ }
478
+ });
479
+ backendProcess.stderr?.on("data", (data) => {
480
+ const msg = data.toString().trim();
481
+ if (msg)
482
+ console.error(msg);
483
+ });
484
+ backendProcess.on("error", (err) => {
485
+ console.error("[donkeylabs-dev] Failed to start backend:", err);
486
+ });
487
+ backendProcess.on("exit", (code) => {
488
+ if (code !== 0 && code !== null) {
489
+ console.error(`[donkeylabs-dev] Backend exited with code ${code}`);
490
+ }
491
+ backendProcess = null;
492
+ backendReady = false;
493
+ });
494
+ server.httpServer?.on("close", () => {
495
+ if (backendProcess) {
496
+ backendProcess.kill();
497
+ backendProcess = null;
498
+ }
499
+ });
500
+ // Return middleware setup function
501
+ return () => {
502
+ const waitForBackend = new Promise((resolve) => {
503
+ const check = () => (backendReady ? resolve() : setTimeout(check, 100));
504
+ setTimeout(check, 500);
505
+ setTimeout(() => {
506
+ if (!backendReady) {
507
+ console.warn("[donkeylabs-dev] Backend startup timeout");
508
+ resolve();
509
+ }
510
+ }, 10000);
511
+ });
512
+ // Proxy middleware - handles GET and POST for API routes
513
+ const proxyMiddleware = (req, res, next) => {
514
+ const url = req.url || "/";
515
+ const urlObj = new URL(url, "http://localhost");
516
+ const pathname = urlObj.pathname;
517
+ // API routes are GET or POST to paths like /routeName.action
518
+ const isApiRoute = (req.method === "GET" || req.method === "POST") && /^\/[a-zA-Z][a-zA-Z0-9_.]*$/.test(pathname);
519
+ if (!isApiRoute)
520
+ return next();
521
+ waitForBackend.then(() => {
522
+ let proxyAborted = false;
523
+ const proxyReq = http.request({
524
+ hostname: "localhost",
525
+ port: backendPort,
526
+ path: url, // Include query string
527
+ method: req.method,
528
+ headers: { ...req.headers, host: `localhost:${backendPort}` },
529
+ }, (proxyRes) => {
530
+ if (proxyAborted)
531
+ return;
532
+ res.setHeader("Access-Control-Allow-Origin", "*");
533
+ res.statusCode = proxyRes.statusCode || 200;
534
+ for (const [k, v] of Object.entries(proxyRes.headers)) {
535
+ if (v)
536
+ res.setHeader(k, v);
537
+ }
538
+ // Flush headers for streaming responses
539
+ if (typeof res.flushHeaders === "function") {
540
+ res.flushHeaders();
541
+ }
542
+ // Stream response back (works for binary/streaming responses)
543
+ proxyRes.pipe(res);
544
+ // Clean up on proxy response end
545
+ proxyRes.on("end", () => {
546
+ if (!proxyAborted)
547
+ res.end();
548
+ });
549
+ });
550
+ // Handle client disconnect - abort proxy request
551
+ req.on("close", () => {
552
+ if (!proxyAborted) {
553
+ proxyAborted = true;
554
+ proxyReq.destroy();
555
+ }
556
+ });
557
+ proxyReq.on("error", (err) => {
558
+ if (proxyAborted)
559
+ return; // Ignore errors after abort
560
+ console.error(`[donkeylabs-dev] Proxy error:`, err.message);
561
+ res.statusCode = 502;
562
+ res.end(JSON.stringify({ error: "Backend unavailable" }));
563
+ });
564
+ // For POST, pipe the body; for GET, just end
565
+ if (req.method === "POST") {
566
+ req.pipe(proxyReq);
567
+ }
568
+ else {
569
+ proxyReq.end();
570
+ }
571
+ });
572
+ };
573
+ const corsMiddleware = (req, res, next) => {
574
+ if (req.method === "OPTIONS") {
575
+ res.setHeader("Access-Control-Allow-Origin", "*");
576
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
577
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
578
+ res.statusCode = 204;
579
+ res.end();
580
+ return;
581
+ }
582
+ next();
583
+ };
584
+ const stack = server.middlewares.stack;
585
+ if (stack && Array.isArray(stack)) {
586
+ stack.unshift({ route: "", handle: corsMiddleware });
587
+ stack.unshift({ route: "", handle: proxyMiddleware });
588
+ }
589
+ else {
590
+ server.middlewares.use(proxyMiddleware);
591
+ server.middlewares.use(corsMiddleware);
592
+ }
593
+ };
594
+ }
595
+ },
596
+ async closeBundle() {
597
+ stopFileWatcher();
598
+ viteServer = null;
599
+ if (backendProcess) {
600
+ backendProcess.kill();
601
+ backendProcess = null;
602
+ }
603
+ if (appServer) {
604
+ await appServer.shutdown?.();
605
+ appServer = null;
606
+ setDevServer(null);
607
+ }
608
+ },
609
+ };
610
+ }
611
+ export default donkeylabsDev;
package/package.json CHANGED
@@ -1,38 +1,40 @@
1
1
  {
2
2
  "name": "@donkeylabs/adapter-sveltekit",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "type": "module",
5
5
  "description": "SvelteKit adapter for @donkeylabs/server - seamless SSR/browser API integration",
6
- "main": "./src/index.ts",
7
- "types": "./src/index.ts",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./src/index.ts",
11
- "import": "./src/index.ts"
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
12
  },
13
13
  "./client": {
14
- "types": "./src/client/index.ts",
15
- "import": "./src/client/index.ts"
14
+ "types": "./dist/client/index.d.ts",
15
+ "import": "./dist/client/index.js"
16
16
  },
17
17
  "./hooks": {
18
- "types": "./src/hooks/index.ts",
19
- "import": "./src/hooks/index.ts"
18
+ "types": "./dist/hooks/index.d.ts",
19
+ "import": "./dist/hooks/index.js"
20
20
  },
21
21
  "./generator": {
22
- "types": "./src/generator/index.ts",
23
- "import": "./src/generator/index.ts"
22
+ "types": "./dist/generator/index.d.ts",
23
+ "import": "./dist/generator/index.js"
24
24
  },
25
25
  "./vite": {
26
- "types": "./src/vite.ts",
27
- "import": "./src/vite.ts"
26
+ "types": "./dist/vite.d.ts",
27
+ "import": "./dist/vite.js"
28
28
  }
29
29
  },
30
30
  "files": [
31
- "src",
31
+ "dist",
32
32
  "LICENSE",
33
33
  "README.md"
34
34
  ],
35
35
  "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "prepublishOnly": "npm run build",
36
38
  "typecheck": "bun --bun tsc --noEmit"
37
39
  },
38
40
  "peerDependencies": {