@b9g/platform-bun 0.1.12-beta.0 → 0.1.13
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 +13 -5
- package/src/index.d.ts +9 -40
- package/src/index.js +70 -113
- package/src/platform.d.ts +43 -0
- package/src/platform.js +175 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b9g/platform-bun",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Bun platform adapter for Shovel with hot reloading and built-in TypeScript/JSX support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shovel",
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"jsx"
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@b9g/assets": "^0.2.0
|
|
16
|
-
"@b9g/cache": "^0.2.0
|
|
17
|
-
"@b9g/http-errors": "^0.2.0
|
|
18
|
-
"@b9g/platform": "^0.1.
|
|
15
|
+
"@b9g/assets": "^0.2.0",
|
|
16
|
+
"@b9g/cache": "^0.2.0",
|
|
17
|
+
"@b9g/http-errors": "^0.2.0",
|
|
18
|
+
"@b9g/platform": "^0.1.15",
|
|
19
19
|
"@logtape/logtape": "^1.2.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
@@ -37,6 +37,14 @@
|
|
|
37
37
|
"./index.js": {
|
|
38
38
|
"types": "./src/index.d.ts",
|
|
39
39
|
"import": "./src/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./platform": {
|
|
42
|
+
"types": "./src/platform.d.ts",
|
|
43
|
+
"import": "./src/platform.js"
|
|
44
|
+
},
|
|
45
|
+
"./platform.js": {
|
|
46
|
+
"types": "./src/platform.d.ts",
|
|
47
|
+
"import": "./src/platform.js"
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides built-in TypeScript/JSX support and simplified server setup for Bun environments.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import { CustomDirectoryStorage } from "@b9g/filesystem";
|
|
8
|
-
import { BasePlatform, type PlatformConfig, type PlatformDefaults, type Handler, type Server, type ServerOptions, type PlatformESBuildConfig, type ProductionEntryPoints, ServiceWorkerPool, CustomLoggerStorage, CustomDatabaseStorage } from "@b9g/platform";
|
|
6
|
+
import { type PlatformDefaults, type Handler, type Server, type ServerOptions, type PlatformESBuildConfig, type EntryPoints, ServiceWorkerPool } from "@b9g/platform";
|
|
9
7
|
import { type ShovelConfig } from "@b9g/platform/runtime";
|
|
10
|
-
export interface BunPlatformOptions
|
|
8
|
+
export interface BunPlatformOptions {
|
|
11
9
|
/** Port for development server (default: 3000) */
|
|
12
10
|
port?: number;
|
|
13
11
|
/** Host for development server (default: localhost) */
|
|
@@ -72,7 +70,7 @@ export declare class BunServiceWorkerContainer extends EventTarget implements Se
|
|
|
72
70
|
* Bun platform implementation
|
|
73
71
|
* ServiceWorker entrypoint loader for Bun with native TypeScript/JSX support
|
|
74
72
|
*/
|
|
75
|
-
export declare class BunPlatform
|
|
73
|
+
export declare class BunPlatform {
|
|
76
74
|
#private;
|
|
77
75
|
readonly name: string;
|
|
78
76
|
readonly serviceWorker: BunServiceWorkerContainer;
|
|
@@ -87,38 +85,6 @@ export declare class BunPlatform extends BasePlatform {
|
|
|
87
85
|
workers: number;
|
|
88
86
|
config?: ShovelConfig;
|
|
89
87
|
};
|
|
90
|
-
/**
|
|
91
|
-
* Create cache storage for Bun
|
|
92
|
-
*
|
|
93
|
-
* Default: MemoryCache (in-process LRU cache).
|
|
94
|
-
* Override via shovel.json caches config.
|
|
95
|
-
* Note: Used for dev/testing - production uses generated config module.
|
|
96
|
-
*/
|
|
97
|
-
createCaches(): Promise<CustomCacheStorage>;
|
|
98
|
-
/**
|
|
99
|
-
* Create directory storage for Bun
|
|
100
|
-
*
|
|
101
|
-
* Defaults:
|
|
102
|
-
* - server: NodeFSDirectory at cwd (app files)
|
|
103
|
-
* - public: NodeFSDirectory at cwd (static assets)
|
|
104
|
-
* - tmp: NodeFSDirectory at OS temp dir
|
|
105
|
-
*
|
|
106
|
-
* Override via shovel.json directories config.
|
|
107
|
-
*/
|
|
108
|
-
createDirectories(): Promise<CustomDirectoryStorage>;
|
|
109
|
-
/**
|
|
110
|
-
* Create logger storage for Bun
|
|
111
|
-
*
|
|
112
|
-
* Uses LogTape for structured logging.
|
|
113
|
-
*/
|
|
114
|
-
createLoggers(): Promise<CustomLoggerStorage>;
|
|
115
|
-
/**
|
|
116
|
-
* Create database storage for Bun
|
|
117
|
-
*
|
|
118
|
-
* Returns undefined if no databases configured in shovel.json.
|
|
119
|
-
* Supports SQLite via bun:sqlite.
|
|
120
|
-
*/
|
|
121
|
-
createDatabases(configOverride?: BunPlatformOptions["config"]): CustomDatabaseStorage | undefined;
|
|
122
88
|
/**
|
|
123
89
|
* Create HTTP server using Bun.serve
|
|
124
90
|
*/
|
|
@@ -137,16 +103,19 @@ export declare class BunPlatform extends BasePlatform {
|
|
|
137
103
|
*/
|
|
138
104
|
reloadWorkers(entrypoint: string): Promise<void>;
|
|
139
105
|
/**
|
|
140
|
-
* Get
|
|
106
|
+
* Get entry points for bundling.
|
|
107
|
+
*
|
|
108
|
+
* Development mode:
|
|
109
|
+
* - worker.js: Single worker with HTTP server (develop command manages process)
|
|
141
110
|
*
|
|
142
|
-
*
|
|
111
|
+
* Production mode:
|
|
143
112
|
* - index.js: Supervisor that spawns workers and handles signals
|
|
144
113
|
* - worker.js: Worker with its own HTTP server (uses reusePort for multi-worker)
|
|
145
114
|
*
|
|
146
115
|
* Unlike Node.js, Bun workers each bind their own server with reusePort,
|
|
147
116
|
* allowing the OS to load-balance across workers without message passing overhead.
|
|
148
117
|
*/
|
|
149
|
-
|
|
118
|
+
getEntryPoints(userEntryPath: string, mode: "development" | "production"): EntryPoints;
|
|
150
119
|
/**
|
|
151
120
|
* Get Bun-specific esbuild configuration
|
|
152
121
|
*
|
package/src/index.js
CHANGED
|
@@ -5,25 +5,16 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import * as Path from "node:path";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { CustomCacheStorage } from "@b9g/cache";
|
|
8
|
-
import { MemoryCache } from "@b9g/cache/memory";
|
|
9
|
-
import { CustomDirectoryStorage } from "@b9g/filesystem";
|
|
10
|
-
import { NodeFSDirectory } from "@b9g/filesystem/node-fs";
|
|
11
8
|
import { InternalServerError, isHTTPError } from "@b9g/http-errors";
|
|
12
9
|
import {
|
|
13
|
-
|
|
14
|
-
ServiceWorkerPool,
|
|
15
|
-
CustomLoggerStorage,
|
|
16
|
-
CustomDatabaseStorage,
|
|
17
|
-
createDatabaseFactory,
|
|
18
|
-
mergeConfigWithDefaults
|
|
10
|
+
ServiceWorkerPool
|
|
19
11
|
} from "@b9g/platform";
|
|
20
12
|
import {
|
|
21
13
|
ShovelServiceWorkerRegistration,
|
|
22
14
|
kServiceWorker,
|
|
23
|
-
createCacheFactory
|
|
24
|
-
createDirectoryFactory
|
|
15
|
+
createCacheFactory
|
|
25
16
|
} from "@b9g/platform/runtime";
|
|
26
|
-
import { MemoryCache
|
|
17
|
+
import { MemoryCache } from "@b9g/cache/memory";
|
|
27
18
|
var logger = getLogger(["shovel", "platform"]);
|
|
28
19
|
var BunServiceWorkerContainer = class extends EventTarget {
|
|
29
20
|
#platform;
|
|
@@ -139,14 +130,12 @@ var BunServiceWorkerContainer = class extends EventTarget {
|
|
|
139
130
|
await this.#pool?.reloadWorkers(entrypoint);
|
|
140
131
|
}
|
|
141
132
|
};
|
|
142
|
-
var BunPlatform = class
|
|
133
|
+
var BunPlatform = class {
|
|
143
134
|
name;
|
|
144
135
|
serviceWorker;
|
|
145
136
|
#options;
|
|
146
137
|
#server;
|
|
147
|
-
#databaseStorage;
|
|
148
138
|
constructor(options = {}) {
|
|
149
|
-
super(options);
|
|
150
139
|
this.name = "bun";
|
|
151
140
|
const cwd = options.cwd || process.cwd();
|
|
152
141
|
this.#options = {
|
|
@@ -164,65 +153,6 @@ var BunPlatform = class extends BasePlatform {
|
|
|
164
153
|
get options() {
|
|
165
154
|
return this.#options;
|
|
166
155
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Create cache storage for Bun
|
|
169
|
-
*
|
|
170
|
-
* Default: MemoryCache (in-process LRU cache).
|
|
171
|
-
* Override via shovel.json caches config.
|
|
172
|
-
* Note: Used for dev/testing - production uses generated config module.
|
|
173
|
-
*/
|
|
174
|
-
async createCaches() {
|
|
175
|
-
const defaults = { default: { impl: MemoryCache } };
|
|
176
|
-
const configs = mergeConfigWithDefaults(
|
|
177
|
-
defaults,
|
|
178
|
-
this.#options.config?.caches
|
|
179
|
-
);
|
|
180
|
-
return new CustomCacheStorage(createCacheFactory({ configs }));
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Create directory storage for Bun
|
|
184
|
-
*
|
|
185
|
-
* Defaults:
|
|
186
|
-
* - server: NodeFSDirectory at cwd (app files)
|
|
187
|
-
* - public: NodeFSDirectory at cwd (static assets)
|
|
188
|
-
* - tmp: NodeFSDirectory at OS temp dir
|
|
189
|
-
*
|
|
190
|
-
* Override via shovel.json directories config.
|
|
191
|
-
*/
|
|
192
|
-
async createDirectories() {
|
|
193
|
-
const defaults = {
|
|
194
|
-
server: { impl: NodeFSDirectory, path: this.#options.cwd },
|
|
195
|
-
public: { impl: NodeFSDirectory, path: this.#options.cwd },
|
|
196
|
-
tmp: { impl: NodeFSDirectory, path: tmpdir() }
|
|
197
|
-
};
|
|
198
|
-
const configs = mergeConfigWithDefaults(
|
|
199
|
-
defaults,
|
|
200
|
-
this.#options.config?.directories
|
|
201
|
-
);
|
|
202
|
-
return new CustomDirectoryStorage(createDirectoryFactory(configs));
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Create logger storage for Bun
|
|
206
|
-
*
|
|
207
|
-
* Uses LogTape for structured logging.
|
|
208
|
-
*/
|
|
209
|
-
async createLoggers() {
|
|
210
|
-
return new CustomLoggerStorage((categories) => getLogger(categories));
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Create database storage for Bun
|
|
214
|
-
*
|
|
215
|
-
* Returns undefined if no databases configured in shovel.json.
|
|
216
|
-
* Supports SQLite via bun:sqlite.
|
|
217
|
-
*/
|
|
218
|
-
createDatabases(configOverride) {
|
|
219
|
-
const config = configOverride ?? this.#options.config;
|
|
220
|
-
if (config?.databases && Object.keys(config.databases).length > 0) {
|
|
221
|
-
const factory = createDatabaseFactory(config.databases);
|
|
222
|
-
return new CustomDatabaseStorage(factory);
|
|
223
|
-
}
|
|
224
|
-
return void 0;
|
|
225
|
-
}
|
|
226
156
|
/**
|
|
227
157
|
* Create HTTP server using Bun.serve
|
|
228
158
|
*/
|
|
@@ -239,8 +169,15 @@ var BunPlatform = class extends BasePlatform {
|
|
|
239
169
|
return await handler(request);
|
|
240
170
|
} catch (error) {
|
|
241
171
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
242
|
-
logger.error("Request error: {error}", { error: err });
|
|
243
172
|
const httpError = isHTTPError(error) ? error : new InternalServerError(err.message, { cause: err });
|
|
173
|
+
if (httpError.status >= 500) {
|
|
174
|
+
logger.error("Request error: {error}", { error: err });
|
|
175
|
+
} else {
|
|
176
|
+
logger.warn("Request error: {status} {error}", {
|
|
177
|
+
status: httpError.status,
|
|
178
|
+
error: err
|
|
179
|
+
});
|
|
180
|
+
}
|
|
244
181
|
const isDev = import.meta.env?.MODE !== "production";
|
|
245
182
|
return httpError.toResponse(isDev);
|
|
246
183
|
}
|
|
@@ -297,44 +234,20 @@ var BunPlatform = class extends BasePlatform {
|
|
|
297
234
|
await this.serviceWorker.reloadWorkers(entrypoint);
|
|
298
235
|
}
|
|
299
236
|
/**
|
|
300
|
-
* Get
|
|
237
|
+
* Get entry points for bundling.
|
|
238
|
+
*
|
|
239
|
+
* Development mode:
|
|
240
|
+
* - worker.js: Single worker with HTTP server (develop command manages process)
|
|
301
241
|
*
|
|
302
|
-
*
|
|
242
|
+
* Production mode:
|
|
303
243
|
* - index.js: Supervisor that spawns workers and handles signals
|
|
304
244
|
* - worker.js: Worker with its own HTTP server (uses reusePort for multi-worker)
|
|
305
245
|
*
|
|
306
246
|
* Unlike Node.js, Bun workers each bind their own server with reusePort,
|
|
307
247
|
* allowing the OS to load-balance across workers without message passing overhead.
|
|
308
248
|
*/
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
import {getLogger} from "@logtape/logtape";
|
|
312
|
-
import {configureLogging} from "@b9g/platform/runtime";
|
|
313
|
-
import BunPlatform from "@b9g/platform-bun";
|
|
314
|
-
import {config} from "shovel:config";
|
|
315
|
-
|
|
316
|
-
await configureLogging(config.logging);
|
|
317
|
-
const logger = getLogger(["shovel", "platform"]);
|
|
318
|
-
|
|
319
|
-
logger.info("Starting production server", {port: config.port, workers: config.workers});
|
|
320
|
-
|
|
321
|
-
// Initialize platform and register ServiceWorker (workers handle their own HTTP via reusePort)
|
|
322
|
-
const platform = new BunPlatform({port: config.port, host: config.host, workers: config.workers});
|
|
323
|
-
await platform.serviceWorker.register(new URL("./worker.js", import.meta.url).href);
|
|
324
|
-
await platform.serviceWorker.ready;
|
|
325
|
-
|
|
326
|
-
logger.info("All workers ready", {port: config.port, workers: config.workers});
|
|
327
|
-
|
|
328
|
-
// Graceful shutdown
|
|
329
|
-
const handleShutdown = async () => {
|
|
330
|
-
logger.info("Shutting down");
|
|
331
|
-
await platform.serviceWorker.terminate();
|
|
332
|
-
process.exit(0);
|
|
333
|
-
};
|
|
334
|
-
process.on("SIGINT", handleShutdown);
|
|
335
|
-
process.on("SIGTERM", handleShutdown);
|
|
336
|
-
`;
|
|
337
|
-
const workerCode = `// Bun Production Worker
|
|
249
|
+
getEntryPoints(userEntryPath, mode) {
|
|
250
|
+
const prodWorkerCode = `// Bun Production Worker
|
|
338
251
|
import BunPlatform from "@b9g/platform-bun";
|
|
339
252
|
import {getLogger} from "@logtape/logtape";
|
|
340
253
|
import {configureLogging, initWorkerRuntime, runLifecycle, dispatchRequest} from "@b9g/platform/runtime";
|
|
@@ -380,10 +293,58 @@ if (!config.lifecycle) {
|
|
|
380
293
|
|
|
381
294
|
postMessage({type: "ready"});
|
|
382
295
|
logger.info("Worker started", {port: config.port});
|
|
296
|
+
`;
|
|
297
|
+
const devWorkerCode = `// Bun Development Worker
|
|
298
|
+
import {configureLogging, initWorkerRuntime, runLifecycle, startWorkerMessageLoop} from "@b9g/platform/runtime";
|
|
299
|
+
import {config} from "shovel:config";
|
|
300
|
+
|
|
301
|
+
await configureLogging(config.logging);
|
|
302
|
+
|
|
303
|
+
// Initialize worker runtime (installs ServiceWorker globals)
|
|
304
|
+
const {registration, databases} = await initWorkerRuntime({config});
|
|
305
|
+
|
|
306
|
+
// Import user code (registers event handlers)
|
|
307
|
+
await import("${userEntryPath}");
|
|
308
|
+
|
|
309
|
+
// Run ServiceWorker lifecycle
|
|
310
|
+
await runLifecycle(registration);
|
|
311
|
+
|
|
312
|
+
// Start message loop for request handling (develop command handles HTTP)
|
|
313
|
+
startWorkerMessageLoop({registration, databases});
|
|
314
|
+
`;
|
|
315
|
+
if (mode === "development") {
|
|
316
|
+
return { worker: devWorkerCode };
|
|
317
|
+
}
|
|
318
|
+
const supervisorCode = `// Bun Production Supervisor
|
|
319
|
+
import {getLogger} from "@logtape/logtape";
|
|
320
|
+
import {configureLogging} from "@b9g/platform/runtime";
|
|
321
|
+
import BunPlatform from "@b9g/platform-bun";
|
|
322
|
+
import {config} from "shovel:config";
|
|
323
|
+
|
|
324
|
+
await configureLogging(config.logging);
|
|
325
|
+
const logger = getLogger(["shovel", "platform"]);
|
|
326
|
+
|
|
327
|
+
logger.info("Starting production server", {port: config.port, workers: config.workers});
|
|
328
|
+
|
|
329
|
+
// Initialize platform and register ServiceWorker (workers handle their own HTTP via reusePort)
|
|
330
|
+
const platform = new BunPlatform({port: config.port, host: config.host, workers: config.workers});
|
|
331
|
+
await platform.serviceWorker.register(new URL("./worker.js", import.meta.url).href);
|
|
332
|
+
await platform.serviceWorker.ready;
|
|
333
|
+
|
|
334
|
+
logger.info("All workers ready", {port: config.port, workers: config.workers});
|
|
335
|
+
|
|
336
|
+
// Graceful shutdown
|
|
337
|
+
const handleShutdown = async () => {
|
|
338
|
+
logger.info("Shutting down");
|
|
339
|
+
await platform.serviceWorker.terminate();
|
|
340
|
+
process.exit(0);
|
|
341
|
+
};
|
|
342
|
+
process.on("SIGINT", handleShutdown);
|
|
343
|
+
process.on("SIGTERM", handleShutdown);
|
|
383
344
|
`;
|
|
384
345
|
return {
|
|
385
|
-
|
|
386
|
-
worker:
|
|
346
|
+
supervisor: supervisorCode,
|
|
347
|
+
worker: prodWorkerCode
|
|
387
348
|
};
|
|
388
349
|
}
|
|
389
350
|
/**
|
|
@@ -437,10 +398,6 @@ logger.info("Worker started", {port: config.port});
|
|
|
437
398
|
async dispose() {
|
|
438
399
|
await this.close();
|
|
439
400
|
await this.serviceWorker.terminate();
|
|
440
|
-
if (this.#databaseStorage) {
|
|
441
|
-
await this.#databaseStorage.closeAll();
|
|
442
|
-
this.#databaseStorage = void 0;
|
|
443
|
-
}
|
|
444
401
|
}
|
|
445
402
|
// =========================================================================
|
|
446
403
|
// Config Expression Method Overrides
|
|
@@ -456,6 +413,6 @@ var src_default = BunPlatform;
|
|
|
456
413
|
export {
|
|
457
414
|
BunPlatform,
|
|
458
415
|
BunServiceWorkerContainer,
|
|
459
|
-
|
|
416
|
+
MemoryCache as DefaultCache,
|
|
460
417
|
src_default as default
|
|
461
418
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun Platform Module
|
|
3
|
+
*
|
|
4
|
+
* Build-time and dev-time functions for Bun.
|
|
5
|
+
* Runtime functions are in ./runtime.ts
|
|
6
|
+
*/
|
|
7
|
+
import type { EntryPoints, ESBuildConfig, PlatformDefaults, DevServerOptions, DevServer } from "@b9g/platform/module";
|
|
8
|
+
export declare const name = "bun";
|
|
9
|
+
/**
|
|
10
|
+
* Get entry points for bundling.
|
|
11
|
+
*
|
|
12
|
+
* Development mode:
|
|
13
|
+
* - worker.js: Single worker with message loop (develop command manages process)
|
|
14
|
+
*
|
|
15
|
+
* Production mode:
|
|
16
|
+
* - supervisor.js: Spawns workers and handles signals
|
|
17
|
+
* - worker.js: Worker with its own HTTP server (uses reusePort for multi-worker)
|
|
18
|
+
*
|
|
19
|
+
* Unlike Node.js, Bun workers each bind their own server with reusePort,
|
|
20
|
+
* allowing the OS to load-balance across workers without message passing overhead.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getEntryPoints(userEntryPath: string, mode: "development" | "production"): EntryPoints;
|
|
23
|
+
/**
|
|
24
|
+
* Get ESBuild configuration for Bun.
|
|
25
|
+
*
|
|
26
|
+
* Note: Bun natively supports import.meta.env, so no define alias is needed.
|
|
27
|
+
* We use platform: "node" since Bun is Node-compatible for module resolution.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getESBuildConfig(): ESBuildConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Get platform defaults for config generation.
|
|
32
|
+
*
|
|
33
|
+
* Provides default directories (server, public, tmp) that work
|
|
34
|
+
* out of the box for Bun deployments.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getDefaults(): PlatformDefaults;
|
|
37
|
+
/**
|
|
38
|
+
* Create a dev server using ServiceWorkerPool.
|
|
39
|
+
*
|
|
40
|
+
* Dynamically imports the platform class to keep heavy dependencies
|
|
41
|
+
* out of production bundles.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createDevServer(options: DevServerOptions): Promise<DevServer>;
|
package/src/platform.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/// <reference types="./platform.d.ts" />
|
|
2
|
+
// src/platform.ts
|
|
3
|
+
import { builtinModules } from "node:module";
|
|
4
|
+
import { getLogger } from "@logtape/logtape";
|
|
5
|
+
var logger = getLogger(["shovel", "platform"]);
|
|
6
|
+
var name = "bun";
|
|
7
|
+
function getEntryPoints(userEntryPath, mode) {
|
|
8
|
+
const safePath = JSON.stringify(userEntryPath);
|
|
9
|
+
const devWorkerCode = `// Bun Development Worker
|
|
10
|
+
import {configureLogging, initWorkerRuntime, runLifecycle, startWorkerMessageLoop} from "@b9g/platform/runtime";
|
|
11
|
+
import {config} from "shovel:config";
|
|
12
|
+
|
|
13
|
+
await configureLogging(config.logging);
|
|
14
|
+
|
|
15
|
+
// Initialize worker runtime (installs ServiceWorker globals)
|
|
16
|
+
const {registration, databases} = await initWorkerRuntime({config});
|
|
17
|
+
|
|
18
|
+
// Import user code (registers event handlers)
|
|
19
|
+
await import(${safePath});
|
|
20
|
+
|
|
21
|
+
// Run ServiceWorker lifecycle
|
|
22
|
+
await runLifecycle(registration);
|
|
23
|
+
|
|
24
|
+
// Start message loop for request handling (develop command handles HTTP)
|
|
25
|
+
startWorkerMessageLoop({registration, databases});
|
|
26
|
+
`;
|
|
27
|
+
if (mode === "development") {
|
|
28
|
+
return { worker: devWorkerCode };
|
|
29
|
+
}
|
|
30
|
+
const prodWorkerCode = `// Bun Production Worker
|
|
31
|
+
import BunPlatform from "@b9g/platform-bun";
|
|
32
|
+
import {getLogger} from "@logtape/logtape";
|
|
33
|
+
import {configureLogging, initWorkerRuntime, runLifecycle, dispatchRequest} from "@b9g/platform/runtime";
|
|
34
|
+
import {config} from "shovel:config";
|
|
35
|
+
|
|
36
|
+
await configureLogging(config.logging);
|
|
37
|
+
const logger = getLogger(["shovel", "platform"]);
|
|
38
|
+
|
|
39
|
+
// Track resources for shutdown
|
|
40
|
+
let server;
|
|
41
|
+
let databases;
|
|
42
|
+
|
|
43
|
+
// Register shutdown handler before async startup
|
|
44
|
+
self.onmessage = async (event) => {
|
|
45
|
+
if (event.data.type === "shutdown") {
|
|
46
|
+
logger.info("Worker shutting down");
|
|
47
|
+
if (server) await server.close();
|
|
48
|
+
if (databases) await databases.closeAll();
|
|
49
|
+
postMessage({type: "shutdown-complete"});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Initialize worker runtime (installs ServiceWorker globals)
|
|
54
|
+
const result = await initWorkerRuntime({config});
|
|
55
|
+
const registration = result.registration;
|
|
56
|
+
databases = result.databases;
|
|
57
|
+
|
|
58
|
+
// Import user code (registers event handlers)
|
|
59
|
+
await import(${safePath});
|
|
60
|
+
|
|
61
|
+
// Run ServiceWorker lifecycle (stage from config.lifecycle if present)
|
|
62
|
+
await runLifecycle(registration, config.lifecycle?.stage);
|
|
63
|
+
|
|
64
|
+
// Start server (skip in lifecycle-only mode)
|
|
65
|
+
if (!config.lifecycle) {
|
|
66
|
+
const platform = new BunPlatform({port: config.port, host: config.host});
|
|
67
|
+
server = platform.createServer(
|
|
68
|
+
(request) => dispatchRequest(registration, request),
|
|
69
|
+
{reusePort: config.workers > 1},
|
|
70
|
+
);
|
|
71
|
+
await server.listen();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
postMessage({type: "ready"});
|
|
75
|
+
logger.info("Worker started", {port: config.port});
|
|
76
|
+
`;
|
|
77
|
+
const supervisorCode = `// Bun Production Supervisor
|
|
78
|
+
import {getLogger} from "@logtape/logtape";
|
|
79
|
+
import {configureLogging} from "@b9g/platform/runtime";
|
|
80
|
+
import BunPlatform from "@b9g/platform-bun";
|
|
81
|
+
import {config} from "shovel:config";
|
|
82
|
+
|
|
83
|
+
await configureLogging(config.logging);
|
|
84
|
+
const logger = getLogger(["shovel", "platform"]);
|
|
85
|
+
|
|
86
|
+
logger.info("Starting production server", {port: config.port, workers: config.workers});
|
|
87
|
+
|
|
88
|
+
// Initialize platform and register ServiceWorker (workers handle their own HTTP via reusePort)
|
|
89
|
+
const platform = new BunPlatform({port: config.port, host: config.host, workers: config.workers});
|
|
90
|
+
await platform.serviceWorker.register(new URL("./worker.js", import.meta.url).href);
|
|
91
|
+
await platform.serviceWorker.ready;
|
|
92
|
+
|
|
93
|
+
logger.info("All workers ready", {port: config.port, workers: config.workers});
|
|
94
|
+
|
|
95
|
+
// Graceful shutdown
|
|
96
|
+
const handleShutdown = async () => {
|
|
97
|
+
logger.info("Shutting down");
|
|
98
|
+
await platform.serviceWorker.terminate();
|
|
99
|
+
process.exit(0);
|
|
100
|
+
};
|
|
101
|
+
process.on("SIGINT", handleShutdown);
|
|
102
|
+
process.on("SIGTERM", handleShutdown);
|
|
103
|
+
`;
|
|
104
|
+
return {
|
|
105
|
+
supervisor: supervisorCode,
|
|
106
|
+
worker: prodWorkerCode
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function getESBuildConfig() {
|
|
110
|
+
return {
|
|
111
|
+
platform: "node",
|
|
112
|
+
external: ["node:*", "bun", "bun:*", ...builtinModules]
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function getDefaults() {
|
|
116
|
+
return {
|
|
117
|
+
caches: {
|
|
118
|
+
default: {
|
|
119
|
+
module: "@b9g/cache/memory",
|
|
120
|
+
export: "MemoryCache"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
directories: {
|
|
124
|
+
server: {
|
|
125
|
+
module: "@b9g/filesystem/node-fs",
|
|
126
|
+
export: "NodeFSDirectory",
|
|
127
|
+
path: "[outdir]/server"
|
|
128
|
+
},
|
|
129
|
+
public: {
|
|
130
|
+
module: "@b9g/filesystem/node-fs",
|
|
131
|
+
export: "NodeFSDirectory",
|
|
132
|
+
path: "[outdir]/public"
|
|
133
|
+
},
|
|
134
|
+
tmp: {
|
|
135
|
+
module: "@b9g/filesystem/node-fs",
|
|
136
|
+
export: "NodeFSDirectory",
|
|
137
|
+
path: "[tmpdir]"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async function createDevServer(options) {
|
|
143
|
+
const { port, host, workerPath, workers = 1 } = options;
|
|
144
|
+
logger.info("Starting Bun dev server", { workerPath, workers });
|
|
145
|
+
const { default: BunPlatform } = await import("./index.js");
|
|
146
|
+
const platform = new BunPlatform({
|
|
147
|
+
port,
|
|
148
|
+
host,
|
|
149
|
+
workers
|
|
150
|
+
});
|
|
151
|
+
await platform.serviceWorker.register(workerPath);
|
|
152
|
+
await platform.serviceWorker.ready;
|
|
153
|
+
await platform.listen();
|
|
154
|
+
logger.info("Bun dev server ready");
|
|
155
|
+
const url = `http://${host}:${port}`;
|
|
156
|
+
return {
|
|
157
|
+
url,
|
|
158
|
+
async reload(newWorkerPath) {
|
|
159
|
+
logger.info("Reloading workers", { workerPath: newWorkerPath });
|
|
160
|
+
await platform.serviceWorker.reloadWorkers(newWorkerPath);
|
|
161
|
+
logger.info("Workers reloaded");
|
|
162
|
+
},
|
|
163
|
+
async close() {
|
|
164
|
+
logger.info("Stopping Bun dev server");
|
|
165
|
+
await platform.dispose();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
createDevServer,
|
|
171
|
+
getDefaults,
|
|
172
|
+
getESBuildConfig,
|
|
173
|
+
getEntryPoints,
|
|
174
|
+
name
|
|
175
|
+
};
|