@b9g/platform-bun 0.1.9 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/platform-bun",
3
- "version": "0.1.9",
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.14",
16
- "@b9g/cache": "^0.1.4",
17
- "@b9g/http-errors": "^0.1.5",
18
- "@b9g/platform": "^0.1.10",
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,9 +3,10 @@
3
3
  *
4
4
  * Provides built-in TypeScript/JSX support and simplified server setup for Bun environments.
5
5
  */
6
- import { BasePlatform, PlatformConfig, Handler, Server, ServerOptions, ServiceWorkerOptions, ServiceWorkerInstance, 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
- export type { Platform, Handler, Server, ServerOptions, ServiceWorkerOptions, ServiceWorkerInstance, } from "@b9g/platform";
9
+ import { CustomDirectoryStorage } from "@b9g/filesystem";
9
10
  export interface BunPlatformOptions extends PlatformConfig {
10
11
  /** Port for development server (default: 3000) */
11
12
  port?: number;
@@ -13,6 +14,10 @@ export interface BunPlatformOptions extends PlatformConfig {
13
14
  host?: string;
14
15
  /** Working directory for file resolution */
15
16
  cwd?: string;
17
+ /** Number of worker threads (default: 1) */
18
+ workers?: number;
19
+ /** Shovel configuration (caches, directories, etc.) */
20
+ config?: ShovelConfig;
16
21
  }
17
22
  /**
18
23
  * Bun platform implementation
@@ -25,17 +30,36 @@ export declare class BunPlatform extends BasePlatform {
25
30
  /**
26
31
  * Get options for testing
27
32
  */
28
- get options(): Required<BunPlatformOptions>;
33
+ get options(): {
34
+ port: number;
35
+ host: string;
36
+ cwd: string;
37
+ workers: number;
38
+ config?: ShovelConfig;
39
+ };
29
40
  /**
30
41
  * Get/set worker pool for testing
31
42
  */
32
43
  get workerPool(): ServiceWorkerPool | undefined;
33
44
  set workerPool(pool: ServiceWorkerPool | undefined);
34
45
  /**
35
- * Create cache storage
36
- * Uses config from package.json shovel field
46
+ * Create cache storage using config from shovel.json
47
+ * Merges with runtime defaults (actual class references) for fallback behavior
37
48
  */
38
49
  createCaches(): Promise<CustomCacheStorage>;
50
+ /**
51
+ * Create directory storage using config from shovel.json
52
+ * Merges with runtime defaults (actual class references) for fallback behavior
53
+ */
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;
39
63
  /**
40
64
  * Create HTTP server using Bun.serve
41
65
  */
@@ -50,12 +74,48 @@ export declare class BunPlatform extends BasePlatform {
50
74
  * @param entrypoint - Path to the new entrypoint (hashed filename)
51
75
  */
52
76
  reloadWorkers(entrypoint: string): Promise<void>;
77
+ /**
78
+ * Get virtual entry wrapper for Bun
79
+ *
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)
84
+ *
85
+ * Returns:
86
+ * - "production": Server entry with Bun.serve and reusePort
87
+ * - "worker": Worker entry that sets up runtime and message loop
88
+ */
89
+ getEntryWrapper(entryPath: string, options?: EntryWrapperOptions): string;
90
+ /**
91
+ * Get Bun-specific esbuild configuration
92
+ *
93
+ * Note: Bun natively supports import.meta.env, so no define alias is needed.
94
+ * We use platform: "node" since Bun is Node-compatible for module resolution.
95
+ */
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;
53
104
  /**
54
105
  * Dispose of platform resources
55
106
  */
56
107
  dispose(): Promise<void>;
108
+ /**
109
+ * Get the OS temp directory (Bun-specific implementation using node:os)
110
+ */
111
+ tmpdir(): string;
57
112
  }
58
113
  /**
59
114
  * Default export for easy importing
60
115
  */
61
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,34 +1,174 @@
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
- loadConfig,
8
- createCacheFactory
9
+ CustomLoggerStorage,
10
+ CustomDatabaseStorage,
11
+ createDatabaseFactory
9
12
  } from "@b9g/platform";
13
+ import {
14
+ createCacheFactory,
15
+ createDirectoryFactory
16
+ } from "@b9g/platform/runtime";
10
17
  import { CustomCacheStorage } from "@b9g/cache";
18
+ import { MemoryCache } from "@b9g/cache/memory";
19
+ import { CustomDirectoryStorage } from "@b9g/filesystem";
20
+ import { NodeFSDirectory } from "@b9g/filesystem/node-fs";
11
21
  import { InternalServerError, isHTTPError } from "@b9g/http-errors";
12
- import * as Path from "path";
13
22
  import { getLogger } from "@logtape/logtape";
14
- var logger = getLogger(["platform-bun"]);
23
+ import * as Path from "path";
24
+ import { MemoryCache as MemoryCache2 } from "@b9g/cache/memory";
25
+ var entryTemplate = `// Bun Production Server Entry
26
+ import {tmpdir} from "os"; // For [tmpdir] config expressions
27
+ import {getLogger} from "@logtape/logtape";
28
+ import {configureLogging} from "@b9g/platform/runtime";
29
+ import {config} from "shovel:config"; // Virtual module - resolved at build time
30
+ import BunPlatform from "@b9g/platform-bun";
31
+
32
+ // Configure logging before anything else
33
+ await configureLogging(config.logging);
34
+
35
+ const logger = getLogger(["shovel", "platform"]);
36
+
37
+ // Configuration from shovel:config
38
+ const PORT = config.port;
39
+ const HOST = config.host;
40
+ const WORKERS = config.workers;
41
+
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
48
+ const platform = new BunPlatform({port: PORT, host: HOST, workers: 1});
49
+ const userCodePath = new URL("./server.js", import.meta.url).pathname;
50
+ const serviceWorker = await platform.loadServiceWorker(userCodePath);
51
+
52
+ Bun.serve({
53
+ port: PORT,
54
+ hostname: HOST,
55
+ // Only need reusePort for multi-worker (multiple listeners on same port)
56
+ reusePort: WORKERS > 1,
57
+ fetch: serviceWorker.handleRequest,
58
+ });
59
+
60
+ // Signal ready to main thread
61
+ postMessage({type: "ready", thread: Bun.threadId});
62
+ logger.info("Worker started", {port: PORT, thread: Bun.threadId});
63
+ } else {
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);
76
+ }
77
+ };
78
+ await checkPort();
79
+
80
+ let shuttingDown = false;
81
+ const workers = [];
82
+ let readyCount = 0;
83
+
84
+ for (let i = 0; i < WORKERS; i++) {
85
+ const worker = new Worker(import.meta.path, {
86
+ env: {...process.env, SHOVEL_SPAWNED_WORKER: "1"},
87
+ });
88
+
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
+ };
97
+
98
+ worker.onerror = (error) => {
99
+ logger.error("Worker error", {error: error.message});
100
+ };
101
+
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);
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);
126
+ }
127
+ `;
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"]);
15
154
  var BunPlatform = class extends BasePlatform {
16
155
  name;
17
156
  #options;
18
157
  #workerPool;
19
158
  #singleThreadedRuntime;
20
159
  #cacheStorage;
21
- #config;
160
+ #directoryStorage;
161
+ #databaseStorage;
22
162
  constructor(options = {}) {
23
163
  super(options);
24
164
  this.name = "bun";
25
165
  const cwd = options.cwd || process.cwd();
26
- this.#config = loadConfig(cwd);
27
166
  this.#options = {
28
- port: options.port ?? this.#config.port,
29
- host: options.host ?? this.#config.host,
167
+ port: options.port ?? 3e3,
168
+ host: options.host ?? "localhost",
169
+ workers: options.workers ?? 1,
30
170
  cwd,
31
- ...options
171
+ config: options.config
32
172
  };
33
173
  }
34
174
  /**
@@ -47,46 +187,96 @@ var BunPlatform = class extends BasePlatform {
47
187
  this.#workerPool = pool;
48
188
  }
49
189
  /**
50
- * Create cache storage
51
- * Uses config from package.json shovel field
190
+ * Create cache storage using config from shovel.json
191
+ * Merges with runtime defaults (actual class references) for fallback behavior
52
192
  */
53
193
  async createCaches() {
54
- return new CustomCacheStorage(createCacheFactory({ config: this.#config }));
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 }));
207
+ }
208
+ /**
209
+ * Create directory storage using config from shovel.json
210
+ * Merges with runtime defaults (actual class references) for fallback behavior
211
+ */
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;
55
245
  }
56
246
  /**
57
247
  * Create HTTP server using Bun.serve
58
248
  */
59
249
  createServer(handler, options = {}) {
60
- const port = options.port ?? this.#options.port;
250
+ const requestedPort = options.port ?? this.#options.port;
61
251
  const hostname = options.host ?? this.#options.host;
62
252
  const server = Bun.serve({
63
- port,
253
+ port: requestedPort,
64
254
  hostname,
65
255
  async fetch(request) {
66
256
  try {
67
257
  return await handler(request);
68
258
  } catch (error) {
69
259
  const err = error instanceof Error ? error : new Error(String(error));
70
- logger.error("Request error", {
71
- error: err.message,
72
- stack: err.stack
73
- });
260
+ logger.error("Request error: {error}", { error: err });
74
261
  const httpError = isHTTPError(error) ? error : new InternalServerError(err.message, { cause: err });
75
262
  const isDev = import.meta.env?.MODE !== "production";
76
263
  return httpError.toResponse(isDev);
77
264
  }
78
265
  }
79
266
  });
267
+ const actualPort = server.port;
80
268
  return {
81
269
  async listen() {
82
- logger.info("Bun server running", { url: `http://${hostname}:${port}` });
270
+ logger.info("Bun server running", {
271
+ url: `http://${hostname}:${actualPort}`
272
+ });
83
273
  },
84
274
  async close() {
85
275
  server.stop();
86
276
  },
87
- address: () => ({ port, host: hostname }),
277
+ address: () => ({ port: actualPort, host: hostname }),
88
278
  get url() {
89
- return `http://${hostname}:${port}`;
279
+ return `http://${hostname}:${actualPort}`;
90
280
  },
91
281
  get ready() {
92
282
  return true;
@@ -98,7 +288,7 @@ var BunPlatform = class extends BasePlatform {
98
288
  * Uses native Web Workers with the common WorkerPool
99
289
  */
100
290
  async loadServiceWorker(entrypoint, options = {}) {
101
- const workerCount = options.workerCount ?? this.#config.workers ?? 1;
291
+ const workerCount = options.workerCount ?? this.#options.workers;
102
292
  if (workerCount === 1 && !options.hotReload) {
103
293
  return this.#loadServiceWorkerDirect(entrypoint, options);
104
294
  }
@@ -110,9 +300,55 @@ var BunPlatform = class extends BasePlatform {
110
300
  */
111
301
  async #loadServiceWorkerDirect(entrypoint, _options) {
112
302
  const entryPath = Path.resolve(this.#options.cwd, entrypoint);
113
- 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
+ }
114
311
  if (!this.#cacheStorage) {
115
- 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
+ );
330
+ }
331
+ if (!this.#directoryStorage) {
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);
116
352
  }
117
353
  if (this.#singleThreadedRuntime) {
118
354
  await this.#singleThreadedRuntime.terminate();
@@ -123,12 +359,13 @@ var BunPlatform = class extends BasePlatform {
123
359
  }
124
360
  logger.info("Creating single-threaded ServiceWorker runtime", { entryPath });
125
361
  this.#singleThreadedRuntime = new SingleThreadedRuntime({
126
- baseDir: entryDir,
127
- cacheStorage: this.#cacheStorage,
128
- config: this.#config
362
+ caches: this.#cacheStorage,
363
+ directories: this.#directoryStorage,
364
+ databases: this.#databaseStorage,
365
+ loggers: new CustomLoggerStorage((cats) => getLogger(cats))
129
366
  });
130
367
  await this.#singleThreadedRuntime.init();
131
- await this.#singleThreadedRuntime.loadEntrypoint(entryPath);
368
+ await this.#singleThreadedRuntime.load(entryPath);
132
369
  const runtime = this.#singleThreadedRuntime;
133
370
  const platform = this;
134
371
  const instance = {
@@ -185,11 +422,9 @@ var BunPlatform = class extends BasePlatform {
185
422
  this.#workerPool = new ServiceWorkerPool(
186
423
  poolOptions,
187
424
  entryPath,
188
- this.#cacheStorage,
189
- this.#config
425
+ this.#cacheStorage
190
426
  );
191
427
  await this.#workerPool.init();
192
- await this.#workerPool.reloadWorkers(entryPath);
193
428
  const workerPool = this.#workerPool;
194
429
  const platform = this;
195
430
  const instance = {
@@ -230,9 +465,72 @@ var BunPlatform = class extends BasePlatform {
230
465
  if (this.#workerPool) {
231
466
  await this.#workerPool.reloadWorkers(entrypoint);
232
467
  } else if (this.#singleThreadedRuntime) {
233
- await this.#singleThreadedRuntime.reloadWorkers(entrypoint);
468
+ await this.#singleThreadedRuntime.load(entrypoint);
234
469
  }
235
470
  }
471
+ /**
472
+ * Get virtual entry wrapper for Bun
473
+ *
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)
478
+ *
479
+ * Returns:
480
+ * - "production": Server entry with Bun.serve and reusePort
481
+ * - "worker": Worker entry that sets up runtime and message loop
482
+ */
483
+ getEntryWrapper(entryPath, options) {
484
+ if (options?.type === "worker") {
485
+ return workerEntryTemplate.replace("__USER_ENTRY__", entryPath);
486
+ }
487
+ return entryTemplate;
488
+ }
489
+ /**
490
+ * Get Bun-specific esbuild configuration
491
+ *
492
+ * Note: Bun natively supports import.meta.env, so no define alias is needed.
493
+ * We use platform: "node" since Bun is Node-compatible for module resolution.
494
+ */
495
+ getESBuildConfig() {
496
+ return {
497
+ platform: "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
+ }
532
+ };
533
+ }
236
534
  /**
237
535
  * Dispose of platform resources
238
536
  */
@@ -249,10 +547,24 @@ var BunPlatform = class extends BasePlatform {
249
547
  await this.#cacheStorage.dispose();
250
548
  this.#cacheStorage = void 0;
251
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();
252
563
  }
253
564
  };
254
565
  var src_default = BunPlatform;
255
566
  export {
256
567
  BunPlatform,
568
+ MemoryCache2 as DefaultCache,
257
569
  src_default as default
258
570
  };