comfyui-node 1.3.1 → 1.4.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.
Files changed (62) hide show
  1. package/README.OLD.md +1395 -0
  2. package/README.md +112 -1223
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/call-wrapper.d.ts +1 -0
  5. package/dist/call-wrapper.d.ts.map +1 -1
  6. package/dist/call-wrapper.js +136 -41
  7. package/dist/call-wrapper.js.map +1 -1
  8. package/dist/client.js +1 -1
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/pool/WorkflowPool.d.ts +93 -0
  14. package/dist/pool/WorkflowPool.d.ts.map +1 -0
  15. package/dist/pool/WorkflowPool.js +438 -0
  16. package/dist/pool/WorkflowPool.js.map +1 -0
  17. package/dist/pool/client/ClientManager.d.ts +71 -0
  18. package/dist/pool/client/ClientManager.d.ts.map +1 -0
  19. package/dist/pool/client/ClientManager.js +167 -0
  20. package/dist/pool/client/ClientManager.js.map +1 -0
  21. package/dist/pool/failover/SmartFailoverStrategy.d.ts +18 -0
  22. package/dist/pool/failover/SmartFailoverStrategy.d.ts.map +1 -0
  23. package/dist/pool/failover/SmartFailoverStrategy.js +65 -0
  24. package/dist/pool/failover/SmartFailoverStrategy.js.map +1 -0
  25. package/dist/pool/failover/Strategy.d.ts +10 -0
  26. package/dist/pool/failover/Strategy.d.ts.map +1 -0
  27. package/dist/pool/failover/Strategy.js +2 -0
  28. package/dist/pool/failover/Strategy.js.map +1 -0
  29. package/dist/pool/index.d.ts +9 -0
  30. package/dist/pool/index.d.ts.map +1 -0
  31. package/dist/pool/index.js +4 -0
  32. package/dist/pool/index.js.map +1 -0
  33. package/dist/pool/queue/QueueAdapter.d.ts +31 -0
  34. package/dist/pool/queue/QueueAdapter.d.ts.map +1 -0
  35. package/dist/pool/queue/QueueAdapter.js +2 -0
  36. package/dist/pool/queue/QueueAdapter.js.map +1 -0
  37. package/dist/pool/queue/adapters/memory.d.ts +21 -0
  38. package/dist/pool/queue/adapters/memory.d.ts.map +1 -0
  39. package/dist/pool/queue/adapters/memory.js +96 -0
  40. package/dist/pool/queue/adapters/memory.js.map +1 -0
  41. package/dist/pool/types/events.d.ts +75 -0
  42. package/dist/pool/types/events.d.ts.map +1 -0
  43. package/dist/pool/types/events.js +2 -0
  44. package/dist/pool/types/events.js.map +1 -0
  45. package/dist/pool/types/job.d.ts +56 -0
  46. package/dist/pool/types/job.d.ts.map +1 -0
  47. package/dist/pool/types/job.js +2 -0
  48. package/dist/pool/types/job.js.map +1 -0
  49. package/dist/pool/utils/clone.d.ts +2 -0
  50. package/dist/pool/utils/clone.d.ts.map +1 -0
  51. package/dist/pool/utils/clone.js +7 -0
  52. package/dist/pool/utils/clone.js.map +1 -0
  53. package/dist/pool/utils/hash.d.ts +5 -0
  54. package/dist/pool/utils/hash.d.ts.map +1 -0
  55. package/dist/pool/utils/hash.js +19 -0
  56. package/dist/pool/utils/hash.js.map +1 -0
  57. package/dist/types/event.d.ts +3 -2
  58. package/dist/types/event.d.ts.map +1 -1
  59. package/dist/workflow.d.ts.map +1 -1
  60. package/dist/workflow.js +2 -1
  61. package/dist/workflow.js.map +1 -1
  62. package/package.json +4 -4
@@ -0,0 +1,167 @@
1
+ import { TypedEventTarget } from "../../typed-event-target.js";
2
+ export class ClientManager extends TypedEventTarget {
3
+ clients = [];
4
+ strategy;
5
+ healthCheckInterval = null;
6
+ healthCheckIntervalMs;
7
+ /**
8
+ * Create a new ClientManager for managing ComfyUI client connections.
9
+ *
10
+ * @param strategy - Failover strategy for handling client failures
11
+ * @param opts - Configuration options
12
+ * @param opts.healthCheckIntervalMs - Interval (ms) for health check pings to keep connections alive.
13
+ * Set to 0 to disable. Default: 30000 (30 seconds).
14
+ */
15
+ constructor(strategy, opts) {
16
+ super();
17
+ this.strategy = strategy;
18
+ this.healthCheckIntervalMs = opts?.healthCheckIntervalMs ?? 30000; // Default: 30 seconds
19
+ }
20
+ emitBlocked(clientId, workflowHash) {
21
+ this.dispatchEvent(new CustomEvent("client:blocked_workflow", { detail: { clientId, workflowHash } }));
22
+ }
23
+ emitUnblocked(clientId, workflowHash) {
24
+ this.dispatchEvent(new CustomEvent("client:unblocked_workflow", { detail: { clientId, workflowHash } }));
25
+ }
26
+ async initialize(clients) {
27
+ for (const client of clients) {
28
+ await this.addClient(client);
29
+ }
30
+ this.startHealthCheck();
31
+ }
32
+ async addClient(client) {
33
+ await client.init();
34
+ const managed = {
35
+ client,
36
+ id: client.id,
37
+ online: true,
38
+ busy: false,
39
+ lastSeenAt: Date.now(),
40
+ supportedWorkflows: new Set()
41
+ };
42
+ this.clients.push(managed);
43
+ client.on("disconnected", () => {
44
+ managed.online = false;
45
+ managed.busy = false;
46
+ managed.lastSeenAt = Date.now();
47
+ this.dispatchEvent(new CustomEvent("client:state", {
48
+ detail: { clientId: managed.id, online: false, busy: false, lastError: managed.lastError }
49
+ }));
50
+ });
51
+ client.on("reconnected", () => {
52
+ managed.online = true;
53
+ managed.lastSeenAt = Date.now();
54
+ this.dispatchEvent(new CustomEvent("client:state", {
55
+ detail: { clientId: managed.id, online: true, busy: managed.busy }
56
+ }));
57
+ });
58
+ }
59
+ list() {
60
+ return [...this.clients];
61
+ }
62
+ getClient(clientId) {
63
+ return this.clients.find((c) => c.id === clientId);
64
+ }
65
+ claim(job) {
66
+ const candidates = this.clients.filter((c) => c.online && !c.busy);
67
+ const preferred = job.options.preferredClientIds?.length
68
+ ? candidates.filter((c) => job.options.preferredClientIds?.includes(c.id))
69
+ : candidates;
70
+ const filtered = preferred
71
+ .filter((client) => !job.options.excludeClientIds?.includes(client.id))
72
+ .filter((client) => !this.strategy.shouldSkipClient(client, job));
73
+ const chosen = filtered[0];
74
+ if (!chosen) {
75
+ return null;
76
+ }
77
+ chosen.busy = true;
78
+ chosen.lastSeenAt = Date.now();
79
+ return {
80
+ client: chosen.client,
81
+ clientId: chosen.id,
82
+ release: (opts) => {
83
+ chosen.busy = false;
84
+ if (opts?.success) {
85
+ const wasBlocked = this.strategy.isWorkflowBlocked?.(chosen, job.workflowHash) ?? false;
86
+ this.strategy.recordSuccess(chosen, job);
87
+ const stillBlocked = this.strategy.isWorkflowBlocked?.(chosen, job.workflowHash) ?? false;
88
+ if (wasBlocked && !stillBlocked) {
89
+ this.emitUnblocked(chosen.id, job.workflowHash);
90
+ }
91
+ }
92
+ this.dispatchEvent(new CustomEvent("client:state", {
93
+ detail: { clientId: chosen.id, online: chosen.online, busy: chosen.busy }
94
+ }));
95
+ }
96
+ };
97
+ }
98
+ recordFailure(clientId, job, error) {
99
+ const client = this.clients.find((c) => c.id === clientId);
100
+ if (!client) {
101
+ return;
102
+ }
103
+ client.lastError = error;
104
+ client.busy = false;
105
+ const wasBlocked = this.strategy.isWorkflowBlocked?.(client, job.workflowHash) ?? false;
106
+ this.strategy.recordFailure(client, job, error);
107
+ const isBlocked = this.strategy.isWorkflowBlocked?.(client, job.workflowHash) ?? false;
108
+ if (!wasBlocked && isBlocked) {
109
+ this.emitBlocked(client.id, job.workflowHash);
110
+ }
111
+ this.dispatchEvent(new CustomEvent("client:state", {
112
+ detail: { clientId: client.id, online: client.online, busy: client.busy, lastError: error }
113
+ }));
114
+ }
115
+ /**
116
+ * Start periodic health check to keep connections alive and detect issues early.
117
+ * Pings idle clients by polling their queue status.
118
+ */
119
+ startHealthCheck() {
120
+ if (this.healthCheckInterval) {
121
+ return; // Already running
122
+ }
123
+ this.healthCheckInterval = setInterval(() => {
124
+ this.performHealthCheck().catch((error) => {
125
+ console.error("[ClientManager] Health check error:", error);
126
+ });
127
+ }, this.healthCheckIntervalMs);
128
+ }
129
+ /**
130
+ * Perform health check on all clients.
131
+ * For idle clients, polls queue status to keep WebSocket alive and detect connection issues.
132
+ */
133
+ async performHealthCheck() {
134
+ for (const managed of this.clients) {
135
+ // Only ping idle (non-busy) clients to avoid interfering with active operations
136
+ if (!managed.busy && managed.online) {
137
+ try {
138
+ // Lightweight ping: poll queue status (triggers WebSocket activity)
139
+ await managed.client.getQueue();
140
+ managed.lastSeenAt = Date.now();
141
+ }
142
+ catch (error) {
143
+ // Health check failed - client may have connection issues
144
+ console.warn(`[ClientManager] Health check failed for client ${managed.id}:`, error);
145
+ // Don't mark as offline here - let the WebSocket disconnect event handle that
146
+ // This prevents false positives from temporary network hiccups
147
+ }
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * Stop health check interval (called during shutdown).
153
+ */
154
+ stopHealthCheck() {
155
+ if (this.healthCheckInterval) {
156
+ clearInterval(this.healthCheckInterval);
157
+ this.healthCheckInterval = null;
158
+ }
159
+ }
160
+ /**
161
+ * Cleanup resources when destroying the manager.
162
+ */
163
+ destroy() {
164
+ this.stopHealthCheck();
165
+ }
166
+ }
167
+ //# sourceMappingURL=ClientManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClientManager.js","sourceRoot":"","sources":["../../../src/pool/client/ClientManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ManagedClient } from "../client/ClientManager.js";
2
+ import type { JobRecord } from "../types/job.js";
3
+ import type { FailoverStrategy } from "./Strategy.js";
4
+ export declare class SmartFailoverStrategy implements FailoverStrategy {
5
+ private workflowFailures;
6
+ private cooldownMs;
7
+ private maxFailuresBeforeBlock;
8
+ constructor(opts?: {
9
+ cooldownMs?: number;
10
+ maxFailuresBeforeBlock?: number;
11
+ });
12
+ shouldSkipClient(client: ManagedClient, job: JobRecord): boolean;
13
+ recordFailure(client: ManagedClient, job: JobRecord, error: unknown): void;
14
+ recordSuccess(client: ManagedClient, job: JobRecord): void;
15
+ resetForWorkflow(workflowHash: string): void;
16
+ isWorkflowBlocked(client: ManagedClient, workflowHash: string): boolean;
17
+ }
18
+ //# sourceMappingURL=SmartFailoverStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartFailoverStrategy.d.ts","sourceRoot":"","sources":["../../../src/pool/failover/SmartFailoverStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAOtD,qBAAa,qBAAsB,YAAW,gBAAgB;IAC5D,OAAO,CAAC,gBAAgB,CAA6D;IACrF,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,sBAAsB,CAAS;gBAE3B,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;KAAE;IAK3E,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO;IAgBhE,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAe1E,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI;IAW1D,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAM5C,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;CAWxE"}
@@ -0,0 +1,65 @@
1
+ export class SmartFailoverStrategy {
2
+ workflowFailures = new Map();
3
+ cooldownMs;
4
+ maxFailuresBeforeBlock;
5
+ constructor(opts) {
6
+ this.cooldownMs = opts?.cooldownMs ?? 60_000;
7
+ this.maxFailuresBeforeBlock = opts?.maxFailuresBeforeBlock ?? 1;
8
+ }
9
+ shouldSkipClient(client, job) {
10
+ const workflowMap = this.workflowFailures.get(client.id);
11
+ if (!workflowMap) {
12
+ return false;
13
+ }
14
+ const entry = workflowMap.get(job.workflowHash);
15
+ if (!entry) {
16
+ return false;
17
+ }
18
+ if (entry.blockedUntil > Date.now()) {
19
+ return true;
20
+ }
21
+ workflowMap.delete(job.workflowHash);
22
+ return false;
23
+ }
24
+ recordFailure(client, job, error) {
25
+ let workflowMap = this.workflowFailures.get(client.id);
26
+ if (!workflowMap) {
27
+ workflowMap = new Map();
28
+ this.workflowFailures.set(client.id, workflowMap);
29
+ }
30
+ const existing = workflowMap.get(job.workflowHash);
31
+ const failureCount = (existing?.failureCount ?? 0) + 1;
32
+ const blocked = failureCount >= this.maxFailuresBeforeBlock;
33
+ workflowMap.set(job.workflowHash, {
34
+ failureCount,
35
+ blockedUntil: blocked ? Date.now() + this.cooldownMs : Date.now()
36
+ });
37
+ }
38
+ recordSuccess(client, job) {
39
+ const workflowMap = this.workflowFailures.get(client.id);
40
+ if (!workflowMap) {
41
+ return;
42
+ }
43
+ workflowMap.delete(job.workflowHash);
44
+ if (workflowMap.size === 0) {
45
+ this.workflowFailures.delete(client.id);
46
+ }
47
+ }
48
+ resetForWorkflow(workflowHash) {
49
+ for (const [, map] of this.workflowFailures) {
50
+ map.delete(workflowHash);
51
+ }
52
+ }
53
+ isWorkflowBlocked(client, workflowHash) {
54
+ const workflowMap = this.workflowFailures.get(client.id);
55
+ if (!workflowMap) {
56
+ return false;
57
+ }
58
+ const entry = workflowMap.get(workflowHash);
59
+ if (!entry) {
60
+ return false;
61
+ }
62
+ return entry.blockedUntil > Date.now();
63
+ }
64
+ }
65
+ //# sourceMappingURL=SmartFailoverStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartFailoverStrategy.js","sourceRoot":"","sources":["../../../src/pool/failover/SmartFailoverStrategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { ManagedClient } from "../client/ClientManager.js";
2
+ import type { JobRecord } from "../types/job.js";
3
+ export interface FailoverStrategy {
4
+ shouldSkipClient(client: ManagedClient, job: JobRecord): boolean;
5
+ recordFailure(client: ManagedClient, job: JobRecord, error: unknown): void;
6
+ recordSuccess(client: ManagedClient, job: JobRecord): void;
7
+ resetForWorkflow?(workflowHash: string): void;
8
+ isWorkflowBlocked?(client: ManagedClient, workflowHash: string): boolean;
9
+ }
10
+ //# sourceMappingURL=Strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Strategy.d.ts","sourceRoot":"","sources":["../../../src/pool/failover/Strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC;IACjE,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3E,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3D,gBAAgB,CAAC,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,iBAAiB,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Strategy.js","sourceRoot":"","sources":["../../../src/pool/failover/Strategy.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export { WorkflowPool } from "./WorkflowPool.js";
2
+ export type { WorkflowPoolOpts } from "./WorkflowPool.js";
3
+ export type { WorkflowPoolEventMap } from "./types/events.js";
4
+ export type { JobRecord, JobStatus, WorkflowJobOptions } from "./types/job.js";
5
+ export type { QueueAdapter, QueueReservation, QueueStats } from "./queue/QueueAdapter.js";
6
+ export { MemoryQueueAdapter } from "./queue/adapters/memory.js";
7
+ export type { FailoverStrategy } from "./failover/Strategy.js";
8
+ export { SmartFailoverStrategy } from "./failover/SmartFailoverStrategy.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { WorkflowPool } from "./WorkflowPool.js";
2
+ export { MemoryQueueAdapter } from "./queue/adapters/memory.js";
3
+ export { SmartFailoverStrategy } from "./failover/SmartFailoverStrategy.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { WorkflowJobPayload } from "../types/job.js";
2
+ export interface QueueStats {
3
+ waiting: number;
4
+ inFlight: number;
5
+ delayed: number;
6
+ failed: number;
7
+ }
8
+ export interface QueueReservation {
9
+ /** Unique reservation identifier (often equals the jobId for in-memory implementation). */
10
+ reservationId: string;
11
+ payload: WorkflowJobPayload;
12
+ attempt: number;
13
+ /** Optional timestamp when the item becomes visible again (for delayed retries). */
14
+ availableAt?: number;
15
+ }
16
+ export interface QueueAdapter {
17
+ enqueue(payload: WorkflowJobPayload, opts?: {
18
+ priority?: number;
19
+ delayMs?: number;
20
+ }): Promise<void>;
21
+ reserve(): Promise<QueueReservation | null>;
22
+ commit(reservationId: string): Promise<void>;
23
+ retry(reservationId: string, opts?: {
24
+ delayMs?: number;
25
+ }): Promise<void>;
26
+ discard(reservationId: string, reason?: unknown): Promise<void>;
27
+ remove(jobId: string): Promise<boolean>;
28
+ stats(): Promise<QueueStats>;
29
+ shutdown(): Promise<void>;
30
+ }
31
+ //# sourceMappingURL=QueueAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueueAdapter.d.ts","sourceRoot":"","sources":["../../../src/pool/queue/QueueAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2FAA2F;IAC3F,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpG,OAAO,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=QueueAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueueAdapter.js","sourceRoot":"","sources":["../../../src/pool/queue/QueueAdapter.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { QueueAdapter, QueueReservation, QueueStats } from "../QueueAdapter.js";
2
+ import type { WorkflowJobPayload } from "../../types/job.js";
3
+ export declare class MemoryQueueAdapter implements QueueAdapter {
4
+ private waiting;
5
+ private inFlight;
6
+ private failed;
7
+ enqueue(payload: WorkflowJobPayload, opts?: {
8
+ priority?: number;
9
+ delayMs?: number;
10
+ }): Promise<void>;
11
+ reserve(): Promise<QueueReservation | null>;
12
+ commit(reservationId: string): Promise<void>;
13
+ retry(reservationId: string, opts?: {
14
+ delayMs?: number;
15
+ }): Promise<void>;
16
+ discard(reservationId: string, reason?: unknown): Promise<void>;
17
+ remove(jobId: string): Promise<boolean>;
18
+ stats(): Promise<QueueStats>;
19
+ shutdown(): Promise<void>;
20
+ }
21
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../src/pool/queue/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAS7D,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,MAAM,CAAyE;IAEjF,OAAO,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBnG,OAAO,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAgB3C,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBxE,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvC,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAS5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
@@ -0,0 +1,96 @@
1
+ export class MemoryQueueAdapter {
2
+ waiting = [];
3
+ inFlight = new Map();
4
+ failed = new Map();
5
+ async enqueue(payload, opts) {
6
+ const priority = opts?.priority ?? 0;
7
+ const availableAt = opts?.delayMs ? Date.now() + opts.delayMs : Date.now();
8
+ const existingFlight = this.inFlight.get(payload.jobId);
9
+ if (existingFlight) {
10
+ // If job is re-enqueued while still marked in-flight, treat as retry (replace entry)
11
+ this.inFlight.delete(payload.jobId);
12
+ }
13
+ const entry = {
14
+ payload,
15
+ attempt: payload.attempts,
16
+ priority,
17
+ availableAt
18
+ };
19
+ this.waiting.push(entry);
20
+ this.waiting.sort((a, b) => {
21
+ if (a.priority === b.priority) {
22
+ return a.availableAt - b.availableAt;
23
+ }
24
+ return b.priority - a.priority;
25
+ });
26
+ }
27
+ async reserve() {
28
+ const now = Date.now();
29
+ const idx = this.waiting.findIndex((entry) => entry.availableAt <= now);
30
+ if (idx === -1) {
31
+ return null;
32
+ }
33
+ const [entry] = this.waiting.splice(idx, 1);
34
+ this.inFlight.set(entry.payload.jobId, entry);
35
+ return {
36
+ reservationId: entry.payload.jobId,
37
+ payload: entry.payload,
38
+ attempt: entry.payload.attempts,
39
+ availableAt: entry.availableAt
40
+ };
41
+ }
42
+ async commit(reservationId) {
43
+ this.inFlight.delete(reservationId);
44
+ this.failed.delete(reservationId);
45
+ }
46
+ async retry(reservationId, opts) {
47
+ const entry = this.inFlight.get(reservationId);
48
+ if (!entry) {
49
+ return;
50
+ }
51
+ this.inFlight.delete(reservationId);
52
+ entry.payload.attempts += 1;
53
+ entry.attempt = entry.payload.attempts;
54
+ entry.availableAt = opts?.delayMs ? Date.now() + opts.delayMs : Date.now();
55
+ this.waiting.push(entry);
56
+ this.waiting.sort((a, b) => {
57
+ if (a.priority === b.priority) {
58
+ return a.availableAt - b.availableAt;
59
+ }
60
+ return b.priority - a.priority;
61
+ });
62
+ }
63
+ async discard(reservationId, reason) {
64
+ const entry = this.inFlight.get(reservationId);
65
+ if (!entry) {
66
+ return;
67
+ }
68
+ this.inFlight.delete(reservationId);
69
+ this.failed.set(reservationId, { entry, reason });
70
+ }
71
+ async remove(jobId) {
72
+ const waitingIdx = this.waiting.findIndex((entry) => entry.payload.jobId === jobId);
73
+ if (waitingIdx !== -1) {
74
+ this.waiting.splice(waitingIdx, 1);
75
+ return true;
76
+ }
77
+ if (this.inFlight.has(jobId)) {
78
+ return false;
79
+ }
80
+ return this.failed.delete(jobId);
81
+ }
82
+ async stats() {
83
+ return {
84
+ waiting: this.waiting.length,
85
+ inFlight: this.inFlight.size,
86
+ delayed: this.waiting.filter((entry) => entry.availableAt > Date.now()).length,
87
+ failed: this.failed.size
88
+ };
89
+ }
90
+ async shutdown() {
91
+ this.waiting = [];
92
+ this.inFlight.clear();
93
+ this.failed.clear();
94
+ }
95
+ }
96
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../../src/pool/queue/adapters/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { TypedEventTarget } from "../../typed-event-target.js";
2
+ import type { JobRecord } from "./job.js";
3
+ export interface WorkflowPoolEventMap extends Record<string, CustomEvent<any>> {
4
+ "pool:ready": CustomEvent<{
5
+ clientIds: string[];
6
+ }>;
7
+ "pool:error": CustomEvent<{
8
+ error: unknown;
9
+ }>;
10
+ "job:queued": CustomEvent<{
11
+ job: JobRecord;
12
+ }>;
13
+ "job:accepted": CustomEvent<{
14
+ job: JobRecord;
15
+ }>;
16
+ "job:started": CustomEvent<{
17
+ job: JobRecord;
18
+ }>;
19
+ "job:progress": CustomEvent<{
20
+ jobId: string;
21
+ clientId: string;
22
+ progress: any;
23
+ }>;
24
+ "job:preview": CustomEvent<{
25
+ jobId: string;
26
+ clientId: string;
27
+ blob: Blob;
28
+ }>;
29
+ "job:preview_meta": CustomEvent<{
30
+ jobId: string;
31
+ clientId: string;
32
+ payload: {
33
+ blob: Blob;
34
+ metadata: any;
35
+ };
36
+ }>;
37
+ "job:output": CustomEvent<{
38
+ jobId: string;
39
+ clientId: string;
40
+ key: string;
41
+ data: any;
42
+ }>;
43
+ "job:completed": CustomEvent<{
44
+ job: JobRecord;
45
+ }>;
46
+ "job:failed": CustomEvent<{
47
+ job: JobRecord;
48
+ willRetry: boolean;
49
+ }>;
50
+ "job:cancelled": CustomEvent<{
51
+ job: JobRecord;
52
+ }>;
53
+ "job:retrying": CustomEvent<{
54
+ job: JobRecord;
55
+ delayMs: number;
56
+ }>;
57
+ "client:state": CustomEvent<{
58
+ clientId: string;
59
+ online: boolean;
60
+ busy: boolean;
61
+ lastError?: unknown;
62
+ }>;
63
+ "client:blocked_workflow": CustomEvent<{
64
+ clientId: string;
65
+ workflowHash: string;
66
+ }>;
67
+ "client:unblocked_workflow": CustomEvent<{
68
+ clientId: string;
69
+ workflowHash: string;
70
+ }>;
71
+ }
72
+ export type WorkflowPoolEventTarget = TypedEventTarget<WorkflowPoolEventMap>;
73
+ export type WorkflowPoolEventName = keyof WorkflowPoolEventMap;
74
+ export type WorkflowPoolListener<K extends WorkflowPoolEventName> = (event: WorkflowPoolEventMap[K]) => void;
75
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/pool/types/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5E,YAAY,EAAE,WAAW,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACnD,YAAY,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,YAAY,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC9C,cAAc,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAChD,aAAa,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC/C,cAAc,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAChF,aAAa,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAC5E,kBAAkB,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,IAAI,EAAE,IAAI,CAAC;YAAC,QAAQ,EAAE,GAAG,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IAC7G,YAAY,EAAE,WAAW,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IACvF,eAAe,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACjD,YAAY,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,eAAe,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACjD,cAAc,EAAE,WAAW,CAAC;QAAE,GAAG,EAAE,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,cAAc,EAAE,WAAW,CAAC;QAC1B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,OAAO,CAAC;QAChB,IAAI,EAAE,OAAO,CAAC;QACd,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC,CAAC;IACH,yBAAyB,EAAE,WAAW,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnF,2BAA2B,EAAE,WAAW,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtF;AAED,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAC,oBAAoB,CAAC,CAAC;AAE7E,MAAM,MAAM,qBAAqB,GAAG,MAAM,oBAAoB,CAAC;AAE/D,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,qBAAqB,IAAI,CAClE,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAC3B,IAAI,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/pool/types/events.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import type { Workflow, WorkflowResult } from "../../workflow.js";
2
+ export type JobId = string;
3
+ export type WorkflowInput = Workflow | object | string | {
4
+ toJSON(): object;
5
+ };
6
+ export interface WorkflowJobAttachment {
7
+ nodeId: string;
8
+ inputName: string;
9
+ file: Blob | Buffer;
10
+ filename?: string;
11
+ }
12
+ export interface WorkflowJobOptions {
13
+ /** Optional priority (higher executes first). Defaults to 0. */
14
+ priority?: number;
15
+ /** Explicit job id to reuse. Random UUID generated when omitted. */
16
+ jobId?: JobId;
17
+ /** Maximum retry attempts across clients. Defaults to 3. */
18
+ maxAttempts?: number;
19
+ /** Milliseconds to wait before retrying a failed job. Defaults to 1000. */
20
+ retryDelayMs?: number;
21
+ /** Optional list of preferred client ids. */
22
+ preferredClientIds?: string[];
23
+ /** Optional list of client ids to exclude. */
24
+ excludeClientIds?: string[];
25
+ /** Arbitrary user metadata persisted alongside the job. */
26
+ metadata?: Record<string, unknown>;
27
+ /** Include node ids when collecting outputs from the workflow. */
28
+ includeOutputs?: string[];
29
+ /** File attachments for the workflow. */
30
+ attachments?: WorkflowJobAttachment[];
31
+ }
32
+ export type JobStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
33
+ export interface WorkflowJobPayload {
34
+ jobId: JobId;
35
+ workflow: object;
36
+ workflowHash: string;
37
+ options: Required<Pick<WorkflowJobOptions, "maxAttempts" | "retryDelayMs">> & Omit<WorkflowJobOptions, "maxAttempts" | "retryDelayMs" | "jobId" | "attachments">;
38
+ attempts: number;
39
+ enqueuedAt: number;
40
+ /** Workflow metadata (outputAliases, outputNodeIds) preserved from Workflow instance */
41
+ workflowMeta?: {
42
+ outputNodeIds?: string[];
43
+ outputAliases?: Record<string, string>;
44
+ };
45
+ }
46
+ export interface JobRecord extends WorkflowJobPayload {
47
+ attachments?: WorkflowJobAttachment[];
48
+ status: JobStatus;
49
+ lastError?: unknown;
50
+ clientId?: string;
51
+ promptId?: string;
52
+ result?: WorkflowResult | Record<string, unknown>;
53
+ startedAt?: number;
54
+ completedAt?: number;
55
+ }
56
+ //# sourceMappingURL=job.d.ts.map