flowscale 2.1.0-beta.1 → 2.1.0-beta.4

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/dist/index.d.ts CHANGED
@@ -126,3 +126,4 @@ export { FlowscalePlatformAPI } from './platform';
126
126
  export { LocalPodsAPI } from './local-pods';
127
127
  export * from './local-types';
128
128
  export * from './platform-types';
129
+ export { RemotePodsTransport } from './remote-transport';
package/dist/index.js CHANGED
@@ -73,7 +73,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
73
73
  return (mod && mod.__esModule) ? mod : { "default": mod };
74
74
  };
75
75
  Object.defineProperty(exports, "__esModule", { value: true });
76
- exports.LocalPodsAPI = exports.FlowscalePlatformAPI = exports.FlowscaleAPI = void 0;
76
+ exports.RemotePodsTransport = exports.LocalPodsAPI = exports.FlowscalePlatformAPI = exports.FlowscaleAPI = void 0;
77
77
  var axios_1 = __importDefault(require("axios"));
78
78
  var FlowscaleAPI = /** @class */ (function () {
79
79
  function FlowscaleAPI(config) {
@@ -1302,3 +1302,5 @@ var local_pods_1 = require("./local-pods");
1302
1302
  Object.defineProperty(exports, "LocalPodsAPI", { enumerable: true, get: function () { return local_pods_1.LocalPodsAPI; } });
1303
1303
  __exportStar(require("./local-types"), exports);
1304
1304
  __exportStar(require("./platform-types"), exports);
1305
+ var remote_transport_1 = require("./remote-transport");
1306
+ Object.defineProperty(exports, "RemotePodsTransport", { enumerable: true, get: function () { return remote_transport_1.RemotePodsTransport; } });
@@ -33,6 +33,12 @@ export interface LocalPodInstance {
33
33
  lastDetectedAt: number | null;
34
34
  comfyuiInfo?: ComfyUISystemStats;
35
35
  createdAt: number;
36
+ /**
37
+ * Pre-computed base URL for reaching this instance.
38
+ * Set by RemotePodsTransport to `http://operatorHost:port`.
39
+ * When undefined, consumers should fall back to `http://localhost:port`.
40
+ */
41
+ baseUrl?: string;
36
42
  }
37
43
  export interface LocalPod {
38
44
  id: string;
@@ -0,0 +1,2 @@
1
+ export { NodePodsTransport } from './node-transport';
2
+ export { PodsOperatorServer } from './operator-server';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PodsOperatorServer = exports.NodePodsTransport = void 0;
4
+ var node_transport_1 = require("./node-transport");
5
+ Object.defineProperty(exports, "NodePodsTransport", { enumerable: true, get: function () { return node_transport_1.NodePodsTransport; } });
6
+ var operator_server_1 = require("./operator-server");
7
+ Object.defineProperty(exports, "PodsOperatorServer", { enumerable: true, get: function () { return operator_server_1.PodsOperatorServer; } });
@@ -0,0 +1,80 @@
1
+ import type { LocalPodsTransport, LocalPod, LocalPodInstance, LocalPodDevice, LocalPodInstanceStatus, SystemInfo, ComfyUISystemStats, CreateLocalPodRequest, UpdateLocalPodRequest, StartInstanceRequest } from './local-types';
2
+ /**
3
+ * NodePodsTransport — manages local pod data in a shared SQLite DB at
4
+ * `~/.flowscale/pods.db` (or a custom path).
5
+ *
6
+ * Implements CRUD for pods and instances. Process-lifecycle methods
7
+ * (startInstance, stopInstance, etc.) are NOT implemented here; they
8
+ * must be provided by the consuming application (e.g. creativeflow-electron).
9
+ *
10
+ * Export path: `flowscale/node`
11
+ */
12
+ export declare class NodePodsTransport implements LocalPodsTransport {
13
+ /** The underlying better-sqlite3 database handle */
14
+ private db;
15
+ private emitter;
16
+ constructor(dbPath?: string);
17
+ private _initSchema;
18
+ create(data: CreateLocalPodRequest): Promise<LocalPod>;
19
+ list(): Promise<LocalPod[]>;
20
+ get(id: string): Promise<LocalPod | null>;
21
+ update(id: string, data: UpdateLocalPodRequest): Promise<LocalPod>;
22
+ delete(id: string): Promise<void>;
23
+ /**
24
+ * Insert a new instance row and return the hydrated LocalPodInstance.
25
+ * Used by process-management code (e.g. startInstance in electron).
26
+ */
27
+ dbInsertInstance(data: {
28
+ id: string;
29
+ podId: string;
30
+ port: number;
31
+ device: LocalPodDevice;
32
+ status: LocalPodInstanceStatus;
33
+ pid: number | null;
34
+ lastDetectedAt: number | null;
35
+ createdAt: number;
36
+ }): LocalPodInstance;
37
+ /**
38
+ * Update specific fields of an instance row.
39
+ * Used by process-management code for status/pid updates.
40
+ */
41
+ dbUpdateInstance(id: string, updates: {
42
+ status?: LocalPodInstanceStatus;
43
+ pid?: number | null;
44
+ lastDetectedAt?: number | null;
45
+ device?: LocalPodDevice;
46
+ }): void;
47
+ /** Get a single instance row by ID. */
48
+ dbGetInstance(id: string): LocalPodInstance | null;
49
+ /** Get all instances for a given pod. */
50
+ dbGetInstancesForPod(podId: string): LocalPodInstance[];
51
+ /** Get all instance rows across all pods. */
52
+ dbGetAllInstances(): LocalPodInstance[];
53
+ /** Get a raw pod row (for accessing comfyuiPath etc in process-mgmt code). */
54
+ dbGetPodRow(id: string): {
55
+ id: string;
56
+ comfyuiPath: string | null;
57
+ } | null;
58
+ deleteInstance(instanceId: string): Promise<void>;
59
+ refreshInstance(instanceId: string): Promise<LocalPodInstance>;
60
+ onInstanceStatusChanged(cb: (instanceId: string, status: LocalPodInstanceStatus, info?: ComfyUISystemStats) => void): () => void;
61
+ onLog(cb: (instanceId: string, line: string) => void): () => void;
62
+ /** Emit an instanceStatusChanged event (called by subclasses / process-lifecycle code). */
63
+ emitInstanceStatusChanged(instanceId: string, status: LocalPodInstanceStatus, info?: ComfyUISystemStats): void;
64
+ /** Emit a log event (called by subclasses / process-lifecycle code). */
65
+ emitLog(instanceId: string, line: string): void;
66
+ scanPaths(): Promise<string | null>;
67
+ scanPorts(_podId: string): Promise<LocalPodInstance[]>;
68
+ startInstance(_req: StartInstanceRequest): Promise<LocalPodInstance>;
69
+ stopInstance(_instanceId: string): Promise<void>;
70
+ restartInstance(_instanceId: string): Promise<void>;
71
+ getSystemInfo(): Promise<SystemInfo>;
72
+ getLogs(_instanceId: string): Promise<string[]>;
73
+ installRocmPyTorch(_podId: string): void;
74
+ onRocmSetupDone(_cb: (data: {
75
+ podId: string;
76
+ success: boolean;
77
+ }) => void): () => void;
78
+ private _getInstancesForPod;
79
+ private _probePort;
80
+ }
@@ -0,0 +1,400 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ Object.defineProperty(exports, "__esModule", { value: true });
72
+ exports.NodePodsTransport = void 0;
73
+ var path = __importStar(require("path"));
74
+ var os = __importStar(require("os"));
75
+ var fs = __importStar(require("fs"));
76
+ var crypto_1 = require("crypto");
77
+ var events_1 = require("events");
78
+ // ── Helpers ────────────────────────────────────────────────────────────────────
79
+ function rowToInstance(row) {
80
+ var _a, _b;
81
+ return {
82
+ id: row.id,
83
+ podId: row.pod_id,
84
+ port: row.port,
85
+ device: JSON.parse(row.device),
86
+ status: row.status,
87
+ pid: (_a = row.pid) !== null && _a !== void 0 ? _a : null,
88
+ lastDetectedAt: (_b = row.last_detected_at) !== null && _b !== void 0 ? _b : null,
89
+ createdAt: row.created_at,
90
+ };
91
+ }
92
+ function rowToPod(row, instances) {
93
+ var _a, _b;
94
+ return {
95
+ id: row.id,
96
+ name: row.name,
97
+ description: (_a = row.description) !== null && _a !== void 0 ? _a : undefined,
98
+ comfyuiPath: (_b = row.comfyui_path) !== null && _b !== void 0 ? _b : null,
99
+ instances: instances,
100
+ createdAt: row.created_at,
101
+ updatedAt: row.updated_at,
102
+ };
103
+ }
104
+ // ── NodePodsTransport ──────────────────────────────────────────────────────────
105
+ /**
106
+ * NodePodsTransport — manages local pod data in a shared SQLite DB at
107
+ * `~/.flowscale/pods.db` (or a custom path).
108
+ *
109
+ * Implements CRUD for pods and instances. Process-lifecycle methods
110
+ * (startInstance, stopInstance, etc.) are NOT implemented here; they
111
+ * must be provided by the consuming application (e.g. creativeflow-electron).
112
+ *
113
+ * Export path: `flowscale/node`
114
+ */
115
+ var NodePodsTransport = /** @class */ (function () {
116
+ function NodePodsTransport(dbPath) {
117
+ this.emitter = new events_1.EventEmitter();
118
+ var resolvedPath = dbPath !== null && dbPath !== void 0 ? dbPath : path.join(os.homedir(), '.flowscale', 'pods.db');
119
+ // Ensure parent directory exists
120
+ fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
121
+ // Lazy-require so consumers that don't use this class don't need better-sqlite3
122
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
123
+ var Database = require('better-sqlite3');
124
+ this.db = new Database(resolvedPath);
125
+ this.db.pragma('journal_mode = WAL');
126
+ this.db.pragma('foreign_keys = ON');
127
+ this._initSchema();
128
+ }
129
+ NodePodsTransport.prototype._initSchema = function () {
130
+ this.db.exec("\n CREATE TABLE IF NOT EXISTS pods (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n description TEXT,\n comfyui_path TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pod_instances (\n id TEXT PRIMARY KEY,\n pod_id TEXT NOT NULL REFERENCES pods(id) ON DELETE CASCADE,\n port INTEGER NOT NULL,\n device TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'idle',\n pid INTEGER,\n last_detected_at INTEGER,\n created_at INTEGER NOT NULL\n );\n ");
131
+ };
132
+ // ── Pod CRUD ───────────────────────────────────────────────────────────────
133
+ NodePodsTransport.prototype.create = function (data) {
134
+ return __awaiter(this, void 0, void 0, function () {
135
+ var id, now, row;
136
+ var _a, _b;
137
+ return __generator(this, function (_c) {
138
+ id = (0, crypto_1.randomUUID)();
139
+ now = Date.now();
140
+ this.db
141
+ .prepare('INSERT INTO pods (id, name, description, comfyui_path, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
142
+ .run(id, data.name, (_a = data.description) !== null && _a !== void 0 ? _a : null, (_b = data.comfyuiPath) !== null && _b !== void 0 ? _b : null, now, now);
143
+ row = this.db.prepare('SELECT * FROM pods WHERE id = ?').get(id);
144
+ return [2 /*return*/, rowToPod(row, [])];
145
+ });
146
+ });
147
+ };
148
+ NodePodsTransport.prototype.list = function () {
149
+ return __awaiter(this, void 0, void 0, function () {
150
+ var rows;
151
+ var _this = this;
152
+ return __generator(this, function (_a) {
153
+ rows = this.db.prepare('SELECT * FROM pods ORDER BY created_at ASC').all();
154
+ return [2 /*return*/, rows.map(function (row) {
155
+ var instances = _this._getInstancesForPod(row.id);
156
+ return rowToPod(row, instances);
157
+ })];
158
+ });
159
+ });
160
+ };
161
+ NodePodsTransport.prototype.get = function (id) {
162
+ return __awaiter(this, void 0, void 0, function () {
163
+ var row, instances;
164
+ return __generator(this, function (_a) {
165
+ row = this.db.prepare('SELECT * FROM pods WHERE id = ?').get(id);
166
+ if (!row)
167
+ return [2 /*return*/, null];
168
+ instances = this._getInstancesForPod(id);
169
+ return [2 /*return*/, rowToPod(row, instances)];
170
+ });
171
+ });
172
+ };
173
+ NodePodsTransport.prototype.update = function (id, data) {
174
+ return __awaiter(this, void 0, void 0, function () {
175
+ var now, sets, values, row, instances;
176
+ var _a;
177
+ var _b, _c;
178
+ return __generator(this, function (_d) {
179
+ now = Date.now();
180
+ sets = ['updated_at = ?'];
181
+ values = [now];
182
+ if (data.name !== undefined) {
183
+ sets.push('name = ?');
184
+ values.push(data.name);
185
+ }
186
+ if (data.description !== undefined) {
187
+ sets.push('description = ?');
188
+ values.push((_b = data.description) !== null && _b !== void 0 ? _b : null);
189
+ }
190
+ if ('comfyuiPath' in data) {
191
+ sets.push('comfyui_path = ?');
192
+ values.push((_c = data.comfyuiPath) !== null && _c !== void 0 ? _c : null);
193
+ }
194
+ values.push(id);
195
+ (_a = this.db.prepare("UPDATE pods SET ".concat(sets.join(', '), " WHERE id = ?"))).run.apply(_a, values);
196
+ row = this.db.prepare('SELECT * FROM pods WHERE id = ?').get(id);
197
+ instances = this._getInstancesForPod(id);
198
+ return [2 /*return*/, rowToPod(row, instances)];
199
+ });
200
+ });
201
+ };
202
+ NodePodsTransport.prototype.delete = function (id) {
203
+ return __awaiter(this, void 0, void 0, function () {
204
+ return __generator(this, function (_a) {
205
+ this.db.prepare('DELETE FROM pods WHERE id = ?').run(id);
206
+ return [2 /*return*/];
207
+ });
208
+ });
209
+ };
210
+ // ── Instance CRUD helpers (for use by process-lifecycle code) ──────────────
211
+ /**
212
+ * Insert a new instance row and return the hydrated LocalPodInstance.
213
+ * Used by process-management code (e.g. startInstance in electron).
214
+ */
215
+ NodePodsTransport.prototype.dbInsertInstance = function (data) {
216
+ this.db
217
+ .prepare("INSERT INTO pod_instances (id, pod_id, port, device, status, pid, last_detected_at, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
218
+ .run(data.id, data.podId, data.port, JSON.stringify(data.device), data.status, data.pid, data.lastDetectedAt, data.createdAt);
219
+ var row = this.db
220
+ .prepare('SELECT * FROM pod_instances WHERE id = ?')
221
+ .get(data.id);
222
+ return rowToInstance(row);
223
+ };
224
+ /**
225
+ * Update specific fields of an instance row.
226
+ * Used by process-management code for status/pid updates.
227
+ */
228
+ NodePodsTransport.prototype.dbUpdateInstance = function (id, updates) {
229
+ var _a;
230
+ var _b, _c;
231
+ var sets = [];
232
+ var values = [];
233
+ if (updates.status !== undefined) {
234
+ sets.push('status = ?');
235
+ values.push(updates.status);
236
+ }
237
+ if ('pid' in updates) {
238
+ sets.push('pid = ?');
239
+ values.push((_b = updates.pid) !== null && _b !== void 0 ? _b : null);
240
+ }
241
+ if ('lastDetectedAt' in updates) {
242
+ sets.push('last_detected_at = ?');
243
+ values.push((_c = updates.lastDetectedAt) !== null && _c !== void 0 ? _c : null);
244
+ }
245
+ if (updates.device !== undefined) {
246
+ sets.push('device = ?');
247
+ values.push(JSON.stringify(updates.device));
248
+ }
249
+ if (sets.length === 0)
250
+ return;
251
+ values.push(id);
252
+ (_a = this.db.prepare("UPDATE pod_instances SET ".concat(sets.join(', '), " WHERE id = ?"))).run.apply(_a, values);
253
+ };
254
+ /** Get a single instance row by ID. */
255
+ NodePodsTransport.prototype.dbGetInstance = function (id) {
256
+ var row = this.db
257
+ .prepare('SELECT * FROM pod_instances WHERE id = ?')
258
+ .get(id);
259
+ return row ? rowToInstance(row) : null;
260
+ };
261
+ /** Get all instances for a given pod. */
262
+ NodePodsTransport.prototype.dbGetInstancesForPod = function (podId) {
263
+ return this._getInstancesForPod(podId);
264
+ };
265
+ /** Get all instance rows across all pods. */
266
+ NodePodsTransport.prototype.dbGetAllInstances = function () {
267
+ var rows = this.db
268
+ .prepare('SELECT * FROM pod_instances')
269
+ .all();
270
+ return rows.map(rowToInstance);
271
+ };
272
+ /** Get a raw pod row (for accessing comfyuiPath etc in process-mgmt code). */
273
+ NodePodsTransport.prototype.dbGetPodRow = function (id) {
274
+ var _a;
275
+ var row = this.db
276
+ .prepare('SELECT * FROM pods WHERE id = ?')
277
+ .get(id);
278
+ if (!row)
279
+ return null;
280
+ return { id: row.id, comfyuiPath: (_a = row.comfyui_path) !== null && _a !== void 0 ? _a : null };
281
+ };
282
+ // ── Instance interface methods ─────────────────────────────────────────────
283
+ NodePodsTransport.prototype.deleteInstance = function (instanceId) {
284
+ return __awaiter(this, void 0, void 0, function () {
285
+ return __generator(this, function (_a) {
286
+ this.db.prepare('DELETE FROM pod_instances WHERE id = ?').run(instanceId);
287
+ return [2 /*return*/];
288
+ });
289
+ });
290
+ };
291
+ NodePodsTransport.prototype.refreshInstance = function (instanceId) {
292
+ return __awaiter(this, void 0, void 0, function () {
293
+ var row, info, now, newStatus, updated, inst;
294
+ return __generator(this, function (_a) {
295
+ switch (_a.label) {
296
+ case 0:
297
+ row = this.db
298
+ .prepare('SELECT * FROM pod_instances WHERE id = ?')
299
+ .get(instanceId);
300
+ if (!row)
301
+ throw new Error("Instance ".concat(instanceId, " not found"));
302
+ return [4 /*yield*/, this._probePort(row.port)];
303
+ case 1:
304
+ info = _a.sent();
305
+ now = Date.now();
306
+ newStatus = info ? 'running' : 'idle';
307
+ this.db
308
+ .prepare('UPDATE pod_instances SET status = ?, last_detected_at = ? WHERE id = ?')
309
+ .run(newStatus, info ? now : row.last_detected_at, instanceId);
310
+ updated = this.db
311
+ .prepare('SELECT * FROM pod_instances WHERE id = ?')
312
+ .get(instanceId);
313
+ inst = rowToInstance(updated);
314
+ this.emitter.emit('instanceStatusChanged', instanceId, newStatus, info !== null && info !== void 0 ? info : undefined);
315
+ return [2 /*return*/, inst];
316
+ }
317
+ });
318
+ });
319
+ };
320
+ // ── Events ─────────────────────────────────────────────────────────────────
321
+ NodePodsTransport.prototype.onInstanceStatusChanged = function (cb) {
322
+ var _this = this;
323
+ this.emitter.on('instanceStatusChanged', cb);
324
+ return function () { return _this.emitter.off('instanceStatusChanged', cb); };
325
+ };
326
+ NodePodsTransport.prototype.onLog = function (cb) {
327
+ var _this = this;
328
+ this.emitter.on('log', cb);
329
+ return function () { return _this.emitter.off('log', cb); };
330
+ };
331
+ /** Emit an instanceStatusChanged event (called by subclasses / process-lifecycle code). */
332
+ NodePodsTransport.prototype.emitInstanceStatusChanged = function (instanceId, status, info) {
333
+ this.emitter.emit('instanceStatusChanged', instanceId, status, info);
334
+ };
335
+ /** Emit a log event (called by subclasses / process-lifecycle code). */
336
+ NodePodsTransport.prototype.emitLog = function (instanceId, line) {
337
+ this.emitter.emit('log', instanceId, line);
338
+ };
339
+ // ── Not-implemented stubs ──────────────────────────────────────────────────
340
+ NodePodsTransport.prototype.scanPaths = function () {
341
+ return Promise.reject(new Error('NodePodsTransport: scanPaths() not implemented — use full LocalPodService'));
342
+ };
343
+ NodePodsTransport.prototype.scanPorts = function (_podId) {
344
+ return Promise.reject(new Error('NodePodsTransport: scanPorts() not implemented — use full LocalPodService'));
345
+ };
346
+ NodePodsTransport.prototype.startInstance = function (_req) {
347
+ return Promise.reject(new Error('NodePodsTransport: startInstance() not implemented — use full LocalPodService'));
348
+ };
349
+ NodePodsTransport.prototype.stopInstance = function (_instanceId) {
350
+ return Promise.reject(new Error('NodePodsTransport: stopInstance() not implemented — use full LocalPodService'));
351
+ };
352
+ NodePodsTransport.prototype.restartInstance = function (_instanceId) {
353
+ return Promise.reject(new Error('NodePodsTransport: restartInstance() not implemented — use full LocalPodService'));
354
+ };
355
+ NodePodsTransport.prototype.getSystemInfo = function () {
356
+ return Promise.reject(new Error('NodePodsTransport: getSystemInfo() not implemented — use full LocalPodService'));
357
+ };
358
+ NodePodsTransport.prototype.getLogs = function (_instanceId) {
359
+ return Promise.reject(new Error('NodePodsTransport: getLogs() not implemented — use full LocalPodService'));
360
+ };
361
+ NodePodsTransport.prototype.installRocmPyTorch = function (_podId) {
362
+ throw new Error('NodePodsTransport: installRocmPyTorch() not implemented — use full LocalPodService');
363
+ };
364
+ NodePodsTransport.prototype.onRocmSetupDone = function (_cb) {
365
+ throw new Error('NodePodsTransport: onRocmSetupDone() not implemented — use full LocalPodService');
366
+ };
367
+ // ── Private helpers ────────────────────────────────────────────────────────
368
+ NodePodsTransport.prototype._getInstancesForPod = function (podId) {
369
+ var rows = this.db
370
+ .prepare('SELECT * FROM pod_instances WHERE pod_id = ?')
371
+ .all(podId);
372
+ return rows.map(rowToInstance);
373
+ };
374
+ NodePodsTransport.prototype._probePort = function (port) {
375
+ return __awaiter(this, void 0, void 0, function () {
376
+ var res, _a;
377
+ return __generator(this, function (_b) {
378
+ switch (_b.label) {
379
+ case 0:
380
+ _b.trys.push([0, 3, , 4]);
381
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/system_stats"), {
382
+ signal: AbortSignal.timeout(1500)
383
+ })];
384
+ case 1:
385
+ res = _b.sent();
386
+ if (!res.ok)
387
+ return [2 /*return*/, null];
388
+ return [4 /*yield*/, res.json()];
389
+ case 2: return [2 /*return*/, (_b.sent())];
390
+ case 3:
391
+ _a = _b.sent();
392
+ return [2 /*return*/, null];
393
+ case 4: return [2 /*return*/];
394
+ }
395
+ });
396
+ });
397
+ };
398
+ return NodePodsTransport;
399
+ }());
400
+ exports.NodePodsTransport = NodePodsTransport;
@@ -0,0 +1,29 @@
1
+ import type { NodePodsTransport } from './node-transport';
2
+ /**
3
+ * PodsOperatorServer — exposes a pod management and workflow execution HTTP API
4
+ * so that remote FlowScale apps (e.g. AI OS) can discover pods and run workflows
5
+ * without any direct knowledge of ComfyUI.
6
+ *
7
+ * Endpoints:
8
+ * GET /api/pods — list all pods
9
+ * GET /api/pods/:id — get a single pod
10
+ * POST /api/pods/:id/upload — upload a file to the pod's ComfyUI instance
11
+ * POST /api/pods/:id/execute — execute a workflow and wait for outputs
12
+ * GET /api/pods/:id/view?filename= — proxy a ComfyUI output image
13
+ *
14
+ * Serves on 0.0.0.0 so any machine on the LAN can reach it.
15
+ * Includes CORS headers for browser-based clients.
16
+ */
17
+ export declare class PodsOperatorServer {
18
+ private server;
19
+ private readonly transport;
20
+ private readonly api;
21
+ private readonly port;
22
+ constructor(transport: NodePodsTransport, port?: number);
23
+ start(): void;
24
+ stop(): void;
25
+ private _json;
26
+ private _readBody;
27
+ /** Returns the port of the first running instance in the given pod. */
28
+ private _runningPort;
29
+ }
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ Object.defineProperty(exports, "__esModule", { value: true });
72
+ exports.PodsOperatorServer = void 0;
73
+ var http = __importStar(require("http"));
74
+ var local_pods_1 = require("./local-pods");
75
+ /**
76
+ * PodsOperatorServer — exposes a pod management and workflow execution HTTP API
77
+ * so that remote FlowScale apps (e.g. AI OS) can discover pods and run workflows
78
+ * without any direct knowledge of ComfyUI.
79
+ *
80
+ * Endpoints:
81
+ * GET /api/pods — list all pods
82
+ * GET /api/pods/:id — get a single pod
83
+ * POST /api/pods/:id/upload — upload a file to the pod's ComfyUI instance
84
+ * POST /api/pods/:id/execute — execute a workflow and wait for outputs
85
+ * GET /api/pods/:id/view?filename= — proxy a ComfyUI output image
86
+ *
87
+ * Serves on 0.0.0.0 so any machine on the LAN can reach it.
88
+ * Includes CORS headers for browser-based clients.
89
+ */
90
+ var PodsOperatorServer = /** @class */ (function () {
91
+ function PodsOperatorServer(transport, port) {
92
+ if (port === void 0) { port = 3001; }
93
+ this.server = null;
94
+ this.transport = transport;
95
+ this.api = new local_pods_1.LocalPodsAPI(transport);
96
+ this.port = port;
97
+ }
98
+ PodsOperatorServer.prototype.start = function () {
99
+ var _this = this;
100
+ if (this.server)
101
+ return;
102
+ this.server = http.createServer(function (req, res) { return __awaiter(_this, void 0, void 0, function () {
103
+ var url, query, pods, podMatch, pod, uploadMatch, podId, port, body, contentType, upstream, data, executeMatch, podId, body, _a, _b, result, viewMatch, podId, port, params, upstream, imageBuffer, err_1;
104
+ var _c, _d, _e, _f, _g, _h, _j;
105
+ return __generator(this, function (_k) {
106
+ switch (_k.label) {
107
+ case 0:
108
+ res.setHeader('Access-Control-Allow-Origin', '*');
109
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
110
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
111
+ if (req.method === 'OPTIONS') {
112
+ res.writeHead(204);
113
+ res.end();
114
+ return [2 /*return*/];
115
+ }
116
+ url = ((_c = req.url) !== null && _c !== void 0 ? _c : '/').split('?')[0];
117
+ query = new URLSearchParams((_e = ((_d = req.url) !== null && _d !== void 0 ? _d : '').split('?')[1]) !== null && _e !== void 0 ? _e : '');
118
+ _k.label = 1;
119
+ case 1:
120
+ _k.trys.push([1, 18, , 19]);
121
+ if (!(req.method === 'GET' && (url === '/api/pods' || url === '/api/pods/'))) return [3 /*break*/, 3];
122
+ return [4 /*yield*/, this.transport.list()];
123
+ case 2:
124
+ pods = _k.sent();
125
+ return [2 /*return*/, this._json(res, 200, pods)];
126
+ case 3:
127
+ podMatch = url.match(/^\/api\/pods\/([^/]+)$/);
128
+ if (!(req.method === 'GET' && podMatch)) return [3 /*break*/, 5];
129
+ return [4 /*yield*/, this.transport.get(decodeURIComponent(podMatch[1]))];
130
+ case 4:
131
+ pod = _k.sent();
132
+ if (!pod)
133
+ return [2 /*return*/, this._json(res, 404, { error: 'Pod not found' })];
134
+ return [2 /*return*/, this._json(res, 200, pod)];
135
+ case 5:
136
+ uploadMatch = url.match(/^\/api\/pods\/([^/]+)\/upload$/);
137
+ if (!(req.method === 'POST' && uploadMatch)) return [3 /*break*/, 10];
138
+ podId = decodeURIComponent(uploadMatch[1]);
139
+ return [4 /*yield*/, this._runningPort(podId)];
140
+ case 6:
141
+ port = _k.sent();
142
+ return [4 /*yield*/, this._readBody(req)];
143
+ case 7:
144
+ body = _k.sent();
145
+ contentType = (_f = req.headers['content-type']) !== null && _f !== void 0 ? _f : 'application/octet-stream';
146
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/upload/image"), {
147
+ method: 'POST',
148
+ headers: { 'content-type': contentType },
149
+ body: body,
150
+ })];
151
+ case 8:
152
+ upstream = _k.sent();
153
+ return [4 /*yield*/, upstream.json()];
154
+ case 9:
155
+ data = _k.sent();
156
+ return [2 /*return*/, this._json(res, upstream.status, data)];
157
+ case 10:
158
+ executeMatch = url.match(/^\/api\/pods\/([^/]+)\/execute$/);
159
+ if (!(req.method === 'POST' && executeMatch)) return [3 /*break*/, 13];
160
+ podId = decodeURIComponent(executeMatch[1]);
161
+ _b = (_a = JSON).parse;
162
+ return [4 /*yield*/, this._readBody(req)];
163
+ case 11:
164
+ body = _b.apply(_a, [(_k.sent()).toString()]);
165
+ return [4 /*yield*/, this.api.executeWorkflowAndWait(podId, body.workflow, (_g = body.options) !== null && _g !== void 0 ? _g : {})];
166
+ case 12:
167
+ result = _k.sent();
168
+ return [2 /*return*/, this._json(res, 200, result)];
169
+ case 13:
170
+ viewMatch = url.match(/^\/api\/pods\/([^/]+)\/view$/);
171
+ if (!(req.method === 'GET' && viewMatch)) return [3 /*break*/, 17];
172
+ podId = decodeURIComponent(viewMatch[1]);
173
+ return [4 /*yield*/, this._runningPort(podId)];
174
+ case 14:
175
+ port = _k.sent();
176
+ params = new URLSearchParams(query.toString());
177
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/view?").concat(params))];
178
+ case 15:
179
+ upstream = _k.sent();
180
+ if (!upstream.ok) {
181
+ res.writeHead(upstream.status);
182
+ res.end();
183
+ return [2 /*return*/];
184
+ }
185
+ return [4 /*yield*/, upstream.arrayBuffer()];
186
+ case 16:
187
+ imageBuffer = _k.sent();
188
+ res.writeHead(200, {
189
+ 'Content-Type': (_h = upstream.headers.get('content-type')) !== null && _h !== void 0 ? _h : 'image/png',
190
+ 'Cache-Control': 'public, max-age=3600',
191
+ });
192
+ res.end(Buffer.from(imageBuffer));
193
+ return [2 /*return*/];
194
+ case 17:
195
+ res.writeHead(404);
196
+ res.end('Not found');
197
+ return [3 /*break*/, 19];
198
+ case 18:
199
+ err_1 = _k.sent();
200
+ console.error('[PodsOperatorServer] Error handling request:', err_1);
201
+ this._json(res, 500, { error: (_j = err_1 === null || err_1 === void 0 ? void 0 : err_1.message) !== null && _j !== void 0 ? _j : 'Internal server error' });
202
+ return [3 /*break*/, 19];
203
+ case 19: return [2 /*return*/];
204
+ }
205
+ });
206
+ }); });
207
+ this.server.listen(this.port, '0.0.0.0', function () {
208
+ console.log("[PodsOperatorServer] Listening on 0.0.0.0:".concat(_this.port));
209
+ });
210
+ this.server.on('error', function (err) {
211
+ console.error('[PodsOperatorServer] Server error:', err);
212
+ });
213
+ };
214
+ PodsOperatorServer.prototype.stop = function () {
215
+ if (this.server) {
216
+ this.server.close();
217
+ this.server = null;
218
+ }
219
+ };
220
+ // ── Private helpers ──────────────────────────────────────────────────────
221
+ PodsOperatorServer.prototype._json = function (res, status, data) {
222
+ res.writeHead(status, { 'Content-Type': 'application/json' });
223
+ res.end(JSON.stringify(data));
224
+ };
225
+ PodsOperatorServer.prototype._readBody = function (req) {
226
+ return new Promise(function (resolve, reject) {
227
+ var chunks = [];
228
+ req.on('data', function (chunk) { return chunks.push(chunk); });
229
+ req.on('end', function () { return resolve(Buffer.concat(chunks)); });
230
+ req.on('error', reject);
231
+ });
232
+ };
233
+ /** Returns the port of the first running instance in the given pod. */
234
+ PodsOperatorServer.prototype._runningPort = function (podId) {
235
+ return __awaiter(this, void 0, void 0, function () {
236
+ var pod, running;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
239
+ case 0: return [4 /*yield*/, this.transport.get(podId)];
240
+ case 1:
241
+ pod = _a.sent();
242
+ if (!pod)
243
+ throw new Error("Pod \"".concat(podId, "\" not found"));
244
+ running = pod.instances.find(function (i) { return i.status === 'running'; });
245
+ if (!running)
246
+ throw new Error("No running instance in pod \"".concat(pod.name, "\""));
247
+ return [2 /*return*/, running.port];
248
+ }
249
+ });
250
+ });
251
+ };
252
+ return PodsOperatorServer;
253
+ }());
254
+ exports.PodsOperatorServer = PodsOperatorServer;
@@ -0,0 +1,43 @@
1
+ import type { LocalPodsTransport, LocalPod, LocalPodInstance, LocalPodInstanceStatus, SystemInfo, ComfyUISystemStats, CreateLocalPodRequest, UpdateLocalPodRequest, StartInstanceRequest } from './local-types';
2
+ /**
3
+ * RemotePodsTransport — reads pods from a FlowScale Operator HTTP API
4
+ * served by PodsOperatorServer running on another machine.
5
+ *
6
+ * Only `list()` and `get()` are functional. All other methods throw since
7
+ * process lifecycle management must be done on the machine running the operator.
8
+ *
9
+ * Instance `baseUrl` fields are automatically set to `http://operatorHost:port`
10
+ * so that callers can reach the ComfyUI instances across the network.
11
+ *
12
+ * Usage:
13
+ * import { RemotePodsTransport, LocalPodsAPI } from 'flowscale'
14
+ * const podsApi = new LocalPodsAPI(new RemotePodsTransport('http://192.168.1.100:3001'))
15
+ */
16
+ export declare class RemotePodsTransport implements LocalPodsTransport {
17
+ private readonly operatorUrl;
18
+ private readonly operatorHost;
19
+ constructor(operatorUrl: string);
20
+ private _injectBaseUrls;
21
+ list(): Promise<LocalPod[]>;
22
+ get(id: string): Promise<LocalPod | null>;
23
+ private _notSupported;
24
+ create(_data: CreateLocalPodRequest): Promise<LocalPod>;
25
+ update(_id: string, _data: UpdateLocalPodRequest): Promise<LocalPod>;
26
+ delete(_id: string): Promise<void>;
27
+ scanPaths(): Promise<string | null>;
28
+ scanPorts(_podId: string): Promise<LocalPodInstance[]>;
29
+ refreshInstance(_instanceId: string): Promise<LocalPodInstance>;
30
+ startInstance(_req: StartInstanceRequest): Promise<LocalPodInstance>;
31
+ stopInstance(_instanceId: string): Promise<void>;
32
+ restartInstance(_instanceId: string): Promise<void>;
33
+ deleteInstance(_instanceId: string): Promise<void>;
34
+ getSystemInfo(): Promise<SystemInfo>;
35
+ getLogs(_instanceId: string): Promise<string[]>;
36
+ installRocmPyTorch(_podId: string): void;
37
+ onInstanceStatusChanged(_cb: (instanceId: string, status: LocalPodInstanceStatus, info?: ComfyUISystemStats) => void): () => void;
38
+ onLog(_cb: (instanceId: string, line: string) => void): () => void;
39
+ onRocmSetupDone(_cb: (data: {
40
+ podId: string;
41
+ success: boolean;
42
+ }) => void): () => void;
43
+ }
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.RemotePodsTransport = void 0;
51
+ /**
52
+ * RemotePodsTransport — reads pods from a FlowScale Operator HTTP API
53
+ * served by PodsOperatorServer running on another machine.
54
+ *
55
+ * Only `list()` and `get()` are functional. All other methods throw since
56
+ * process lifecycle management must be done on the machine running the operator.
57
+ *
58
+ * Instance `baseUrl` fields are automatically set to `http://operatorHost:port`
59
+ * so that callers can reach the ComfyUI instances across the network.
60
+ *
61
+ * Usage:
62
+ * import { RemotePodsTransport, LocalPodsAPI } from 'flowscale'
63
+ * const podsApi = new LocalPodsAPI(new RemotePodsTransport('http://192.168.1.100:3001'))
64
+ */
65
+ var RemotePodsTransport = /** @class */ (function () {
66
+ function RemotePodsTransport(operatorUrl) {
67
+ this.operatorUrl = operatorUrl.replace(/\/$/, '');
68
+ try {
69
+ this.operatorHost = new URL(this.operatorUrl).hostname;
70
+ }
71
+ catch (_a) {
72
+ this.operatorHost = 'localhost';
73
+ }
74
+ }
75
+ RemotePodsTransport.prototype._injectBaseUrls = function (pod) {
76
+ var _this = this;
77
+ return __assign(__assign({}, pod), { instances: pod.instances.map(function (inst) { return (__assign(__assign({}, inst), { baseUrl: "http://".concat(_this.operatorHost, ":").concat(inst.port) })); }) });
78
+ };
79
+ RemotePodsTransport.prototype.list = function () {
80
+ return __awaiter(this, void 0, void 0, function () {
81
+ var res, pods;
82
+ var _this = this;
83
+ return __generator(this, function (_a) {
84
+ switch (_a.label) {
85
+ case 0: return [4 /*yield*/, fetch("".concat(this.operatorUrl, "/api/pods"), {
86
+ signal: AbortSignal.timeout(5000),
87
+ })];
88
+ case 1:
89
+ res = _a.sent();
90
+ if (!res.ok)
91
+ throw new Error("Operator /api/pods failed (".concat(res.status, ")"));
92
+ return [4 /*yield*/, res.json()];
93
+ case 2:
94
+ pods = (_a.sent());
95
+ return [2 /*return*/, pods.map(function (p) { return _this._injectBaseUrls(p); })];
96
+ }
97
+ });
98
+ });
99
+ };
100
+ RemotePodsTransport.prototype.get = function (id) {
101
+ return __awaiter(this, void 0, void 0, function () {
102
+ var res, pod;
103
+ return __generator(this, function (_a) {
104
+ switch (_a.label) {
105
+ case 0: return [4 /*yield*/, fetch("".concat(this.operatorUrl, "/api/pods/").concat(encodeURIComponent(id)), { signal: AbortSignal.timeout(5000) })];
106
+ case 1:
107
+ res = _a.sent();
108
+ if (res.status === 404)
109
+ return [2 /*return*/, null];
110
+ if (!res.ok)
111
+ throw new Error("Operator /api/pods/".concat(id, " failed (").concat(res.status, ")"));
112
+ return [4 /*yield*/, res.json()];
113
+ case 2:
114
+ pod = (_a.sent());
115
+ return [2 /*return*/, this._injectBaseUrls(pod)];
116
+ }
117
+ });
118
+ });
119
+ };
120
+ // ── Not available via remote operator ──────────────────────────────────────
121
+ RemotePodsTransport.prototype._notSupported = function (method) {
122
+ throw new Error("RemotePodsTransport: \"".concat(method, "\" is not available via remote operator \u2014 ") +
123
+ 'connect to the operator machine directly to manage pods.');
124
+ };
125
+ RemotePodsTransport.prototype.create = function (_data) {
126
+ return this._notSupported('create');
127
+ };
128
+ RemotePodsTransport.prototype.update = function (_id, _data) {
129
+ return this._notSupported('update');
130
+ };
131
+ RemotePodsTransport.prototype.delete = function (_id) {
132
+ return this._notSupported('delete');
133
+ };
134
+ RemotePodsTransport.prototype.scanPaths = function () {
135
+ return this._notSupported('scanPaths');
136
+ };
137
+ RemotePodsTransport.prototype.scanPorts = function (_podId) {
138
+ return this._notSupported('scanPorts');
139
+ };
140
+ RemotePodsTransport.prototype.refreshInstance = function (_instanceId) {
141
+ return this._notSupported('refreshInstance');
142
+ };
143
+ RemotePodsTransport.prototype.startInstance = function (_req) {
144
+ return this._notSupported('startInstance');
145
+ };
146
+ RemotePodsTransport.prototype.stopInstance = function (_instanceId) {
147
+ return this._notSupported('stopInstance');
148
+ };
149
+ RemotePodsTransport.prototype.restartInstance = function (_instanceId) {
150
+ return this._notSupported('restartInstance');
151
+ };
152
+ RemotePodsTransport.prototype.deleteInstance = function (_instanceId) {
153
+ return this._notSupported('deleteInstance');
154
+ };
155
+ RemotePodsTransport.prototype.getSystemInfo = function () {
156
+ return this._notSupported('getSystemInfo');
157
+ };
158
+ RemotePodsTransport.prototype.getLogs = function (_instanceId) {
159
+ return this._notSupported('getLogs');
160
+ };
161
+ RemotePodsTransport.prototype.installRocmPyTorch = function (_podId) {
162
+ this._notSupported('installRocmPyTorch');
163
+ };
164
+ RemotePodsTransport.prototype.onInstanceStatusChanged = function (_cb) {
165
+ return function () { };
166
+ };
167
+ RemotePodsTransport.prototype.onLog = function (_cb) {
168
+ return function () { };
169
+ };
170
+ RemotePodsTransport.prototype.onRocmSetupDone = function (_cb) {
171
+ return function () { };
172
+ };
173
+ return RemotePodsTransport;
174
+ }());
175
+ exports.RemotePodsTransport = RemotePodsTransport;
package/package.json CHANGED
@@ -1,9 +1,19 @@
1
1
  {
2
2
  "name": "flowscale",
3
- "version": "2.1.0-beta.1",
3
+ "version": "2.1.0-beta.4",
4
4
  "description": "An NPM library for communicating with the Flowscale APIs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ },
12
+ "./node": {
13
+ "require": "./dist/node-index.js",
14
+ "types": "./dist/node-index.d.ts"
15
+ }
16
+ },
7
17
  "keywords": [
8
18
  "flowscale",
9
19
  "api",
@@ -33,7 +43,16 @@
33
43
  "axios": "^1.7.7",
34
44
  "form-data": "^4.0.1"
35
45
  },
46
+ "peerDependencies": {
47
+ "better-sqlite3": ">=9.0.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "better-sqlite3": {
51
+ "optional": true
52
+ }
53
+ },
36
54
  "devDependencies": {
55
+ "@types/better-sqlite3": "^7.6.13",
37
56
  "@types/form-data": "^2.5.2",
38
57
  "@types/node": "^22.9.1",
39
58
  "typescript": "^5.6.3"