@b9g/platform-bun 0.1.10 → 0.1.11

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.
Files changed (3) hide show
  1. package/package.json +6 -7
  2. package/src/index.d.ts +49 -13
  3. package/src/index.js +265 -66
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/platform-bun",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Bun platform adapter for Shovel with hot reloading and built-in TypeScript/JSX support",
5
5
  "keywords": [
6
6
  "shovel",
@@ -12,15 +12,14 @@
12
12
  "jsx"
13
13
  ],
14
14
  "dependencies": {
15
- "@b9g/assets": "^0.1.15",
16
- "@b9g/cache": "^0.1.5",
17
- "@b9g/http-errors": "^0.1.5",
18
- "@b9g/platform": "^0.1.12",
15
+ "@b9g/assets": "^0.2.0-beta.0",
16
+ "@b9g/cache": "^0.2.0-beta.0",
17
+ "@b9g/http-errors": "^0.2.0-beta.0",
18
+ "@b9g/platform": "^0.1.13",
19
19
  "@logtape/logtape": "^1.2.0"
20
20
  },
21
21
  "devDependencies": {
22
- "@b9g/libuild": "^0.1.18",
23
- "bun-types": "latest"
22
+ "@b9g/libuild": "^0.1.18"
24
23
  },
25
24
  "type": "module",
26
25
  "types": "src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Provides built-in TypeScript/JSX support and simplified server setup for Bun environments.
5
5
  */
6
- import { BasePlatform, type PlatformConfig, type Handler, type Server, type ServerOptions, type ServiceWorkerOptions, type ServiceWorkerInstance, type EntryWrapperOptions, type PlatformEsbuildConfig, ServiceWorkerPool } from "@b9g/platform";
6
+ import { BasePlatform, type PlatformConfig, type PlatformDefaults, type Handler, type Server, type ServerOptions, type ServiceWorkerOptions, type ServiceWorkerInstance, type EntryWrapperOptions, type PlatformESBuildConfig, ServiceWorkerPool, CustomLoggerStorage, CustomDatabaseStorage } from "@b9g/platform";
7
+ import { type ShovelConfig } from "@b9g/platform/runtime";
7
8
  import { CustomCacheStorage } from "@b9g/cache";
8
9
  import { CustomDirectoryStorage } from "@b9g/filesystem";
9
10
  export interface BunPlatformOptions extends PlatformConfig {
@@ -15,6 +16,8 @@ export interface BunPlatformOptions extends PlatformConfig {
15
16
  cwd?: string;
16
17
  /** Number of worker threads (default: 1) */
17
18
  workers?: number;
19
+ /** Shovel configuration (caches, directories, etc.) */
20
+ config?: ShovelConfig;
18
21
  }
19
22
  /**
20
23
  * Bun platform implementation
@@ -27,20 +30,36 @@ export declare class BunPlatform extends BasePlatform {
27
30
  /**
28
31
  * Get options for testing
29
32
  */
30
- get options(): Required<BunPlatformOptions>;
33
+ get options(): {
34
+ port: number;
35
+ host: string;
36
+ cwd: string;
37
+ workers: number;
38
+ config?: ShovelConfig;
39
+ };
31
40
  /**
32
41
  * Get/set worker pool for testing
33
42
  */
34
43
  get workerPool(): ServiceWorkerPool | undefined;
35
44
  set workerPool(pool: ServiceWorkerPool | undefined);
36
45
  /**
37
- * Create cache storage (in-memory by default)
46
+ * Create cache storage using config from shovel.json
47
+ * Merges with runtime defaults (actual class references) for fallback behavior
38
48
  */
39
49
  createCaches(): Promise<CustomCacheStorage>;
40
50
  /**
41
- * Create directory storage for the given base directory
51
+ * Create directory storage using config from shovel.json
52
+ * Merges with runtime defaults (actual class references) for fallback behavior
42
53
  */
43
- createDirectories(baseDir: string): CustomDirectoryStorage;
54
+ createDirectories(): Promise<CustomDirectoryStorage>;
55
+ /**
56
+ * Create logger storage using config from shovel.json
57
+ */
58
+ createLoggers(): Promise<CustomLoggerStorage>;
59
+ /**
60
+ * Create database storage from declarative config in shovel.json
61
+ */
62
+ createDatabases(configOverride?: BunPlatformOptions["config"]): CustomDatabaseStorage | undefined;
44
63
  /**
45
64
  * Create HTTP server using Bun.serve
46
65
  */
@@ -58,28 +77,45 @@ export declare class BunPlatform extends BasePlatform {
58
77
  /**
59
78
  * Get virtual entry wrapper for Bun
60
79
  *
61
- * Returns production server entry template that uses:
62
- * - shovel:config virtual module for configuration
63
- * - Bun.serve with reusePort for multi-worker scaling
64
- * - Direct import of user's server code
80
+ * @param entryPath - Absolute path to user's entrypoint file
81
+ * @param options - Entry wrapper options
82
+ * @param options.type - "production" (default) or "worker"
83
+ * @param options.outDir - Output directory (required for "worker" type)
65
84
  *
66
- * The template is a real .ts file (entry-template.ts) for better
67
- * IDE support and linting. It's imported with {type: "text"}.
85
+ * Returns:
86
+ * - "production": Server entry with Bun.serve and reusePort
87
+ * - "worker": Worker entry that sets up runtime and message loop
68
88
  */
69
- getEntryWrapper(_entryPath: string, _options?: EntryWrapperOptions): string;
89
+ getEntryWrapper(entryPath: string, options?: EntryWrapperOptions): string;
70
90
  /**
71
91
  * Get Bun-specific esbuild configuration
72
92
  *
73
93
  * Note: Bun natively supports import.meta.env, so no define alias is needed.
74
94
  * We use platform: "node" since Bun is Node-compatible for module resolution.
75
95
  */
76
- getEsbuildConfig(): PlatformEsbuildConfig;
96
+ getESBuildConfig(): PlatformESBuildConfig;
97
+ /**
98
+ * Get Bun-specific defaults for config generation
99
+ *
100
+ * Provides default directories (server, public, tmp) that work
101
+ * out of the box for Bun deployments.
102
+ */
103
+ getDefaults(): PlatformDefaults;
77
104
  /**
78
105
  * Dispose of platform resources
79
106
  */
80
107
  dispose(): Promise<void>;
108
+ /**
109
+ * Get the OS temp directory (Bun-specific implementation using node:os)
110
+ */
111
+ tmpdir(): string;
81
112
  }
82
113
  /**
83
114
  * Default export for easy importing
84
115
  */
85
116
  export default BunPlatform;
117
+ /**
118
+ * Platform's default cache implementation.
119
+ * Re-exported so config can reference: { module: "@b9g/platform-bun", export: "DefaultCache" }
120
+ */
121
+ export { MemoryCache as DefaultCache } from "@b9g/cache/memory";
package/src/index.js CHANGED
@@ -1,19 +1,29 @@
1
1
  /// <reference types="./index.d.ts" />
2
2
  // src/index.ts
3
+ import { builtinModules } from "node:module";
4
+ import { tmpdir } from "node:os";
3
5
  import {
4
6
  BasePlatform,
5
7
  ServiceWorkerPool,
6
8
  SingleThreadedRuntime,
7
- CustomLoggerStorage
9
+ CustomLoggerStorage,
10
+ CustomDatabaseStorage,
11
+ createDatabaseFactory
8
12
  } from "@b9g/platform";
13
+ import {
14
+ createCacheFactory,
15
+ createDirectoryFactory
16
+ } from "@b9g/platform/runtime";
9
17
  import { CustomCacheStorage } from "@b9g/cache";
10
- import { CustomDirectoryStorage } from "@b9g/filesystem";
11
18
  import { MemoryCache } from "@b9g/cache/memory";
12
- import { NodeDirectory } from "@b9g/filesystem/node";
19
+ import { CustomDirectoryStorage } from "@b9g/filesystem";
20
+ import { NodeFSDirectory } from "@b9g/filesystem/node-fs";
13
21
  import { InternalServerError, isHTTPError } from "@b9g/http-errors";
14
22
  import { getLogger } from "@logtape/logtape";
15
23
  import * as Path from "path";
24
+ import { MemoryCache as MemoryCache2 } from "@b9g/cache/memory";
16
25
  var entryTemplate = `// Bun Production Server Entry
26
+ import {tmpdir} from "os"; // For [tmpdir] config expressions
17
27
  import {getLogger} from "@logtape/logtape";
18
28
  import {configureLogging} from "@b9g/platform/runtime";
19
29
  import {config} from "shovel:config"; // Virtual module - resolved at build time
@@ -22,16 +32,19 @@ import BunPlatform from "@b9g/platform-bun";
22
32
  // Configure logging before anything else
23
33
  await configureLogging(config.logging);
24
34
 
25
- const logger = getLogger(["platform"]);
35
+ const logger = getLogger(["shovel", "platform"]);
26
36
 
27
37
  // Configuration from shovel:config
28
38
  const PORT = config.port;
29
39
  const HOST = config.host;
30
40
  const WORKERS = config.workers;
31
- const isWorker = !Bun.isMainThread;
32
41
 
33
- // Worker thread entry - each worker runs its own Bun.serve with reusePort
34
- if (isWorker) {
42
+ // Use explicit marker instead of Bun.isMainThread
43
+ // This handles the edge case where Shovel's build output is embedded in another worker
44
+ const isShovelWorker = process.env.SHOVEL_SPAWNED_WORKER === "1";
45
+
46
+ if (isShovelWorker) {
47
+ // Worker thread: runs BOTH server AND ServiceWorker
35
48
  const platform = new BunPlatform({port: PORT, host: HOST, workers: 1});
36
49
  const userCodePath = new URL("./server.js", import.meta.url).pathname;
37
50
  const serviceWorker = await platform.loadServiceWorker(userCodePath);
@@ -39,47 +52,105 @@ if (isWorker) {
39
52
  Bun.serve({
40
53
  port: PORT,
41
54
  hostname: HOST,
42
- reusePort: true,
55
+ // Only need reusePort for multi-worker (multiple listeners on same port)
56
+ reusePort: WORKERS > 1,
43
57
  fetch: serviceWorker.handleRequest,
44
58
  });
45
59
 
60
+ // Signal ready to main thread
61
+ postMessage({type: "ready", thread: Bun.threadId});
46
62
  logger.info("Worker started", {port: PORT, thread: Bun.threadId});
47
63
  } else {
48
- // Main thread - spawn worker threads, each binds to same port with reusePort
49
- if (WORKERS > 1) {
50
- for (let i = 0; i < WORKERS; i++) {
51
- new Worker(import.meta.path);
64
+ // Main thread: supervisor only - ALWAYS spawn workers (even for workers:1)
65
+ // This ensures ServiceWorker code always runs in a worker thread for dev/prod parity
66
+
67
+ // Port availability check - fail fast if port is in use
68
+ // Prevents accidental port sharing with other processes
69
+ const checkPort = async () => {
70
+ try {
71
+ const testServer = Bun.serve({port: PORT, hostname: HOST, fetch: () => new Response()});
72
+ testServer.stop();
73
+ } catch (err) {
74
+ logger.error("Port unavailable", {port: PORT, host: HOST, error: err});
75
+ process.exit(1);
52
76
  }
53
- logger.info("Spawned workers", {count: WORKERS, port: PORT});
54
- } else {
55
- // Single worker mode - run directly in main thread
56
- const platform = new BunPlatform({port: PORT, host: HOST, workers: 1});
57
- const userCodePath = new URL("./server.js", import.meta.url).pathname;
58
- const serviceWorker = await platform.loadServiceWorker(userCodePath);
77
+ };
78
+ await checkPort();
79
+
80
+ let shuttingDown = false;
81
+ const workers = [];
82
+ let readyCount = 0;
59
83
 
60
- const server = platform.createServer(serviceWorker.handleRequest, {
61
- port: PORT,
62
- host: HOST,
84
+ for (let i = 0; i < WORKERS; i++) {
85
+ const worker = new Worker(import.meta.path, {
86
+ env: {...process.env, SHOVEL_SPAWNED_WORKER: "1"},
63
87
  });
64
- await server.listen();
65
88
 
66
- logger.info("Server started", {url: server.url});
89
+ worker.onmessage = (event) => {
90
+ if (event.data.type === "ready") {
91
+ readyCount++;
92
+ if (readyCount === WORKERS) {
93
+ logger.info("All workers ready", {count: WORKERS, port: PORT});
94
+ }
95
+ }
96
+ };
67
97
 
68
- // Graceful shutdown
69
- const shutdown = async () => {
70
- logger.info("Shutting down");
71
- await serviceWorker.dispose();
72
- await platform.dispose();
73
- await server.close();
74
- process.exit(0);
98
+ worker.onerror = (error) => {
99
+ logger.error("Worker error", {error: error.message});
75
100
  };
76
101
 
77
- process.on("SIGINT", shutdown);
78
- process.on("SIGTERM", shutdown);
102
+ // If a worker crashes, fail fast - let process supervisor handle restarts
103
+ worker.addEventListener("close", () => {
104
+ if (shuttingDown) return;
105
+ logger.error("Worker crashed, exiting");
106
+ process.exit(1);
107
+ });
108
+
109
+ workers.push(worker);
79
110
  }
111
+
112
+ logger.info("Spawned workers", {count: WORKERS, port: PORT});
113
+
114
+ // Graceful shutdown
115
+ const shutdown = async () => {
116
+ shuttingDown = true;
117
+ logger.info("Shutting down workers");
118
+ for (const worker of workers) {
119
+ worker.terminate();
120
+ }
121
+ process.exit(0);
122
+ };
123
+
124
+ process.on("SIGINT", shutdown);
125
+ process.on("SIGTERM", shutdown);
80
126
  }
81
127
  `;
82
- var logger = getLogger(["platform"]);
128
+ var workerEntryTemplate = `// Worker Entry for ServiceWorkerPool
129
+ // This file sets up the ServiceWorker runtime and message loop
130
+ import {tmpdir} from "os"; // For [tmpdir] config expressions
131
+ import {config} from "shovel:config";
132
+ import {initWorkerRuntime, startWorkerMessageLoop, configureLogging} from "@b9g/platform/runtime";
133
+
134
+ // Configure logging before anything else
135
+ await configureLogging(config.logging);
136
+
137
+ // Initialize the worker runtime (installs ServiceWorker globals)
138
+ // Platform defaults and paths are already resolved at build time
139
+ const {registration, databases} = await initWorkerRuntime({config});
140
+
141
+ // Import user code (registers event handlers via addEventListener)
142
+ // Must use dynamic import to ensure globals are installed first
143
+ await import("__USER_ENTRY__");
144
+
145
+ // Run ServiceWorker lifecycle
146
+ await registration.install();
147
+ await registration.activate();
148
+
149
+ // Start the message loop (handles request/response messages from main thread)
150
+ // Pass databases so they can be closed on graceful shutdown
151
+ startWorkerMessageLoop({registration, databases});
152
+ `;
153
+ var logger = getLogger(["shovel", "platform"]);
83
154
  var BunPlatform = class extends BasePlatform {
84
155
  name;
85
156
  #options;
@@ -87,6 +158,7 @@ var BunPlatform = class extends BasePlatform {
87
158
  #singleThreadedRuntime;
88
159
  #cacheStorage;
89
160
  #directoryStorage;
161
+ #databaseStorage;
90
162
  constructor(options = {}) {
91
163
  super(options);
92
164
  this.name = "bun";
@@ -96,7 +168,7 @@ var BunPlatform = class extends BasePlatform {
96
168
  host: options.host ?? "localhost",
97
169
  workers: options.workers ?? 1,
98
170
  cwd,
99
- ...options
171
+ config: options.config
100
172
  };
101
173
  }
102
174
  /**
@@ -115,26 +187,61 @@ var BunPlatform = class extends BasePlatform {
115
187
  this.#workerPool = pool;
116
188
  }
117
189
  /**
118
- * Create cache storage (in-memory by default)
190
+ * Create cache storage using config from shovel.json
191
+ * Merges with runtime defaults (actual class references) for fallback behavior
119
192
  */
120
193
  async createCaches() {
121
- return new CustomCacheStorage((name) => new MemoryCache(name));
194
+ const runtimeDefaults = {
195
+ default: { impl: MemoryCache }
196
+ };
197
+ const userCaches = this.#options.config?.caches ?? {};
198
+ const configs = {};
199
+ const allNames = /* @__PURE__ */ new Set([
200
+ ...Object.keys(runtimeDefaults),
201
+ ...Object.keys(userCaches)
202
+ ]);
203
+ for (const name of allNames) {
204
+ configs[name] = { ...runtimeDefaults[name], ...userCaches[name] };
205
+ }
206
+ return new CustomCacheStorage(createCacheFactory({ configs }));
122
207
  }
123
208
  /**
124
- * Create directory storage for the given base directory
209
+ * Create directory storage using config from shovel.json
210
+ * Merges with runtime defaults (actual class references) for fallback behavior
125
211
  */
126
- createDirectories(baseDir) {
127
- return new CustomDirectoryStorage((name) => {
128
- let dirPath;
129
- if (name === "static") {
130
- dirPath = Path.resolve(baseDir, "../static");
131
- } else if (name === "server") {
132
- dirPath = baseDir;
133
- } else {
134
- dirPath = Path.resolve(baseDir, `../${name}`);
135
- }
136
- return Promise.resolve(new NodeDirectory(dirPath));
137
- });
212
+ async createDirectories() {
213
+ const runtimeDefaults = {
214
+ server: { impl: NodeFSDirectory, path: this.#options.cwd },
215
+ public: { impl: NodeFSDirectory, path: this.#options.cwd },
216
+ tmp: { impl: NodeFSDirectory, path: tmpdir() }
217
+ };
218
+ const userDirs = this.#options.config?.directories ?? {};
219
+ const configs = {};
220
+ const allNames = /* @__PURE__ */ new Set([
221
+ ...Object.keys(runtimeDefaults),
222
+ ...Object.keys(userDirs)
223
+ ]);
224
+ for (const name of allNames) {
225
+ configs[name] = { ...runtimeDefaults[name], ...userDirs[name] };
226
+ }
227
+ return new CustomDirectoryStorage(createDirectoryFactory(configs));
228
+ }
229
+ /**
230
+ * Create logger storage using config from shovel.json
231
+ */
232
+ async createLoggers() {
233
+ return new CustomLoggerStorage((categories) => getLogger(categories));
234
+ }
235
+ /**
236
+ * Create database storage from declarative config in shovel.json
237
+ */
238
+ createDatabases(configOverride) {
239
+ const config = configOverride ?? this.#options.config;
240
+ if (config?.databases && Object.keys(config.databases).length > 0) {
241
+ const factory = createDatabaseFactory(config.databases);
242
+ return new CustomDatabaseStorage(factory);
243
+ }
244
+ return void 0;
138
245
  }
139
246
  /**
140
247
  * Create HTTP server using Bun.serve
@@ -193,12 +300,55 @@ var BunPlatform = class extends BasePlatform {
193
300
  */
194
301
  async #loadServiceWorkerDirect(entrypoint, _options) {
195
302
  const entryPath = Path.resolve(this.#options.cwd, entrypoint);
196
- const entryDir = Path.dirname(entryPath);
303
+ let config = this.#options.config;
304
+ const configPath = Path.join(Path.dirname(entryPath), "config.js");
305
+ try {
306
+ const configModule = await import(configPath);
307
+ config = configModule.config ?? config;
308
+ } catch (err) {
309
+ logger.debug`Using platform config (no config.js): ${err}`;
310
+ }
197
311
  if (!this.#cacheStorage) {
198
- this.#cacheStorage = await this.createCaches();
312
+ const runtimeCacheDefaults = {
313
+ default: { impl: MemoryCache }
314
+ };
315
+ const userCaches = config?.caches ?? {};
316
+ const cacheConfigs = {};
317
+ const allCacheNames = /* @__PURE__ */ new Set([
318
+ ...Object.keys(runtimeCacheDefaults),
319
+ ...Object.keys(userCaches)
320
+ ]);
321
+ for (const name of allCacheNames) {
322
+ cacheConfigs[name] = {
323
+ ...runtimeCacheDefaults[name],
324
+ ...userCaches[name]
325
+ };
326
+ }
327
+ this.#cacheStorage = new CustomCacheStorage(
328
+ createCacheFactory({ configs: cacheConfigs })
329
+ );
199
330
  }
200
331
  if (!this.#directoryStorage) {
201
- this.#directoryStorage = this.createDirectories(entryDir);
332
+ const runtimeDirDefaults = {
333
+ server: { impl: NodeFSDirectory },
334
+ public: { impl: NodeFSDirectory },
335
+ tmp: { impl: NodeFSDirectory }
336
+ };
337
+ const userDirs = config?.directories ?? {};
338
+ const dirConfigs = {};
339
+ const allDirNames = /* @__PURE__ */ new Set([
340
+ ...Object.keys(runtimeDirDefaults),
341
+ ...Object.keys(userDirs)
342
+ ]);
343
+ for (const name of allDirNames) {
344
+ dirConfigs[name] = { ...runtimeDirDefaults[name], ...userDirs[name] };
345
+ }
346
+ this.#directoryStorage = new CustomDirectoryStorage(
347
+ createDirectoryFactory(dirConfigs)
348
+ );
349
+ }
350
+ if (!this.#databaseStorage) {
351
+ this.#databaseStorage = this.createDatabases(config);
202
352
  }
203
353
  if (this.#singleThreadedRuntime) {
204
354
  await this.#singleThreadedRuntime.terminate();
@@ -211,7 +361,8 @@ var BunPlatform = class extends BasePlatform {
211
361
  this.#singleThreadedRuntime = new SingleThreadedRuntime({
212
362
  caches: this.#cacheStorage,
213
363
  directories: this.#directoryStorage,
214
- loggers: new CustomLoggerStorage((...cats) => getLogger(cats))
364
+ databases: this.#databaseStorage,
365
+ loggers: new CustomLoggerStorage((cats) => getLogger(cats))
215
366
  });
216
367
  await this.#singleThreadedRuntime.init();
217
368
  await this.#singleThreadedRuntime.load(entryPath);
@@ -271,12 +422,9 @@ var BunPlatform = class extends BasePlatform {
271
422
  this.#workerPool = new ServiceWorkerPool(
272
423
  poolOptions,
273
424
  entryPath,
274
- this.#cacheStorage,
275
- {}
276
- // Empty config - use defaults
425
+ this.#cacheStorage
277
426
  );
278
427
  await this.#workerPool.init();
279
- await this.#workerPool.reloadWorkers(entryPath);
280
428
  const workerPool = this.#workerPool;
281
429
  const platform = this;
282
430
  const instance = {
@@ -323,15 +471,19 @@ var BunPlatform = class extends BasePlatform {
323
471
  /**
324
472
  * Get virtual entry wrapper for Bun
325
473
  *
326
- * Returns production server entry template that uses:
327
- * - shovel:config virtual module for configuration
328
- * - Bun.serve with reusePort for multi-worker scaling
329
- * - Direct import of user's server code
474
+ * @param entryPath - Absolute path to user's entrypoint file
475
+ * @param options - Entry wrapper options
476
+ * @param options.type - "production" (default) or "worker"
477
+ * @param options.outDir - Output directory (required for "worker" type)
330
478
  *
331
- * The template is a real .ts file (entry-template.ts) for better
332
- * IDE support and linting. It's imported with {type: "text"}.
479
+ * Returns:
480
+ * - "production": Server entry with Bun.serve and reusePort
481
+ * - "worker": Worker entry that sets up runtime and message loop
333
482
  */
334
- getEntryWrapper(_entryPath, _options) {
483
+ getEntryWrapper(entryPath, options) {
484
+ if (options?.type === "worker") {
485
+ return workerEntryTemplate.replace("__USER_ENTRY__", entryPath);
486
+ }
335
487
  return entryTemplate;
336
488
  }
337
489
  /**
@@ -340,10 +492,43 @@ var BunPlatform = class extends BasePlatform {
340
492
  * Note: Bun natively supports import.meta.env, so no define alias is needed.
341
493
  * We use platform: "node" since Bun is Node-compatible for module resolution.
342
494
  */
343
- getEsbuildConfig() {
495
+ getESBuildConfig() {
344
496
  return {
345
497
  platform: "node",
346
- external: ["node:*"]
498
+ external: ["node:*", "bun", "bun:*", ...builtinModules]
499
+ };
500
+ }
501
+ /**
502
+ * Get Bun-specific defaults for config generation
503
+ *
504
+ * Provides default directories (server, public, tmp) that work
505
+ * out of the box for Bun deployments.
506
+ */
507
+ getDefaults() {
508
+ return {
509
+ caches: {
510
+ default: {
511
+ module: "@b9g/cache/memory",
512
+ export: "MemoryCache"
513
+ }
514
+ },
515
+ directories: {
516
+ server: {
517
+ module: "@b9g/filesystem/node-fs",
518
+ export: "NodeFSDirectory",
519
+ path: "[outdir]/server"
520
+ },
521
+ public: {
522
+ module: "@b9g/filesystem/node-fs",
523
+ export: "NodeFSDirectory",
524
+ path: "[outdir]/public"
525
+ },
526
+ tmp: {
527
+ module: "@b9g/filesystem/node-fs",
528
+ export: "NodeFSDirectory",
529
+ path: "[tmpdir]"
530
+ }
531
+ }
347
532
  };
348
533
  }
349
534
  /**
@@ -362,10 +547,24 @@ var BunPlatform = class extends BasePlatform {
362
547
  await this.#cacheStorage.dispose();
363
548
  this.#cacheStorage = void 0;
364
549
  }
550
+ if (this.#databaseStorage) {
551
+ await this.#databaseStorage.closeAll();
552
+ this.#databaseStorage = void 0;
553
+ }
554
+ }
555
+ // =========================================================================
556
+ // Config Expression Method Overrides
557
+ // =========================================================================
558
+ /**
559
+ * Get the OS temp directory (Bun-specific implementation using node:os)
560
+ */
561
+ tmpdir() {
562
+ return tmpdir();
365
563
  }
366
564
  };
367
565
  var src_default = BunPlatform;
368
566
  export {
369
567
  BunPlatform,
568
+ MemoryCache2 as DefaultCache,
370
569
  src_default as default
371
570
  };