flowscale 2.1.0-beta.0 → 2.1.0-beta.1

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
@@ -123,4 +123,6 @@ export declare class FlowscaleAPI {
123
123
  }
124
124
  export * from './types';
125
125
  export { FlowscalePlatformAPI } from './platform';
126
+ export { LocalPodsAPI } from './local-pods';
127
+ export * from './local-types';
126
128
  export * from './platform-types';
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.FlowscalePlatformAPI = exports.FlowscaleAPI = void 0;
76
+ 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) {
@@ -1297,4 +1297,8 @@ __exportStar(require("./types"), exports);
1297
1297
  // Platform API — JWT-based control of the full Flowscale platform
1298
1298
  var platform_1 = require("./platform");
1299
1299
  Object.defineProperty(exports, "FlowscalePlatformAPI", { enumerable: true, get: function () { return platform_1.FlowscalePlatformAPI; } });
1300
+ // Local Pods API — for managing local ComfyUI instances in Electron
1301
+ var local_pods_1 = require("./local-pods");
1302
+ Object.defineProperty(exports, "LocalPodsAPI", { enumerable: true, get: function () { return local_pods_1.LocalPodsAPI; } });
1303
+ __exportStar(require("./local-types"), exports);
1300
1304
  __exportStar(require("./platform-types"), exports);
@@ -0,0 +1,67 @@
1
+ import type { LocalPodsTransport, LocalPod, LocalPodInstance, LocalPodInstanceStatus, SystemInfo, ComfyUISystemStats, ComfyUIWorkflow, ComfyUIWorkflowResult, PodWorkflowHandle, ExecuteWorkflowOptions, CreateLocalPodRequest, UpdateLocalPodRequest, StartInstanceRequest } from './local-types';
2
+ /**
3
+ * LocalPodsAPI — manages local ComfyUI pods via a pluggable transport.
4
+ *
5
+ * In the Electron app, pass an ElectronPodsTransport that delegates to IPC.
6
+ * This class contains no logic; it is a typed facade over the transport.
7
+ */
8
+ export declare class LocalPodsAPI {
9
+ private transport;
10
+ constructor(transport: LocalPodsTransport);
11
+ create(data: CreateLocalPodRequest): Promise<LocalPod>;
12
+ list(): Promise<LocalPod[]>;
13
+ get(id: string): Promise<LocalPod | null>;
14
+ update(id: string, data: UpdateLocalPodRequest): Promise<LocalPod>;
15
+ delete(id: string): Promise<void>;
16
+ /** Scan common OS directories for a ComfyUI installation path. */
17
+ scanPaths(): Promise<string | null>;
18
+ /** Probe ports 8188–9188 and associate any found ComfyUI instances with podId. */
19
+ scanPorts(podId: string): Promise<LocalPodInstance[]>;
20
+ /** Re-probe a single instance port and return the updated instance. */
21
+ refreshInstance(instanceId: string): Promise<LocalPodInstance>;
22
+ startInstance(req: StartInstanceRequest): Promise<LocalPodInstance>;
23
+ stopInstance(instanceId: string): Promise<void>;
24
+ restartInstance(instanceId: string): Promise<void>;
25
+ deleteInstance(instanceId: string): Promise<void>;
26
+ getSystemInfo(): Promise<SystemInfo>;
27
+ getLogs(instanceId: string): Promise<string[]>;
28
+ onInstanceStatusChanged(cb: (instanceId: string, status: LocalPodInstanceStatus, info?: ComfyUISystemStats) => void): () => void;
29
+ onLog(cb: (instanceId: string, line: string) => void): () => void;
30
+ installRocmPyTorch(podId: string): void;
31
+ onRocmSetupDone(cb: (data: {
32
+ podId: string;
33
+ success: boolean;
34
+ }) => void): () => void;
35
+ /**
36
+ * Execute a workflow on a pod. The SDK automatically picks the
37
+ * least-loaded running ComfyUI instance inside the pod.
38
+ *
39
+ * Returns a handle with a `wait()` method to get the outputs.
40
+ * Use `executeWorkflowAndWait` if you want a single awaitable call.
41
+ *
42
+ * @param podId ID of the pod to run the workflow on
43
+ * @param workflow ComfyUI workflow graph (API format)
44
+ * @param options Optional clientId and extraData
45
+ */
46
+ executeWorkflow(podId: string, workflow: ComfyUIWorkflow | Record<string, unknown>, options?: ExecuteWorkflowOptions): Promise<PodWorkflowHandle>;
47
+ /**
48
+ * Execute a workflow on a pod and wait for it to complete.
49
+ * The SDK automatically picks the least-loaded running instance.
50
+ *
51
+ * @param podId ID of the pod to run the workflow on
52
+ * @param workflow ComfyUI workflow graph (API format)
53
+ * @param options Optional clientId and extraData
54
+ * @param timeoutMs Maximum wait time in ms (default 5 minutes)
55
+ */
56
+ executeWorkflowAndWait(podId: string, workflow: ComfyUIWorkflow | Record<string, unknown>, options?: ExecuteWorkflowOptions, timeoutMs?: number): Promise<ComfyUIWorkflowResult>;
57
+ /**
58
+ * Find the port of the least-loaded running instance in a pod.
59
+ * Checks ComfyUI's /queue endpoint on all running instances in parallel
60
+ * and picks the one with the fewest queued jobs.
61
+ */
62
+ private _findFreeInstancePort;
63
+ /** Returns total number of jobs (running + pending) on a ComfyUI instance. */
64
+ private _getQueueDepth;
65
+ /** Poll /history until the prompt completes, then return the result. */
66
+ private _pollHistory;
67
+ }
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ 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);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.LocalPodsAPI = void 0;
40
+ /**
41
+ * LocalPodsAPI — manages local ComfyUI pods via a pluggable transport.
42
+ *
43
+ * In the Electron app, pass an ElectronPodsTransport that delegates to IPC.
44
+ * This class contains no logic; it is a typed facade over the transport.
45
+ */
46
+ var LocalPodsAPI = /** @class */ (function () {
47
+ function LocalPodsAPI(transport) {
48
+ this.transport = transport;
49
+ }
50
+ // ── Pod CRUD ──────────────────────────────────────────────
51
+ LocalPodsAPI.prototype.create = function (data) {
52
+ return this.transport.create(data);
53
+ };
54
+ LocalPodsAPI.prototype.list = function () {
55
+ return this.transport.list();
56
+ };
57
+ LocalPodsAPI.prototype.get = function (id) {
58
+ return this.transport.get(id);
59
+ };
60
+ LocalPodsAPI.prototype.update = function (id, data) {
61
+ return this.transport.update(id, data);
62
+ };
63
+ LocalPodsAPI.prototype.delete = function (id) {
64
+ return this.transport.delete(id);
65
+ };
66
+ // ── Detection & scanning ──────────────────────────────────
67
+ /** Scan common OS directories for a ComfyUI installation path. */
68
+ LocalPodsAPI.prototype.scanPaths = function () {
69
+ return this.transport.scanPaths();
70
+ };
71
+ /** Probe ports 8188–9188 and associate any found ComfyUI instances with podId. */
72
+ LocalPodsAPI.prototype.scanPorts = function (podId) {
73
+ return this.transport.scanPorts(podId);
74
+ };
75
+ /** Re-probe a single instance port and return the updated instance. */
76
+ LocalPodsAPI.prototype.refreshInstance = function (instanceId) {
77
+ return this.transport.refreshInstance(instanceId);
78
+ };
79
+ // ── Instance lifecycle ────────────────────────────────────
80
+ LocalPodsAPI.prototype.startInstance = function (req) {
81
+ return this.transport.startInstance(req);
82
+ };
83
+ LocalPodsAPI.prototype.stopInstance = function (instanceId) {
84
+ return this.transport.stopInstance(instanceId);
85
+ };
86
+ LocalPodsAPI.prototype.restartInstance = function (instanceId) {
87
+ return this.transport.restartInstance(instanceId);
88
+ };
89
+ LocalPodsAPI.prototype.deleteInstance = function (instanceId) {
90
+ return this.transport.deleteInstance(instanceId);
91
+ };
92
+ // ── System info ───────────────────────────────────────────
93
+ LocalPodsAPI.prototype.getSystemInfo = function () {
94
+ return this.transport.getSystemInfo();
95
+ };
96
+ // ── Logs ──────────────────────────────────────────────────
97
+ LocalPodsAPI.prototype.getLogs = function (instanceId) {
98
+ return this.transport.getLogs(instanceId);
99
+ };
100
+ // ── Events ────────────────────────────────────────────────
101
+ LocalPodsAPI.prototype.onInstanceStatusChanged = function (cb) {
102
+ return this.transport.onInstanceStatusChanged(cb);
103
+ };
104
+ LocalPodsAPI.prototype.onLog = function (cb) {
105
+ return this.transport.onLog(cb);
106
+ };
107
+ // ── AMD GPU setup ─────────────────────────────────────────
108
+ LocalPodsAPI.prototype.installRocmPyTorch = function (podId) {
109
+ return this.transport.installRocmPyTorch(podId);
110
+ };
111
+ LocalPodsAPI.prototype.onRocmSetupDone = function (cb) {
112
+ return this.transport.onRocmSetupDone(cb);
113
+ };
114
+ // ── Workflow execution ────────────────────────────────────
115
+ // External apps only need to know about pods — the SDK handles
116
+ // routing to a free ComfyUI instance internally.
117
+ /**
118
+ * Execute a workflow on a pod. The SDK automatically picks the
119
+ * least-loaded running ComfyUI instance inside the pod.
120
+ *
121
+ * Returns a handle with a `wait()` method to get the outputs.
122
+ * Use `executeWorkflowAndWait` if you want a single awaitable call.
123
+ *
124
+ * @param podId ID of the pod to run the workflow on
125
+ * @param workflow ComfyUI workflow graph (API format)
126
+ * @param options Optional clientId and extraData
127
+ */
128
+ LocalPodsAPI.prototype.executeWorkflow = function (podId_1, workflow_1) {
129
+ return __awaiter(this, arguments, void 0, function (podId, workflow, options) {
130
+ var pod, port, clientId, body, res, text, prompt_id;
131
+ var _this = this;
132
+ var _a;
133
+ if (options === void 0) { options = {}; }
134
+ return __generator(this, function (_b) {
135
+ switch (_b.label) {
136
+ case 0: return [4 /*yield*/, this.transport.get(podId)];
137
+ case 1:
138
+ pod = _b.sent();
139
+ if (!pod)
140
+ throw new Error("Pod \"".concat(podId, "\" not found"));
141
+ return [4 /*yield*/, this._findFreeInstancePort(pod)];
142
+ case 2:
143
+ port = _b.sent();
144
+ clientId = (_a = options.clientId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
145
+ body = { prompt: workflow, client_id: clientId };
146
+ if (options.extraData)
147
+ body.extra_data = options.extraData;
148
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/prompt"), {
149
+ method: 'POST',
150
+ headers: { 'Content-Type': 'application/json' },
151
+ body: JSON.stringify(body)
152
+ })];
153
+ case 3:
154
+ res = _b.sent();
155
+ if (!!res.ok) return [3 /*break*/, 5];
156
+ return [4 /*yield*/, res.text().catch(function () { return res.statusText; })];
157
+ case 4:
158
+ text = _b.sent();
159
+ throw new Error("ComfyUI /prompt failed (".concat(res.status, "): ").concat(text));
160
+ case 5: return [4 /*yield*/, res.json()];
161
+ case 6:
162
+ prompt_id = (_b.sent()).prompt_id;
163
+ return [2 /*return*/, {
164
+ promptId: prompt_id,
165
+ podId: podId,
166
+ wait: function (timeoutMs) { return _this._pollHistory(port, prompt_id, podId, timeoutMs); }
167
+ }];
168
+ }
169
+ });
170
+ });
171
+ };
172
+ /**
173
+ * Execute a workflow on a pod and wait for it to complete.
174
+ * The SDK automatically picks the least-loaded running instance.
175
+ *
176
+ * @param podId ID of the pod to run the workflow on
177
+ * @param workflow ComfyUI workflow graph (API format)
178
+ * @param options Optional clientId and extraData
179
+ * @param timeoutMs Maximum wait time in ms (default 5 minutes)
180
+ */
181
+ LocalPodsAPI.prototype.executeWorkflowAndWait = function (podId_1, workflow_1) {
182
+ return __awaiter(this, arguments, void 0, function (podId, workflow, options, timeoutMs) {
183
+ var handle;
184
+ if (options === void 0) { options = {}; }
185
+ if (timeoutMs === void 0) { timeoutMs = 300000; }
186
+ return __generator(this, function (_a) {
187
+ switch (_a.label) {
188
+ case 0: return [4 /*yield*/, this.executeWorkflow(podId, workflow, options)];
189
+ case 1:
190
+ handle = _a.sent();
191
+ return [2 /*return*/, handle.wait(timeoutMs)];
192
+ }
193
+ });
194
+ });
195
+ };
196
+ // ── Private helpers ───────────────────────────────────────
197
+ /**
198
+ * Find the port of the least-loaded running instance in a pod.
199
+ * Checks ComfyUI's /queue endpoint on all running instances in parallel
200
+ * and picks the one with the fewest queued jobs.
201
+ */
202
+ LocalPodsAPI.prototype._findFreeInstancePort = function (pod) {
203
+ return __awaiter(this, void 0, void 0, function () {
204
+ var running, withLoad;
205
+ var _this = this;
206
+ return __generator(this, function (_a) {
207
+ switch (_a.label) {
208
+ case 0:
209
+ running = pod.instances.filter(function (i) { return i.status === 'running'; });
210
+ if (running.length === 0) {
211
+ throw new Error("No running ComfyUI instances in pod \"".concat(pod.name, "\". Start an instance first."));
212
+ }
213
+ return [4 /*yield*/, Promise.all(running.map(function (inst) { return __awaiter(_this, void 0, void 0, function () {
214
+ var load;
215
+ return __generator(this, function (_a) {
216
+ switch (_a.label) {
217
+ case 0: return [4 /*yield*/, this._getQueueDepth(inst.port)];
218
+ case 1:
219
+ load = _a.sent();
220
+ return [2 /*return*/, { port: inst.port, load: load }];
221
+ }
222
+ });
223
+ }); }))
224
+ // Sort by total load (running + pending jobs) and pick the least busy
225
+ ];
226
+ case 1:
227
+ withLoad = _a.sent();
228
+ // Sort by total load (running + pending jobs) and pick the least busy
229
+ withLoad.sort(function (a, b) { return a.load - b.load; });
230
+ return [2 /*return*/, withLoad[0].port];
231
+ }
232
+ });
233
+ });
234
+ };
235
+ /** Returns total number of jobs (running + pending) on a ComfyUI instance. */
236
+ LocalPodsAPI.prototype._getQueueDepth = function (port) {
237
+ return __awaiter(this, void 0, void 0, function () {
238
+ var res, data, _a;
239
+ return __generator(this, function (_b) {
240
+ switch (_b.label) {
241
+ case 0:
242
+ _b.trys.push([0, 3, , 4]);
243
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/queue"), {
244
+ signal: AbortSignal.timeout(2000)
245
+ })];
246
+ case 1:
247
+ res = _b.sent();
248
+ if (!res.ok)
249
+ return [2 /*return*/, Infinity];
250
+ return [4 /*yield*/, res.json()];
251
+ case 2:
252
+ data = _b.sent();
253
+ return [2 /*return*/, data.queue_running.length + data.queue_pending.length];
254
+ case 3:
255
+ _a = _b.sent();
256
+ return [2 /*return*/, Infinity]; // treat unreachable instances as fully loaded
257
+ case 4: return [2 /*return*/];
258
+ }
259
+ });
260
+ });
261
+ };
262
+ /** Poll /history until the prompt completes, then return the result. */
263
+ LocalPodsAPI.prototype._pollHistory = function (port_1, promptId_1, podId_1) {
264
+ return __awaiter(this, arguments, void 0, function (port, promptId, podId, timeoutMs, pollMs) {
265
+ var start, res, history_1, entry, err_1;
266
+ if (timeoutMs === void 0) { timeoutMs = 300000; }
267
+ if (pollMs === void 0) { pollMs = 1000; }
268
+ return __generator(this, function (_a) {
269
+ switch (_a.label) {
270
+ case 0:
271
+ start = Date.now();
272
+ _a.label = 1;
273
+ case 1:
274
+ if (!(Date.now() - start < timeoutMs)) return [3 /*break*/, 8];
275
+ return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, pollMs); })];
276
+ case 2:
277
+ _a.sent();
278
+ _a.label = 3;
279
+ case 3:
280
+ _a.trys.push([3, 6, , 7]);
281
+ return [4 /*yield*/, fetch("http://localhost:".concat(port, "/history/").concat(promptId), {
282
+ signal: AbortSignal.timeout(5000)
283
+ })];
284
+ case 4:
285
+ res = _a.sent();
286
+ if (!res.ok)
287
+ return [3 /*break*/, 1];
288
+ return [4 /*yield*/, res.json()];
289
+ case 5:
290
+ history_1 = _a.sent();
291
+ entry = history_1[promptId];
292
+ if (!entry)
293
+ return [3 /*break*/, 1];
294
+ if (entry.status.status_str === 'error') {
295
+ throw new Error("Workflow \"".concat(promptId, "\" failed on pod \"").concat(podId, "\""));
296
+ }
297
+ if (entry.status.completed) {
298
+ return [2 /*return*/, {
299
+ promptId: promptId,
300
+ podId: podId,
301
+ outputs: entry.outputs,
302
+ elapsedMs: Date.now() - start
303
+ }];
304
+ }
305
+ return [3 /*break*/, 7];
306
+ case 6:
307
+ err_1 = _a.sent();
308
+ if (err_1 instanceof Error && err_1.message.startsWith('Workflow'))
309
+ throw err_1;
310
+ return [3 /*break*/, 7];
311
+ case 7: return [3 /*break*/, 1];
312
+ case 8: throw new Error("Workflow \"".concat(promptId, "\" timed out after ").concat(timeoutMs, "ms"));
313
+ }
314
+ });
315
+ });
316
+ };
317
+ return LocalPodsAPI;
318
+ }());
319
+ exports.LocalPodsAPI = LocalPodsAPI;
@@ -0,0 +1,143 @@
1
+ export type LocalPodDevice = {
2
+ type: 'cpu';
3
+ } | {
4
+ type: 'gpu';
5
+ index: number;
6
+ name: string;
7
+ vram?: number;
8
+ vendor?: string;
9
+ };
10
+ export type LocalPodInstanceStatus = 'running' | 'idle';
11
+ export interface ComfyUIDevice {
12
+ name: string;
13
+ type: string;
14
+ index: number;
15
+ vram_total: number;
16
+ vram_free: number;
17
+ }
18
+ export interface ComfyUISystemStats {
19
+ system: {
20
+ os: string;
21
+ python_version: string;
22
+ };
23
+ devices: ComfyUIDevice[];
24
+ }
25
+ export interface LocalPodInstance {
26
+ id: string;
27
+ podId: string;
28
+ port: number;
29
+ device: LocalPodDevice;
30
+ status: LocalPodInstanceStatus;
31
+ /** null = externally running (not spawned by app) */
32
+ pid: number | null;
33
+ lastDetectedAt: number | null;
34
+ comfyuiInfo?: ComfyUISystemStats;
35
+ createdAt: number;
36
+ }
37
+ export interface LocalPod {
38
+ id: string;
39
+ name: string;
40
+ description?: string;
41
+ /** null if not found/provided */
42
+ comfyuiPath: string | null;
43
+ instances: LocalPodInstance[];
44
+ createdAt: number;
45
+ updatedAt: number;
46
+ }
47
+ export interface GpuInfo {
48
+ index: number;
49
+ name: string;
50
+ vram?: number;
51
+ vendor?: string;
52
+ }
53
+ export interface CpuInfo {
54
+ model: string;
55
+ cores: number;
56
+ threads: number;
57
+ }
58
+ export interface SystemInfo {
59
+ gpus: GpuInfo[];
60
+ cpu: CpuInfo;
61
+ }
62
+ export interface CreateLocalPodRequest {
63
+ name: string;
64
+ description?: string;
65
+ comfyuiPath?: string;
66
+ }
67
+ export interface UpdateLocalPodRequest {
68
+ name?: string;
69
+ description?: string;
70
+ comfyuiPath?: string | null;
71
+ }
72
+ export interface StartInstanceRequest {
73
+ podId: string;
74
+ /** The device (CPU or specific GPU) to start ComfyUI on */
75
+ device: LocalPodDevice;
76
+ }
77
+ /** A ComfyUI workflow graph — map of node ID to node definition */
78
+ export type ComfyUIWorkflow = Record<string, {
79
+ class_type: string;
80
+ inputs: Record<string, unknown>;
81
+ _meta?: Record<string, unknown>;
82
+ }>;
83
+ export interface ExecuteWorkflowOptions {
84
+ /** ComfyUI client ID for WebSocket tracking. Auto-generated if omitted. */
85
+ clientId?: string;
86
+ /** Extra data passed to ComfyUI alongside the prompt */
87
+ extraData?: Record<string, unknown>;
88
+ }
89
+ export interface ComfyUIOutputFile {
90
+ filename: string;
91
+ subfolder: string;
92
+ type: 'output' | 'temp' | 'input';
93
+ }
94
+ export interface ComfyUINodeOutput {
95
+ images?: ComfyUIOutputFile[];
96
+ gifs?: ComfyUIOutputFile[];
97
+ [key: string]: unknown;
98
+ }
99
+ export interface ComfyUIWorkflowResult {
100
+ promptId: string;
101
+ podId: string;
102
+ /** Map of node ID → its outputs (images, etc.) */
103
+ outputs: Record<string, ComfyUINodeOutput>;
104
+ /** Total elapsed time in ms */
105
+ elapsedMs: number;
106
+ }
107
+ /**
108
+ * Handle returned by `executeWorkflow`. Lets you track or await the result
109
+ * without caring which instance inside the pod is running it.
110
+ */
111
+ export interface PodWorkflowHandle {
112
+ /** ComfyUI prompt ID */
113
+ promptId: string;
114
+ podId: string;
115
+ /** Wait for the workflow to complete and return its outputs */
116
+ wait(timeoutMs?: number): Promise<ComfyUIWorkflowResult>;
117
+ }
118
+ export interface LocalPodsTransport {
119
+ create(data: CreateLocalPodRequest): Promise<LocalPod>;
120
+ list(): Promise<LocalPod[]>;
121
+ get(id: string): Promise<LocalPod | null>;
122
+ update(id: string, data: UpdateLocalPodRequest): Promise<LocalPod>;
123
+ delete(id: string): Promise<void>;
124
+ /** Scan common OS directories for a ComfyUI installation. Returns path or null. */
125
+ scanPaths(): Promise<string | null>;
126
+ /** Scan ports 8188–9188 in parallel; associate discovered instances with podId. */
127
+ scanPorts(podId: string): Promise<LocalPodInstance[]>;
128
+ /** Re-probe a single instance's port and update its status. */
129
+ refreshInstance(instanceId: string): Promise<LocalPodInstance>;
130
+ startInstance(req: StartInstanceRequest): Promise<LocalPodInstance>;
131
+ stopInstance(instanceId: string): Promise<void>;
132
+ restartInstance(instanceId: string): Promise<void>;
133
+ deleteInstance(instanceId: string): Promise<void>;
134
+ getSystemInfo(): Promise<SystemInfo>;
135
+ getLogs(instanceId: string): Promise<string[]>;
136
+ onInstanceStatusChanged(cb: (instanceId: string, status: LocalPodInstanceStatus, info?: ComfyUISystemStats) => void): () => void;
137
+ onLog(cb: (instanceId: string, line: string) => void): () => void;
138
+ installRocmPyTorch(podId: string): void;
139
+ onRocmSetupDone(cb: (data: {
140
+ podId: string;
141
+ success: boolean;
142
+ }) => void): () => void;
143
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // Local Pod Types — for Electron/local ComfyUI management
4
+ // ============================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowscale",
3
- "version": "2.1.0-beta.0",
3
+ "version": "2.1.0-beta.1",
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",