@b9g/platform 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -213,7 +213,7 @@ const platform = new CloudflarePlatform({
213
213
 
214
214
  ### Re-exports from @b9g/filesystem
215
215
 
216
- - `BucketStorage`, `Bucket`, `BucketFactory`, `CustomBucketStorage`
216
+ - `DirectoryStorage`, `Directory`, `DirectoryFactory`, `CustomDirectoryStorage`
217
217
 
218
218
  ### Re-exports from @b9g/cache
219
219
 
@@ -0,0 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ export {
10
+ __require
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/platform",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "ServiceWorker-first universal deployment platform. Write ServiceWorker apps once, deploy anywhere (Node/Bun/Cloudflare). Registry-based multi-app orchestration.",
5
5
  "keywords": [
6
6
  "serviceworker",
@@ -15,15 +15,39 @@
15
15
  "shovel"
16
16
  ],
17
17
  "dependencies": {
18
- "@b9g/async-context": "^0.1.1",
19
- "@b9g/cache": "^0.1.4",
20
- "@b9g/filesystem": "^0.1.6",
18
+ "@b9g/async-context": "^0.1.4",
19
+ "@b9g/cache": "^0.1.5",
20
+ "@b9g/filesystem": "^0.1.7",
21
21
  "@logtape/logtape": "^1.2.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@b9g/libuild": "^0.1.11",
24
+ "@b9g/libuild": "^0.1.18",
25
25
  "bun-types": "latest"
26
26
  },
27
+ "peerDependencies": {
28
+ "@logtape/file": "^1.0.0",
29
+ "@logtape/otel": "^1.0.0",
30
+ "@logtape/sentry": "^1.0.0",
31
+ "@logtape/syslog": "^1.0.0",
32
+ "@logtape/cloudwatch-logs": "^1.0.0"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "@logtape/file": {
36
+ "optional": true
37
+ },
38
+ "@logtape/otel": {
39
+ "optional": true
40
+ },
41
+ "@logtape/sentry": {
42
+ "optional": true
43
+ },
44
+ "@logtape/syslog": {
45
+ "optional": true
46
+ },
47
+ "@logtape/cloudwatch-logs": {
48
+ "optional": true
49
+ }
50
+ },
27
51
  "type": "module",
28
52
  "types": "src/index.d.ts",
29
53
  "module": "src/index.js",
@@ -33,14 +57,6 @@
33
57
  "import": "./src/index.js"
34
58
  },
35
59
  "./package.json": "./package.json",
36
- "./worker-pool": {
37
- "types": "./src/worker-pool.d.ts",
38
- "import": "./src/worker-pool.js"
39
- },
40
- "./worker-pool.js": {
41
- "types": "./src/worker-pool.d.ts",
42
- "import": "./src/worker-pool.js"
43
- },
44
60
  "./runtime": {
45
61
  "types": "./src/runtime.d.ts",
46
62
  "import": "./src/runtime.js"
@@ -49,21 +65,13 @@
49
65
  "types": "./src/runtime.d.ts",
50
66
  "import": "./src/runtime.js"
51
67
  },
52
- "./config": {
53
- "types": "./src/config.d.ts",
54
- "import": "./src/config.js"
55
- },
56
- "./config.js": {
57
- "types": "./src/config.d.ts",
58
- "import": "./src/config.js"
68
+ "./worker": {
69
+ "types": "./src/worker.d.ts",
70
+ "import": "./src/worker.js"
59
71
  },
60
- "./cookie-store": {
61
- "types": "./src/cookie-store.d.ts",
62
- "import": "./src/cookie-store.js"
63
- },
64
- "./cookie-store.js": {
65
- "types": "./src/cookie-store.d.ts",
66
- "import": "./src/cookie-store.js"
72
+ "./worker.js": {
73
+ "types": "./src/worker.d.ts",
74
+ "import": "./src/worker.js"
67
75
  },
68
76
  "./index": {
69
77
  "types": "./src/index.d.ts",
@@ -72,14 +80,6 @@
72
80
  "./index.js": {
73
81
  "types": "./src/index.d.ts",
74
82
  "import": "./src/index.js"
75
- },
76
- "./single-threaded": {
77
- "types": "./src/single-threaded.d.ts",
78
- "import": "./src/single-threaded.js"
79
- },
80
- "./single-threaded.js": {
81
- "types": "./src/single-threaded.d.ts",
82
- "import": "./src/single-threaded.js"
83
83
  }
84
84
  }
85
85
  }
package/src/index.d.ts CHANGED
@@ -3,7 +3,14 @@
3
3
  *
4
4
  * Platform = "ServiceWorker entrypoint loader for JavaScript runtimes"
5
5
  * Core responsibility: Take a ServiceWorker-style app file and make it run in this environment.
6
+ *
7
+ * This module contains:
8
+ * - Platform interface and base classes
9
+ * - SingleThreadedRuntime for main-thread execution
10
+ * - ServiceWorkerPool for multi-worker execution
6
11
  */
12
+ import type { DirectoryStorage } from "@b9g/filesystem";
13
+ import { CustomLoggerStorage, type LoggerStorage } from "./runtime.js";
7
14
  /**
8
15
  * Platform configuration
9
16
  * Extended by platform-specific implementations (NodePlatformOptions, etc.)
@@ -76,6 +83,35 @@ export interface ServiceWorkerInstance {
76
83
  /** Dispose of resources */
77
84
  dispose(): Promise<void>;
78
85
  }
86
+ /**
87
+ * Options for getEntryWrapper()
88
+ * Reserved for future platform-specific options.
89
+ */
90
+ export interface EntryWrapperOptions {
91
+ }
92
+ /**
93
+ * Esbuild configuration subset that platforms can customize
94
+ */
95
+ export interface PlatformEsbuildConfig {
96
+ /** Target platform: "node" or "browser" */
97
+ platform?: "node" | "browser" | "neutral";
98
+ /** Export conditions for package.json resolution */
99
+ conditions?: string[];
100
+ /** External modules to exclude from bundle */
101
+ external?: string[];
102
+ /** Compile-time defines */
103
+ define?: Record<string, string>;
104
+ /**
105
+ * Whether the entry wrapper imports user code inline (bundled together)
106
+ * or references it as a separate file (loaded at runtime).
107
+ *
108
+ * - true: User code is imported inline (e.g., Cloudflare: `import "user-entry"`)
109
+ * - false: User code is loaded separately (e.g., Node/Bun: `loadServiceWorker("./server.js")`)
110
+ *
111
+ * Default: false (separate build)
112
+ */
113
+ bundlesUserCodeInline?: boolean;
114
+ }
79
115
  /**
80
116
  * Platform interface - ServiceWorker entrypoint loader for JavaScript runtimes
81
117
  *
@@ -100,6 +136,28 @@ export interface Platform {
100
136
  * SUPPORTING UTILITY - Create server instance for this platform
101
137
  */
102
138
  createServer(handler: Handler, options?: ServerOptions): Server;
139
+ /**
140
+ * BUILD SUPPORT - Get virtual entry wrapper template for user code
141
+ *
142
+ * Returns a JavaScript/TypeScript string that:
143
+ * 1. Initializes platform-specific runtime (polyfills, globals)
144
+ * 2. Imports the user's entrypoint
145
+ * 3. Exports any required handlers (e.g., ES module export for Cloudflare)
146
+ *
147
+ * The CLI uses this to create a virtual entry point for bundling.
148
+ * Every platform must provide a wrapper - there is no "raw user code" mode.
149
+ *
150
+ * @param entryPath - Absolute path to user's entrypoint file
151
+ * @param options - Additional options
152
+ */
153
+ getEntryWrapper(entryPath: string, options?: EntryWrapperOptions): string;
154
+ /**
155
+ * BUILD SUPPORT - Get platform-specific esbuild configuration
156
+ *
157
+ * Returns partial esbuild config that the CLI merges with common settings.
158
+ * Includes platform target, conditions, externals, and defines.
159
+ */
160
+ getEsbuildConfig(): PlatformEsbuildConfig;
103
161
  }
104
162
  /**
105
163
  * Platform registry - internal implementation
@@ -126,24 +184,24 @@ export declare function detectRuntime(): "bun" | "deno" | "node";
126
184
  */
127
185
  export declare function detectDeploymentPlatform(): string | null;
128
186
  /**
129
- * Detect platform for development
130
- *
131
- * Priority:
132
- * 1. Check package.json for installed @b9g/platform-* package
133
- * 2. Fallback to current runtime (bun/node/deno)
187
+ * Detect platform for development based on current runtime
134
188
  */
135
189
  export declare function detectDevelopmentPlatform(): string;
136
190
  /**
137
- * Resolve platform name from options or auto-detect
191
+ * Resolve platform name from options, config, or auto-detect
138
192
  *
139
193
  * Priority:
140
- * 1. Explicit --platform or --target flag
141
- * 2. Deployment platform detection (production environments)
142
- * 3. Development platform detection (local runtime)
194
+ * 1. Explicit --platform or --target CLI flag
195
+ * 2. shovel.json or package.json "shovel.platform" field
196
+ * 3. Deployment platform detection (production environments)
197
+ * 4. Development platform detection (local runtime)
143
198
  */
144
199
  export declare function resolvePlatform(options: {
145
200
  platform?: string;
146
201
  target?: string;
202
+ config?: {
203
+ platform?: string;
204
+ };
147
205
  }): string;
148
206
  /**
149
207
  * Create platform instance based on name
@@ -164,6 +222,16 @@ export declare abstract class BasePlatform implements Platform {
164
222
  * Returns empty CacheStorage - applications create caches on-demand via caches.open()
165
223
  */
166
224
  createCaches(): Promise<CacheStorage>;
225
+ /**
226
+ * Get virtual entry wrapper template for user code
227
+ * Subclasses must override to provide platform-specific wrappers
228
+ */
229
+ abstract getEntryWrapper(entryPath: string, options?: EntryWrapperOptions): string;
230
+ /**
231
+ * Get platform-specific esbuild configuration
232
+ * Subclasses should override to provide platform-specific config
233
+ */
234
+ abstract getEsbuildConfig(): PlatformEsbuildConfig;
167
235
  }
168
236
  /**
169
237
  * Global platform registry
@@ -187,9 +255,150 @@ export declare function getPlatform(name?: string): Platform;
187
255
  * Get platform with async auto-registration fallback
188
256
  */
189
257
  export declare function getPlatformAsync(name?: string): Promise<Platform>;
190
- export { ServiceWorkerPool, type WorkerPoolOptions, type WorkerMessage, type WorkerRequest, type WorkerResponse, type WorkerLoadMessage, type WorkerReadyMessage, type WorkerErrorMessage, type WorkerInitMessage, type WorkerInitializedMessage, } from "./worker-pool.js";
191
- export { SingleThreadedRuntime, type SingleThreadedRuntimeOptions, } from "./single-threaded.js";
192
- export { ShovelServiceWorkerRegistration, ShovelGlobalScope, FetchEvent, InstallEvent, ActivateEvent, ExtendableEvent, } from "./runtime.js";
193
- export { RequestCookieStore, type CookieListItem, type CookieInit, type CookieStoreGetOptions, type CookieStoreDeleteOptions, type CookieSameSite, type CookieList, parseCookieHeader, serializeCookie, parseSetCookieHeader, } from "./cookie-store.js";
194
- export { CustomBucketStorage } from "@b9g/filesystem";
195
- export { loadConfig, configureLogging, getCacheConfig, getBucketConfig, parseConfigExpr, processConfigValue, matchPattern, createBucketFactory, createCacheFactory, type ShovelConfig, type CacheConfig, type BucketConfig, type LoggingConfig, type LogLevel, type BucketFactoryOptions, type CacheFactoryOptions, type ProcessedShovelConfig, } from "./config.js";
258
+ /**
259
+ * Common interface for ServiceWorker runtimes
260
+ */
261
+ export interface ServiceWorkerRuntime {
262
+ init(): Promise<void>;
263
+ load(entrypoint: string): Promise<void>;
264
+ handleRequest(request: Request): Promise<Response>;
265
+ terminate(): Promise<void>;
266
+ readonly workerCount: number;
267
+ readonly ready: boolean;
268
+ }
269
+ export interface SingleThreadedRuntimeOptions {
270
+ /** Cache storage for the runtime */
271
+ caches: CacheStorage;
272
+ /** Directory storage for the runtime */
273
+ directories: DirectoryStorage;
274
+ /** Logger storage for the runtime */
275
+ loggers: LoggerStorage;
276
+ }
277
+ /**
278
+ * Single-threaded ServiceWorker runtime
279
+ *
280
+ * Runs ServiceWorker code directly in the main thread.
281
+ * Implements ServiceWorkerRuntime interface for interchangeability with ServiceWorkerPool.
282
+ */
283
+ export declare class SingleThreadedRuntime implements ServiceWorkerRuntime {
284
+ #private;
285
+ constructor(options: SingleThreadedRuntimeOptions);
286
+ /**
287
+ * Initialize the runtime (install ServiceWorker globals)
288
+ */
289
+ init(): Promise<void>;
290
+ /**
291
+ * Load (or reload) a ServiceWorker entrypoint
292
+ * @param entrypoint - Path to the entrypoint file (content-hashed filename)
293
+ */
294
+ load(entrypoint: string): Promise<void>;
295
+ /**
296
+ * Handle an HTTP request
297
+ * This is the key method - direct call, no postMessage!
298
+ */
299
+ handleRequest(request: Request): Promise<Response>;
300
+ /**
301
+ * Graceful shutdown
302
+ */
303
+ terminate(): Promise<void>;
304
+ /**
305
+ * Get the number of workers (always 1 for single-threaded)
306
+ */
307
+ get workerCount(): number;
308
+ /**
309
+ * Check if ready to handle requests
310
+ */
311
+ get ready(): boolean;
312
+ }
313
+ /**
314
+ * Worker pool options
315
+ */
316
+ export interface WorkerPoolOptions {
317
+ /** Number of workers in the pool (default: 1) */
318
+ workerCount?: number;
319
+ /** Request timeout in milliseconds (default: 30000) */
320
+ requestTimeout?: number;
321
+ /** Working directory for file resolution */
322
+ cwd?: string;
323
+ }
324
+ export interface WorkerMessage {
325
+ type: string;
326
+ [key: string]: any;
327
+ }
328
+ export interface WorkerRequest extends WorkerMessage {
329
+ type: "request";
330
+ request: {
331
+ url: string;
332
+ method: string;
333
+ headers: Record<string, string>;
334
+ body?: ArrayBuffer | null;
335
+ };
336
+ requestID: number;
337
+ }
338
+ export interface WorkerResponse extends WorkerMessage {
339
+ type: "response";
340
+ response: {
341
+ status: number;
342
+ statusText: string;
343
+ headers: Record<string, string>;
344
+ body: ArrayBuffer;
345
+ };
346
+ requestID: number;
347
+ }
348
+ export interface WorkerLoadMessage extends WorkerMessage {
349
+ type: "load";
350
+ entrypoint: string;
351
+ }
352
+ export interface WorkerReadyMessage extends WorkerMessage {
353
+ type: "ready" | "worker-ready";
354
+ entrypoint?: string;
355
+ }
356
+ export interface WorkerErrorMessage extends WorkerMessage {
357
+ type: "error";
358
+ error: string;
359
+ stack?: string;
360
+ requestID?: number;
361
+ }
362
+ export interface WorkerInitMessage extends WorkerMessage {
363
+ type: "init";
364
+ config: any;
365
+ baseDir: string;
366
+ }
367
+ export interface WorkerInitializedMessage extends WorkerMessage {
368
+ type: "initialized";
369
+ }
370
+ /**
371
+ * ServiceWorkerPool - manages a pool of ServiceWorker instances
372
+ * Handles HTTP request/response routing, cache coordination, and hot reloading
373
+ */
374
+ export declare class ServiceWorkerPool {
375
+ #private;
376
+ constructor(options?: WorkerPoolOptions, appEntrypoint?: string, cacheStorage?: CacheStorage, config?: any);
377
+ /**
378
+ * Initialize workers (must be called after construction)
379
+ */
380
+ init(): Promise<void>;
381
+ /**
382
+ * Handle HTTP request using round-robin worker selection
383
+ */
384
+ handleRequest(request: Request): Promise<Response>;
385
+ /**
386
+ * Reload ServiceWorker with new entrypoint (hot reload)
387
+ * The entrypoint path contains a content hash for cache busting
388
+ */
389
+ reloadWorkers(entrypoint: string): Promise<void>;
390
+ /**
391
+ * Graceful shutdown of all workers
392
+ */
393
+ terminate(): Promise<void>;
394
+ /**
395
+ * Get the number of active workers
396
+ */
397
+ get workerCount(): number;
398
+ /**
399
+ * Check if the pool is ready to handle requests
400
+ */
401
+ get ready(): boolean;
402
+ }
403
+ export { CustomLoggerStorage, type LoggerStorage };
404
+ export type { LoggerFactory } from "./runtime.js";