flowscale 2.0.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
@@ -122,3 +122,7 @@ export declare class FlowscaleAPI {
122
122
  };
123
123
  }
124
124
  export * from './types';
125
+ export { FlowscalePlatformAPI } from './platform';
126
+ export { LocalPodsAPI } from './local-pods';
127
+ export * from './local-types';
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.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) {
@@ -1294,3 +1294,11 @@ if (typeof window !== 'undefined') {
1294
1294
  }
1295
1295
  // Export all types for TypeScript consumers
1296
1296
  __exportStar(require("./types"), exports);
1297
+ // Platform API — JWT-based control of the full Flowscale platform
1298
+ var platform_1 = require("./platform");
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);
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 });
@@ -0,0 +1,156 @@
1
+ export interface FlowscalePlatformConfig {
2
+ /** Flowscale JWT access token (from OAuth or login) */
3
+ token: string;
4
+ /** Team UUID — required for all team-scoped endpoints */
5
+ teamId: string;
6
+ /** Platform API base URL. Defaults to https://api.flowscale.ai */
7
+ baseUrl?: string;
8
+ /** Request timeout in ms. Default: 30000 */
9
+ timeout?: number;
10
+ }
11
+ export interface PlatformResponse<T = unknown> {
12
+ status: string;
13
+ data: T;
14
+ errors?: string;
15
+ }
16
+ export interface ProjectWorkflow {
17
+ id: string;
18
+ name: string;
19
+ description: string;
20
+ inputs: string;
21
+ outputs: string;
22
+ }
23
+ export interface Project {
24
+ _id: string;
25
+ name: string;
26
+ description?: string;
27
+ team_id: string;
28
+ cluster_url?: string;
29
+ api_key?: string;
30
+ status?: string;
31
+ created_at: string;
32
+ updated_at?: string;
33
+ }
34
+ export interface CreateProjectRequest {
35
+ name: string;
36
+ description?: string;
37
+ comfyui_version?: string;
38
+ [key: string]: unknown;
39
+ }
40
+ export interface UpdateProjectRequest {
41
+ name?: string;
42
+ description?: string;
43
+ [key: string]: unknown;
44
+ }
45
+ export interface ProjectApiKeyRequest {
46
+ name: string;
47
+ scopes?: string[];
48
+ }
49
+ export interface ProjectContentItem {
50
+ id: string;
51
+ name: string;
52
+ type: 'file' | 'folder';
53
+ path?: string;
54
+ size?: number;
55
+ created_at?: string;
56
+ }
57
+ export interface Pod {
58
+ _id: string;
59
+ name: string;
60
+ team_id: string;
61
+ project_id?: string;
62
+ status?: string;
63
+ gpu_type?: string;
64
+ budget?: number;
65
+ created_at: string;
66
+ }
67
+ export interface CreatePodRequest {
68
+ name: string;
69
+ project_id?: string;
70
+ gpu_type?: string;
71
+ budget?: number;
72
+ [key: string]: unknown;
73
+ }
74
+ export interface UpdatePodRequest {
75
+ name?: string;
76
+ budget?: number;
77
+ [key: string]: unknown;
78
+ }
79
+ export interface Cluster {
80
+ _id: string;
81
+ pod_id: string;
82
+ project_id?: string;
83
+ status: string;
84
+ created_at: string;
85
+ started_at?: string;
86
+ stopped_at?: string;
87
+ }
88
+ export interface StartClusterRequest {
89
+ pod_id: string;
90
+ project_id?: string;
91
+ [key: string]: unknown;
92
+ }
93
+ export interface ClusterLogEntry {
94
+ timestamp: string;
95
+ message: string;
96
+ level?: string;
97
+ }
98
+ export interface ClusterAnalytics {
99
+ [key: string]: unknown;
100
+ }
101
+ export interface PlatformRun {
102
+ _id: string;
103
+ team_id: string;
104
+ project_id?: string;
105
+ workflow_id?: string;
106
+ status: string;
107
+ created_at: string;
108
+ completed_at?: string;
109
+ }
110
+ export interface CreatePlatformRunRequest {
111
+ workflow_id: string;
112
+ inputs?: Record<string, unknown>;
113
+ [key: string]: unknown;
114
+ }
115
+ export interface TeamApiKey {
116
+ _id: string;
117
+ name: string;
118
+ key_preview: string;
119
+ scopes?: string[];
120
+ created_at: string;
121
+ }
122
+ export interface CreateTeamApiKeyRequest {
123
+ name: string;
124
+ scopes?: string[];
125
+ }
126
+ export interface InviteLink {
127
+ _id: string;
128
+ token: string;
129
+ url: string;
130
+ role?: string;
131
+ expires_at?: string;
132
+ created_at: string;
133
+ }
134
+ export interface CreateInviteLinkRequest {
135
+ role?: string;
136
+ expires_in_hours?: number;
137
+ }
138
+ export interface AnalyticsOverview {
139
+ total_runs: number;
140
+ total_api_calls: number;
141
+ credits_used: number;
142
+ [key: string]: unknown;
143
+ }
144
+ export interface RunsAnalytics {
145
+ [key: string]: unknown;
146
+ }
147
+ export interface ApiCallsAnalytics {
148
+ [key: string]: unknown;
149
+ }
150
+ export interface UserProfile {
151
+ username: string;
152
+ email: string;
153
+ avatar?: string;
154
+ is_active: boolean;
155
+ created_at: string;
156
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // Platform API — configuration
4
+ // ============================================================
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,29 @@
1
+ import { FlowscaleAPI } from './index';
2
+ import type { FlowscalePlatformConfig } from './platform-types';
3
+ export declare class FlowscalePlatformAPI {
4
+ private client;
5
+ private teamId;
6
+ readonly projects: ReturnType<FlowscalePlatformAPI['buildProjects']>;
7
+ readonly pods: ReturnType<FlowscalePlatformAPI['buildPods']>;
8
+ readonly clusters: ReturnType<FlowscalePlatformAPI['buildClusters']>;
9
+ readonly runs: ReturnType<FlowscalePlatformAPI['buildRuns']>;
10
+ readonly team: ReturnType<FlowscalePlatformAPI['buildTeam']>;
11
+ readonly analytics: ReturnType<FlowscalePlatformAPI['buildAnalytics']>;
12
+ readonly auth: ReturnType<FlowscalePlatformAPI['buildAuth']>;
13
+ constructor(config: FlowscalePlatformConfig);
14
+ /**
15
+ * Create a deployment-level FlowscaleAPI client for a specific project cluster.
16
+ * @param clusterUrl The cluster base URL from the project (e.g. https://cluster-xyz.flowscale.ai)
17
+ * @param apiKey A project-scoped API key from project.addApiKey()
18
+ */
19
+ getDeploymentClient(clusterUrl: string, apiKey: string): FlowscaleAPI;
20
+ private request;
21
+ private buildProjects;
22
+ private buildPods;
23
+ private buildClusters;
24
+ private buildRuns;
25
+ private buildTeam;
26
+ private buildAnalytics;
27
+ private buildAuth;
28
+ }
29
+ export * from './platform-types';
@@ -0,0 +1,380 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
+ return new (P || (P = Promise))(function (resolve, reject) {
19
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
23
+ });
24
+ };
25
+ var __generator = (this && this.__generator) || function (thisArg, body) {
26
+ 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);
27
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
28
+ function verb(n) { return function (v) { return step([n, v]); }; }
29
+ function step(op) {
30
+ if (f) throw new TypeError("Generator is already executing.");
31
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
32
+ 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;
33
+ if (y = 0, t) op = [op[0] & 2, t.value];
34
+ switch (op[0]) {
35
+ case 0: case 1: t = op; break;
36
+ case 4: _.label++; return { value: op[1], done: false };
37
+ case 5: _.label++; y = op[1]; op = [0]; continue;
38
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
39
+ default:
40
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
41
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
42
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
43
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
44
+ if (t[2]) _.ops.pop();
45
+ _.trys.pop(); continue;
46
+ }
47
+ op = body.call(thisArg, _);
48
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
49
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
50
+ }
51
+ };
52
+ var __importDefault = (this && this.__importDefault) || function (mod) {
53
+ return (mod && mod.__esModule) ? mod : { "default": mod };
54
+ };
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ exports.FlowscalePlatformAPI = void 0;
57
+ var axios_1 = __importDefault(require("axios"));
58
+ var index_1 = require("./index");
59
+ var DEFAULT_BASE_URL = 'https://api.flowscale.ai';
60
+ var FlowscalePlatformAPI = /** @class */ (function () {
61
+ function FlowscalePlatformAPI(config) {
62
+ var _this = this;
63
+ var _a, _b;
64
+ if (!config.token)
65
+ throw new Error('FlowscalePlatformAPI: token is required');
66
+ if (!config.teamId)
67
+ throw new Error('FlowscalePlatformAPI: teamId is required');
68
+ this.teamId = config.teamId;
69
+ this.client = axios_1.default.create({
70
+ baseURL: ((_a = config.baseUrl) !== null && _a !== void 0 ? _a : DEFAULT_BASE_URL).trimEnd().replace(/\/$/, ''),
71
+ timeout: (_b = config.timeout) !== null && _b !== void 0 ? _b : 30000,
72
+ });
73
+ this.client.interceptors.request.use(function (req) {
74
+ if (!req.headers)
75
+ req.headers = {};
76
+ req.headers['Authorization'] = "Bearer ".concat(config.token);
77
+ req.headers['X-Team'] = _this.teamId;
78
+ return req;
79
+ });
80
+ this.projects = this.buildProjects();
81
+ this.pods = this.buildPods();
82
+ this.clusters = this.buildClusters();
83
+ this.runs = this.buildRuns();
84
+ this.team = this.buildTeam();
85
+ this.analytics = this.buildAnalytics();
86
+ this.auth = this.buildAuth();
87
+ }
88
+ // ── Bridge to deployment client ─────────────────────────
89
+ /**
90
+ * Create a deployment-level FlowscaleAPI client for a specific project cluster.
91
+ * @param clusterUrl The cluster base URL from the project (e.g. https://cluster-xyz.flowscale.ai)
92
+ * @param apiKey A project-scoped API key from project.addApiKey()
93
+ */
94
+ FlowscalePlatformAPI.prototype.getDeploymentClient = function (clusterUrl, apiKey) {
95
+ return new index_1.FlowscaleAPI({ baseUrl: clusterUrl, apiKey: apiKey });
96
+ };
97
+ // ── Helper ───────────────────────────────────────────────
98
+ FlowscalePlatformAPI.prototype.request = function (method, path, data, params) {
99
+ return __awaiter(this, void 0, void 0, function () {
100
+ var response;
101
+ return __generator(this, function (_a) {
102
+ switch (_a.label) {
103
+ case 0: return [4 /*yield*/, this.client.request({ method: method, url: path, data: data, params: params })];
104
+ case 1:
105
+ response = _a.sent();
106
+ return [2 /*return*/, response.data];
107
+ }
108
+ });
109
+ });
110
+ };
111
+ // ── Projects ─────────────────────────────────────────────
112
+ FlowscalePlatformAPI.prototype.buildProjects = function () {
113
+ var req = this.request.bind(this);
114
+ return {
115
+ /** List all projects for the team. */
116
+ list: function () {
117
+ return req('get', '/api/v2/project');
118
+ },
119
+ /** Get a single project by ID. */
120
+ get: function (projectId) {
121
+ return req('get', "/api/v2/project/".concat(enc(projectId)));
122
+ },
123
+ /** Get a public project (no auth required — skips team header). */
124
+ getPublic: function (projectId) {
125
+ return req('get', "/api/v2/project/public/".concat(enc(projectId)));
126
+ },
127
+ /** Create a new project. */
128
+ create: function (data) {
129
+ return req('post', '/api/v2/project', data);
130
+ },
131
+ /** Update a project. */
132
+ update: function (projectId, data) {
133
+ return req('put', "/api/v2/project/".concat(enc(projectId)), data);
134
+ },
135
+ /** Delete a project. */
136
+ delete: function (projectId) {
137
+ return req('delete', "/api/v2/project/".concat(enc(projectId)));
138
+ },
139
+ /** Fork a project into the current team. */
140
+ fork: function (projectId) {
141
+ return req('post', "/api/v2/project/".concat(enc(projectId), "/fork"));
142
+ },
143
+ /** List workflows for a project. */
144
+ listWorkflows: function (projectId) {
145
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/workflows"));
146
+ },
147
+ /** Get a single workflow. */
148
+ getWorkflow: function (projectId, workflowId) {
149
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/workflows/").concat(enc(workflowId)));
150
+ },
151
+ /** Add a project-scoped API key (use with getDeploymentClient). */
152
+ addApiKey: function (projectId, data) {
153
+ return req('post', "/api/v2/project/".concat(enc(projectId), "/api_key"), data);
154
+ },
155
+ /** Delete a project-scoped API key. */
156
+ deleteApiKey: function (projectId, data) {
157
+ return req('delete', "/api/v2/project/".concat(enc(projectId), "/api_key"), data);
158
+ },
159
+ /** List files and folders in a project. */
160
+ getContents: function (projectId) {
161
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/contents"));
162
+ },
163
+ /** Create a folder inside a project. */
164
+ createFolder: function (projectId, data) {
165
+ return req('post', "/api/v2/project/".concat(enc(projectId), "/contents/folder"), data);
166
+ },
167
+ /** Download a file (returns download URL or content). */
168
+ downloadFile: function (projectId, fileId) {
169
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/contents/file/").concat(enc(fileId), "/download"));
170
+ },
171
+ /** Delete a file from a project. */
172
+ deleteFile: function (projectId, fileId) {
173
+ return req('delete', "/api/v2/project/".concat(enc(projectId), "/contents/file/").concat(enc(fileId)));
174
+ },
175
+ /** Delete a folder from a project. */
176
+ deleteFolder: function (projectId, folderId) {
177
+ return req('delete', "/api/v2/project/".concat(enc(projectId), "/contents/folder/").concat(enc(folderId)));
178
+ },
179
+ /** Get ComfyUI compute balance for a project. */
180
+ getComfyBalance: function (projectId) {
181
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/comfy/balance"));
182
+ },
183
+ /** Get storage usage analytics for a project. */
184
+ getStorageAnalytics: function (projectId) {
185
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/storage-analytics"));
186
+ },
187
+ /** Get clusters deployed for a specific project. */
188
+ getDeployedClusters: function (projectId) {
189
+ return req('get', "/api/v2/project/".concat(enc(projectId), "/clusters/deployed"));
190
+ },
191
+ };
192
+ };
193
+ // ── Pods ─────────────────────────────────────────────────
194
+ FlowscalePlatformAPI.prototype.buildPods = function () {
195
+ var req = this.request.bind(this);
196
+ return {
197
+ /** List available GPU types. */
198
+ listGpus: function () {
199
+ return req('get', '/api/v2/pod/gpus');
200
+ },
201
+ /** List all pods for the team. */
202
+ list: function () {
203
+ return req('get', '/api/v2/pod');
204
+ },
205
+ /** Get a pod by ID. */
206
+ get: function (podId) {
207
+ return req('get', "/api/v2/pod/".concat(enc(podId)));
208
+ },
209
+ /** Create a new pod. */
210
+ create: function (data) {
211
+ return req('post', '/api/v2/pod', data);
212
+ },
213
+ /** Update pod settings. */
214
+ update: function (podId, data) {
215
+ return req('put', "/api/v2/pod/".concat(enc(podId)), data);
216
+ },
217
+ /** Update pod budget. */
218
+ updateBudget: function (podId, budget) {
219
+ return req('patch', "/api/v2/pod/".concat(enc(podId), "/budget"), { budget: budget });
220
+ },
221
+ /** Stop all running clusters for a pod. */
222
+ stop: function (podId) {
223
+ return req('post', "/api/v2/pod/".concat(enc(podId), "/stop"));
224
+ },
225
+ /** Delete a pod. */
226
+ delete: function (podId) {
227
+ return req('delete', "/api/v2/pod/".concat(enc(podId)));
228
+ },
229
+ /** List workflows attached to a pod. */
230
+ listWorkflows: function (podId) {
231
+ return req('get', "/api/v2/pod/".concat(enc(podId), "/workflows"));
232
+ },
233
+ /** List all clusters for a pod. */
234
+ listClusters: function (podId) {
235
+ return req('get', "/api/v2/pod/".concat(enc(podId), "/clusters"));
236
+ },
237
+ /** Get the currently active cluster for a pod. */
238
+ getActiveCluster: function (podId) {
239
+ return req('get', "/api/v2/pod/".concat(enc(podId), "/cluster/active"));
240
+ },
241
+ };
242
+ };
243
+ // ── Clusters ─────────────────────────────────────────────
244
+ FlowscalePlatformAPI.prototype.buildClusters = function () {
245
+ var req = this.request.bind(this);
246
+ return {
247
+ /** List all clusters for the team. */
248
+ list: function () {
249
+ return req('get', '/api/v2/cluster');
250
+ },
251
+ /** Get a cluster by ID. */
252
+ get: function (clusterId) {
253
+ return req('get', "/api/v2/cluster/".concat(enc(clusterId)));
254
+ },
255
+ /** Start (deploy) a new cluster. */
256
+ start: function (data) {
257
+ return req('post', '/api/v2/cluster', data);
258
+ },
259
+ /** Stop a running cluster. */
260
+ stop: function (clusterId) {
261
+ return req('post', "/api/v2/cluster/".concat(enc(clusterId), "/stop"));
262
+ },
263
+ /** Get logs for a cluster. */
264
+ getLogs: function (clusterId) {
265
+ return req('get', "/api/v2/cluster/".concat(enc(clusterId), "/logs"));
266
+ },
267
+ /** Get usage analytics for a cluster. */
268
+ getAnalytics: function (clusterId) {
269
+ return req('get', "/api/v2/cluster/".concat(enc(clusterId), "/analytics"));
270
+ },
271
+ /** Analyze init logs with AI. */
272
+ analyzeInitLogs: function (clusterId) {
273
+ return req('post', "/api/v2/cluster/".concat(enc(clusterId), "/analyze-init-logs"));
274
+ },
275
+ /** Get temp nodes for a cluster. */
276
+ getTempNodes: function (clusterId) {
277
+ return req('get', "/api/v2/cluster/".concat(enc(clusterId), "/tempnodes"));
278
+ },
279
+ };
280
+ };
281
+ // ── Runs (platform-level) ─────────────────────────────────
282
+ FlowscalePlatformAPI.prototype.buildRuns = function () {
283
+ var req = this.request.bind(this);
284
+ return {
285
+ /** List all runs for the team. */
286
+ list: function (params) {
287
+ return req('get', '/api/v2/run', undefined, params);
288
+ },
289
+ /** Create a new run. */
290
+ create: function (data) {
291
+ return req('post', '/api/v2/run', data);
292
+ },
293
+ /** Delete a single run. */
294
+ delete: function (runId) {
295
+ return req('delete', "/api/v2/run/".concat(enc(runId)));
296
+ },
297
+ /** List output filenames for recent runs. */
298
+ listOutputs: function () {
299
+ return req('get', '/api/v2/run/outputs/list');
300
+ },
301
+ };
302
+ };
303
+ // ── Team ─────────────────────────────────────────────────
304
+ FlowscalePlatformAPI.prototype.buildTeam = function () {
305
+ var req = this.request.bind(this);
306
+ return {
307
+ /** List team-level API keys. */
308
+ listApiKeys: function () {
309
+ return req('get', '/api/v2/team/api-keys');
310
+ },
311
+ /** Create a new team-level API key. */
312
+ createApiKey: function (data) {
313
+ return req('post', '/api/v2/team/api-keys', data);
314
+ },
315
+ /** Revoke a team-level API key. */
316
+ revokeApiKey: function (keyId) {
317
+ return req('delete', "/api/v2/team/api-keys/".concat(enc(keyId)));
318
+ },
319
+ /** List active invite links. */
320
+ listInviteLinks: function () {
321
+ return req('get', '/api/v2/team/invite-links');
322
+ },
323
+ /** Create a new invite link. */
324
+ createInviteLink: function (data) {
325
+ return req('post', '/api/v2/team/invite-link', data);
326
+ },
327
+ /** Delete an invite link. */
328
+ deleteInviteLink: function (linkId) {
329
+ return req('delete', "/api/v2/team/invite-link/".concat(enc(linkId)));
330
+ },
331
+ };
332
+ };
333
+ // ── Analytics ────────────────────────────────────────────
334
+ FlowscalePlatformAPI.prototype.buildAnalytics = function () {
335
+ var req = this.request.bind(this);
336
+ return {
337
+ /** Get all analytics for the team. */
338
+ get: function (params) {
339
+ return req('get', '/api/v2/analytics', undefined, params);
340
+ },
341
+ /** Get high-level overview metrics. */
342
+ getOverview: function () {
343
+ return req('get', '/api/v2/analytics/overview');
344
+ },
345
+ /** Get run-specific analytics. */
346
+ getRuns: function (params) {
347
+ return req('get', '/api/v2/analytics/runs', undefined, params);
348
+ },
349
+ /** Get API call analytics. */
350
+ getApiCalls: function (params) {
351
+ return req('get', '/api/v2/analytics/api-calls', undefined, params);
352
+ },
353
+ };
354
+ };
355
+ // ── Auth ─────────────────────────────────────────────────
356
+ FlowscalePlatformAPI.prototype.buildAuth = function () {
357
+ var req = this.request.bind(this);
358
+ return {
359
+ /** Get the current user's profile. */
360
+ getProfile: function () {
361
+ return req('get', '/api/v2/auth/profile');
362
+ },
363
+ /** Refresh the access token using the refresh token. */
364
+ refreshToken: function (refreshToken) {
365
+ return req('post', '/api/v2/auth/refresh', { refresh_token: refreshToken });
366
+ },
367
+ /** Logout (invalidate current token). */
368
+ logout: function () {
369
+ return req('post', '/api/v2/auth/logout');
370
+ },
371
+ };
372
+ };
373
+ return FlowscalePlatformAPI;
374
+ }());
375
+ exports.FlowscalePlatformAPI = FlowscalePlatformAPI;
376
+ // ── Utility ───────────────────────────────────────────────
377
+ function enc(value) {
378
+ return encodeURIComponent(value);
379
+ }
380
+ __exportStar(require("./platform-types"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowscale",
3
- "version": "2.0.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",