@b9g/platform-node 0.1.2 → 0.1.3

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-node",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Node.js platform adapter for Shovel with hot reloading and ESBuild integration",
5
5
  "keywords": [
6
6
  "shovel",
@@ -11,8 +11,8 @@
11
11
  "esbuild"
12
12
  ],
13
13
  "dependencies": {
14
- "@b9g/platform": "^0.1.1",
15
- "@b9g/cache": "^0.1.1",
14
+ "@b9g/platform": "workspace:*",
15
+ "@b9g/cache": "workspace:*",
16
16
  "@remix-run/node-fetch-server": "^0.11.0",
17
17
  "@aws-sdk/client-s3": "^3.0.0"
18
18
  },
package/src/platform.d.ts CHANGED
@@ -23,7 +23,7 @@ export interface NodePlatformOptions extends PlatformConfig {
23
23
  export declare class NodePlatform extends BasePlatform {
24
24
  readonly name = "node";
25
25
  private options;
26
- private workerManager?;
26
+ private workerPool?;
27
27
  private cacheStorage?;
28
28
  constructor(options?: NodePlatformOptions);
29
29
  /**
@@ -41,7 +41,7 @@ export declare class NodePlatform extends BasePlatform {
41
41
  protected getDefaultCacheConfig(): CacheConfig;
42
42
  /**
43
43
  * SUPPORTING UTILITY - Create cache storage optimized for Node.js
44
- * Now uses the base class implementation with dynamic loading
44
+ * Uses MemoryCache in main thread, PostMessageCache in workers
45
45
  */
46
46
  createCaches(config?: CacheConfig): Promise<CustomCacheStorage>;
47
47
  /**
@@ -52,6 +52,10 @@ export declare class NodePlatform extends BasePlatform {
52
52
  * Get filesystem root for File System Access API
53
53
  */
54
54
  getFileSystemRoot(name?: string): Promise<FileSystemDirectoryHandle>;
55
+ /**
56
+ * Reload workers for hot reloading (called by CLI)
57
+ */
58
+ reloadWorkers(version?: number | string): Promise<void>;
55
59
  /**
56
60
  * Dispose of platform resources
57
61
  */
package/src/platform.js CHANGED
@@ -3,157 +3,41 @@
3
3
  import {
4
4
  BasePlatform
5
5
  } from "@b9g/platform";
6
- import { CustomCacheStorage, MemoryCacheManager, PostMessageCache } from "@b9g/cache";
7
- import { FileSystemRegistry, getFileSystemRoot, NodeFileSystemAdapter } from "@b9g/filesystem";
6
+ import { WorkerPool } from "@b9g/platform/worker-pool";
7
+ import { CustomCacheStorage, MemoryCache, MemoryCacheManager, PostMessageCache } from "@b9g/cache";
8
+ import { FileSystemRegistry, getDirectoryHandle, LocalBucket } from "@b9g/filesystem";
8
9
  import * as Http from "http";
9
10
  import * as Path from "path";
10
- import { Worker } from "worker_threads";
11
- import { fileURLToPath } from "url";
12
- var __filename = fileURLToPath(import.meta.url);
13
- var __dirname = Path.dirname(__filename);
14
- var WorkerManager = class {
15
- constructor(cacheStorage, options, workerCount = 1, entrypoint) {
16
- this.entrypoint = entrypoint;
17
- this.memoryCacheManager = new MemoryCacheManager();
18
- this.options = options;
19
- console.info(
20
- "[WorkerManager] Constructor called with entrypoint:",
21
- entrypoint
22
- );
23
- this.initWorkers(workerCount);
24
- }
25
- workers = [];
26
- currentWorker = 0;
27
- requestId = 0;
28
- pendingRequests = /* @__PURE__ */ new Map();
11
+ var NodeWorkerPool = class extends WorkerPool {
29
12
  memoryCacheManager;
30
- options;
31
- initWorkers(count) {
32
- for (let i = 0; i < count; i++) {
33
- this.createWorker();
34
- }
35
- }
36
- createWorker() {
37
- let workerScript;
38
- try {
39
- const workerUrl = import.meta.resolve("@b9g/shovel/worker.js");
40
- workerScript = fileURLToPath(workerUrl);
41
- } catch (error) {
42
- throw new Error(
43
- `Could not resolve @b9g/shovel/worker.js: ${error.message}`
44
- );
45
- }
46
- const worker = new Worker(workerScript);
47
- worker.on("message", (message) => {
48
- if (message.type?.startsWith("cache:")) {
49
- this.memoryCacheManager.handleMessage(worker, message);
50
- } else {
51
- this.handleWorkerMessage(message);
52
- }
53
- });
54
- worker.on("error", (error) => {
55
- console.error("[Platform-Node] Worker error:", error);
56
- });
57
- this.workers.push(worker);
58
- return worker;
59
- }
60
- handleWorkerMessage(message) {
61
- if (message.type === "response" && message.requestId) {
62
- const pending = this.pendingRequests.get(message.requestId);
63
- if (pending) {
64
- const response = new Response(message.response.body, {
65
- status: message.response.status,
66
- statusText: message.response.statusText,
67
- headers: message.response.headers
68
- });
69
- pending.resolve(response);
70
- this.pendingRequests.delete(message.requestId);
71
- }
72
- } else if (message.type === "error" && message.requestId) {
73
- const pending = this.pendingRequests.get(message.requestId);
74
- if (pending) {
75
- pending.reject(new Error(message.error));
76
- this.pendingRequests.delete(message.requestId);
77
- }
78
- } else if (message.type === "ready") {
79
- console.info(`[Platform-Node] ServiceWorker ready (v${message.version})`);
80
- } else if (message.type === "worker-ready") {
81
- console.info("[Platform-Node] Worker initialized");
82
- }
83
- }
84
- /**
85
- * Handle HTTP request using round-robin Worker selection
86
- */
87
- async handleRequest(request) {
88
- const worker = this.workers[this.currentWorker];
13
+ constructor(cacheStorage, poolOptions, appEntrypoint) {
14
+ super(cacheStorage, poolOptions, appEntrypoint);
15
+ this.memoryCacheManager = new MemoryCacheManager();
89
16
  console.info(
90
- `[WorkerManager] Dispatching to worker ${this.currentWorker} of ${this.workers.length}`
17
+ "[NodeWorkerPool] Initialized with entrypoint:",
18
+ appEntrypoint
91
19
  );
92
- this.currentWorker = (this.currentWorker + 1) % this.workers.length;
93
- const requestId = ++this.requestId;
94
- return new Promise((resolve2, reject) => {
95
- this.pendingRequests.set(requestId, { resolve: resolve2, reject });
96
- worker.postMessage({
97
- type: "request",
98
- request: {
99
- url: request.url,
100
- method: request.method,
101
- headers: Object.fromEntries(request.headers.entries()),
102
- body: request.body
103
- },
104
- requestId
105
- });
106
- setTimeout(() => {
107
- if (this.pendingRequests.has(requestId)) {
108
- this.pendingRequests.delete(requestId);
109
- reject(new Error("Request timeout"));
110
- }
111
- }, 3e4);
112
- });
113
20
  }
114
21
  /**
115
- * Reload ServiceWorker with new version (hot reload simulation)
22
+ * Handle Node.js-specific cache coordination
116
23
  */
117
- async reloadWorkers(version = Date.now()) {
118
- console.info(`[Platform-Node] Reloading ServiceWorker (v${version})`);
119
- const loadPromises = this.workers.map((worker) => {
120
- return new Promise((resolve2) => {
121
- const handleReady = (message) => {
122
- if (message.type === "ready" && message.version === version) {
123
- worker.off("message", handleReady);
124
- resolve2();
125
- }
126
- };
127
- console.info("[Platform-Node] Sending load message:", {
128
- version,
129
- entrypoint: this.entrypoint
130
- });
131
- worker.on("message", handleReady);
132
- worker.postMessage({
133
- type: "load",
134
- version,
135
- entrypoint: this.entrypoint
136
- });
137
- });
138
- });
139
- await Promise.all(loadPromises);
140
- console.info(`[Platform-Node] All Workers reloaded (v${version})`);
24
+ handleCacheMessage(message) {
25
+ if (message.type?.startsWith("cache:")) {
26
+ console.warn("[NodeWorkerPool] Cache coordination not fully implemented in abstraction");
27
+ }
141
28
  }
142
29
  /**
143
- * Graceful shutdown
30
+ * Enhanced termination with memory cache cleanup
144
31
  */
145
32
  async terminate() {
146
- const terminatePromises = this.workers.map((worker) => worker.terminate());
147
- await Promise.allSettled(terminatePromises);
33
+ await super.terminate();
148
34
  await this.memoryCacheManager.dispose();
149
- this.workers = [];
150
- this.pendingRequests.clear();
151
35
  }
152
36
  };
153
37
  var NodePlatform = class extends BasePlatform {
154
38
  name = "node";
155
39
  options;
156
- workerManager;
40
+ workerPool;
157
41
  cacheStorage;
158
42
  constructor(options = {}) {
159
43
  super(options);
@@ -164,7 +48,7 @@ var NodePlatform = class extends BasePlatform {
164
48
  cwd: process.cwd(),
165
49
  ...options
166
50
  };
167
- FileSystemRegistry.register("node", new NodeFileSystemAdapter({
51
+ FileSystemRegistry.register("node", new LocalBucket({
168
52
  rootPath: this.options.cwd
169
53
  }));
170
54
  }
@@ -173,7 +57,7 @@ var NodePlatform = class extends BasePlatform {
173
57
  */
174
58
  async getDirectoryHandle(name) {
175
59
  const distPath = Path.resolve(this.options.cwd, "dist");
176
- const adapter = new NodeFileSystemAdapter({ rootPath: distPath });
60
+ const adapter = new LocalBucket({ rootPath: distPath });
177
61
  return await adapter.getDirectoryHandle(name);
178
62
  }
179
63
  /**
@@ -185,29 +69,34 @@ var NodePlatform = class extends BasePlatform {
185
69
  if (!this.cacheStorage) {
186
70
  this.cacheStorage = await this.createCaches(options.caches);
187
71
  }
188
- if (this.workerManager) {
189
- await this.workerManager.terminate();
72
+ if (this.workerPool) {
73
+ await this.workerPool.terminate();
190
74
  }
191
75
  const workerCount = options.workerCount || 1;
192
76
  console.info(
193
- "[Platform-Node] Creating WorkerManager with entryPath:",
77
+ "[Platform-Node] Creating NodeWorkerPool with entryPath:",
194
78
  entryPath
195
79
  );
196
- this.workerManager = new WorkerManager(
80
+ this.workerPool = new NodeWorkerPool(
197
81
  this.cacheStorage,
198
- this.options,
199
- workerCount,
82
+ {
83
+ workerCount,
84
+ requestTimeout: 3e4,
85
+ hotReload: this.options.hotReload,
86
+ cwd: this.options.cwd
87
+ },
200
88
  entryPath
201
89
  );
90
+ await this.workerPool.init();
202
91
  const version = Date.now();
203
- await this.workerManager.reloadWorkers(version);
92
+ await this.workerPool.reloadWorkers(version);
204
93
  const instance = {
205
- runtime: this.workerManager,
94
+ runtime: this.workerPool,
206
95
  handleRequest: async (request) => {
207
- if (!this.workerManager) {
208
- throw new Error("WorkerManager not initialized");
96
+ if (!this.workerPool) {
97
+ throw new Error("NodeWorkerPool not initialized");
209
98
  }
210
- return this.workerManager.handleRequest(request);
99
+ return this.workerPool.handleRequest(request);
211
100
  },
212
101
  install: async () => {
213
102
  console.info(
@@ -223,12 +112,12 @@ var NodePlatform = class extends BasePlatform {
223
112
  return [];
224
113
  },
225
114
  get ready() {
226
- return this.workerManager !== void 0;
115
+ return this.workerPool?.ready ?? false;
227
116
  },
228
117
  dispose: async () => {
229
- if (this.workerManager) {
230
- await this.workerManager.terminate();
231
- this.workerManager = void 0;
118
+ if (this.workerPool) {
119
+ await this.workerPool.terminate();
120
+ this.workerPool = void 0;
232
121
  }
233
122
  console.info("[Platform-Node] ServiceWorker disposed");
234
123
  }
@@ -251,16 +140,24 @@ var NodePlatform = class extends BasePlatform {
251
140
  }
252
141
  /**
253
142
  * SUPPORTING UTILITY - Create cache storage optimized for Node.js
254
- * Now uses the base class implementation with dynamic loading
143
+ * Uses MemoryCache in main thread, PostMessageCache in workers
255
144
  */
256
145
  async createCaches(config) {
257
- const cacheStorage = await super.createCaches(config);
146
+ const { isMainThread } = await import("worker_threads");
258
147
  return new CustomCacheStorage((name) => {
259
- return new PostMessageCache(name, {
260
- maxEntries: 1e3,
261
- maxSize: 50 * 1024 * 1024
262
- // 50MB
263
- });
148
+ if (isMainThread) {
149
+ return new MemoryCache(name, {
150
+ maxEntries: 1e3,
151
+ maxAge: 60 * 60 * 1e3
152
+ // 1 hour
153
+ });
154
+ } else {
155
+ return new PostMessageCache(name, {
156
+ maxEntries: 1e3,
157
+ maxAge: 60 * 60 * 1e3
158
+ // 1 hour
159
+ });
160
+ }
264
161
  });
265
162
  }
266
163
  /**
@@ -337,15 +234,23 @@ var NodePlatform = class extends BasePlatform {
337
234
  * Get filesystem root for File System Access API
338
235
  */
339
236
  async getFileSystemRoot(name = "default") {
340
- return await getFileSystemRoot(name);
237
+ return await getDirectoryHandle(name);
238
+ }
239
+ /**
240
+ * Reload workers for hot reloading (called by CLI)
241
+ */
242
+ async reloadWorkers(version) {
243
+ if (this.workerPool) {
244
+ await this.workerPool.reloadWorkers(version);
245
+ }
341
246
  }
342
247
  /**
343
248
  * Dispose of platform resources
344
249
  */
345
250
  async dispose() {
346
- if (this.workerManager) {
347
- await this.workerManager.terminate();
348
- this.workerManager = void 0;
251
+ if (this.workerPool) {
252
+ await this.workerPool.terminate();
253
+ this.workerPool = void 0;
349
254
  }
350
255
  }
351
256
  };