@spooled/sdk 1.0.32 → 1.0.34
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-CfLL1w6Y.d.cts → index-CYEamGDj.d.cts} +48 -3
- package/dist/{index-CfLL1w6Y.d.ts → index-CYEamGDj.d.ts} +48 -3
- package/dist/index.cjs +87 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -8
- package/dist/index.d.ts +18 -8
- package/dist/index.js +87 -72
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +8 -4
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +8 -4
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
- package/proto/spooled.proto +13 -0
|
@@ -107,11 +107,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
107
|
successThreshold: number;
|
|
108
108
|
timeout: number;
|
|
109
109
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.0.
|
|
110
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.0.33";
|
|
111
111
|
readonly autoRefreshToken: true;
|
|
112
112
|
};
|
|
113
113
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.0.
|
|
114
|
+
declare const SDK_VERSION = "1.0.33";
|
|
115
115
|
/** API version prefix */
|
|
116
116
|
declare const API_VERSION = "v1";
|
|
117
117
|
/**
|
|
@@ -647,6 +647,13 @@ interface ClaimedJob {
|
|
|
647
647
|
maxRetries: number;
|
|
648
648
|
timeoutSeconds: number;
|
|
649
649
|
leaseExpiresAt?: string;
|
|
650
|
+
/**
|
|
651
|
+
* Lease fencing token for this claim. Echo it back on
|
|
652
|
+
* complete/fail/heartbeat so the operation applies only to the lease this
|
|
653
|
+
* worker actually holds (backend rejects stale leases with 409
|
|
654
|
+
* LEASE_EXPIRED). Omitted = legacy behavior.
|
|
655
|
+
*/
|
|
656
|
+
leaseId?: string;
|
|
650
657
|
}
|
|
651
658
|
/** Parameters for claiming jobs */
|
|
652
659
|
interface ClaimJobsParams {
|
|
@@ -669,6 +676,8 @@ interface CompleteJobParams {
|
|
|
669
676
|
workerId: string;
|
|
670
677
|
/** Optional result payload */
|
|
671
678
|
result?: JsonObject;
|
|
679
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
680
|
+
leaseId?: string;
|
|
672
681
|
}
|
|
673
682
|
/** Parameters for failing a job */
|
|
674
683
|
interface FailJobParams {
|
|
@@ -676,6 +685,8 @@ interface FailJobParams {
|
|
|
676
685
|
workerId: string;
|
|
677
686
|
/** Error message (1-2048 chars) */
|
|
678
687
|
error: string;
|
|
688
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
689
|
+
leaseId?: string;
|
|
679
690
|
}
|
|
680
691
|
/** Parameters for job heartbeat */
|
|
681
692
|
interface HeartbeatJobParams {
|
|
@@ -683,6 +694,8 @@ interface HeartbeatJobParams {
|
|
|
683
694
|
workerId: string;
|
|
684
695
|
/** Lease duration in seconds (5-3600) */
|
|
685
696
|
leaseDurationSecs: number;
|
|
697
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
698
|
+
leaseId?: string;
|
|
686
699
|
}
|
|
687
700
|
/** Response for priority boost */
|
|
688
701
|
interface BoostPriorityResponse {
|
|
@@ -2315,6 +2328,26 @@ interface JobStatusChangedEvent extends RealtimeEventBase {
|
|
|
2315
2328
|
newStatus: JobStatus;
|
|
2316
2329
|
};
|
|
2317
2330
|
}
|
|
2331
|
+
/** Queue stats update event (backend `QueueStats`) */
|
|
2332
|
+
interface QueueStatsEvent extends RealtimeEventBase {
|
|
2333
|
+
type: 'queue.stats';
|
|
2334
|
+
data: {
|
|
2335
|
+
queueName: string;
|
|
2336
|
+
pending: number;
|
|
2337
|
+
processing: number;
|
|
2338
|
+
completed: number;
|
|
2339
|
+
failed: number;
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
/** Worker heartbeat event (backend `WorkerHeartbeat`) */
|
|
2343
|
+
interface WorkerHeartbeatEvent extends RealtimeEventBase {
|
|
2344
|
+
type: 'worker.heartbeat';
|
|
2345
|
+
data: {
|
|
2346
|
+
workerId: string;
|
|
2347
|
+
status: string;
|
|
2348
|
+
currentJobId?: string;
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2318
2351
|
/** Queue paused event */
|
|
2319
2352
|
interface QueuePausedEvent extends RealtimeEventBase {
|
|
2320
2353
|
type: 'queue.paused';
|
|
@@ -2363,7 +2396,7 @@ interface HeartbeatEvent extends RealtimeEventBase {
|
|
|
2363
2396
|
};
|
|
2364
2397
|
}
|
|
2365
2398
|
/** All realtime event types */
|
|
2366
|
-
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2399
|
+
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueueStatsEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | WorkerHeartbeatEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2367
2400
|
/** Event type names */
|
|
2368
2401
|
type RealtimeEventType = RealtimeEvent['type'];
|
|
2369
2402
|
/** Extract event data type from event type name */
|
|
@@ -2582,6 +2615,12 @@ interface GrpcJob {
|
|
|
2582
2615
|
leaseExpiresAt?: GrpcTimestamp | string | null;
|
|
2583
2616
|
assignedWorkerId?: string | null;
|
|
2584
2617
|
idempotencyKey?: string | null;
|
|
2618
|
+
/**
|
|
2619
|
+
* Lease fencing token (proto `lease_id`). Returned on dequeue; echo it back
|
|
2620
|
+
* in Complete/Fail/RenewLease so the operation applies only to the lease
|
|
2621
|
+
* this worker actually holds (empty = legacy worker_id fence).
|
|
2622
|
+
*/
|
|
2623
|
+
leaseId?: string;
|
|
2585
2624
|
}
|
|
2586
2625
|
/** Enqueue request */
|
|
2587
2626
|
interface GrpcEnqueueRequest {
|
|
@@ -2617,6 +2656,8 @@ interface GrpcCompleteRequest {
|
|
|
2617
2656
|
workerId: string;
|
|
2618
2657
|
/** Result as object (will be converted to google.protobuf.Struct) */
|
|
2619
2658
|
result?: Record<string, unknown>;
|
|
2659
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2660
|
+
leaseId?: string;
|
|
2620
2661
|
}
|
|
2621
2662
|
/** Complete response */
|
|
2622
2663
|
interface GrpcCompleteResponse {
|
|
@@ -2628,6 +2669,8 @@ interface GrpcFailRequest {
|
|
|
2628
2669
|
workerId: string;
|
|
2629
2670
|
error: string;
|
|
2630
2671
|
retry?: boolean;
|
|
2672
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2673
|
+
leaseId?: string;
|
|
2631
2674
|
}
|
|
2632
2675
|
/** Fail response */
|
|
2633
2676
|
interface GrpcFailResponse {
|
|
@@ -2640,6 +2683,8 @@ interface GrpcRenewLeaseRequest {
|
|
|
2640
2683
|
jobId: string;
|
|
2641
2684
|
workerId: string;
|
|
2642
2685
|
extensionSecs: number;
|
|
2686
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2687
|
+
leaseId?: string;
|
|
2643
2688
|
}
|
|
2644
2689
|
/** Renew lease response */
|
|
2645
2690
|
interface GrpcRenewLeaseResponse {
|
|
@@ -107,11 +107,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
107
|
successThreshold: number;
|
|
108
108
|
timeout: number;
|
|
109
109
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.0.
|
|
110
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.0.33";
|
|
111
111
|
readonly autoRefreshToken: true;
|
|
112
112
|
};
|
|
113
113
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.0.
|
|
114
|
+
declare const SDK_VERSION = "1.0.33";
|
|
115
115
|
/** API version prefix */
|
|
116
116
|
declare const API_VERSION = "v1";
|
|
117
117
|
/**
|
|
@@ -647,6 +647,13 @@ interface ClaimedJob {
|
|
|
647
647
|
maxRetries: number;
|
|
648
648
|
timeoutSeconds: number;
|
|
649
649
|
leaseExpiresAt?: string;
|
|
650
|
+
/**
|
|
651
|
+
* Lease fencing token for this claim. Echo it back on
|
|
652
|
+
* complete/fail/heartbeat so the operation applies only to the lease this
|
|
653
|
+
* worker actually holds (backend rejects stale leases with 409
|
|
654
|
+
* LEASE_EXPIRED). Omitted = legacy behavior.
|
|
655
|
+
*/
|
|
656
|
+
leaseId?: string;
|
|
650
657
|
}
|
|
651
658
|
/** Parameters for claiming jobs */
|
|
652
659
|
interface ClaimJobsParams {
|
|
@@ -669,6 +676,8 @@ interface CompleteJobParams {
|
|
|
669
676
|
workerId: string;
|
|
670
677
|
/** Optional result payload */
|
|
671
678
|
result?: JsonObject;
|
|
679
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
680
|
+
leaseId?: string;
|
|
672
681
|
}
|
|
673
682
|
/** Parameters for failing a job */
|
|
674
683
|
interface FailJobParams {
|
|
@@ -676,6 +685,8 @@ interface FailJobParams {
|
|
|
676
685
|
workerId: string;
|
|
677
686
|
/** Error message (1-2048 chars) */
|
|
678
687
|
error: string;
|
|
688
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
689
|
+
leaseId?: string;
|
|
679
690
|
}
|
|
680
691
|
/** Parameters for job heartbeat */
|
|
681
692
|
interface HeartbeatJobParams {
|
|
@@ -683,6 +694,8 @@ interface HeartbeatJobParams {
|
|
|
683
694
|
workerId: string;
|
|
684
695
|
/** Lease duration in seconds (5-3600) */
|
|
685
696
|
leaseDurationSecs: number;
|
|
697
|
+
/** Lease fencing token from the claimed job (rejects stale leases when set) */
|
|
698
|
+
leaseId?: string;
|
|
686
699
|
}
|
|
687
700
|
/** Response for priority boost */
|
|
688
701
|
interface BoostPriorityResponse {
|
|
@@ -2315,6 +2328,26 @@ interface JobStatusChangedEvent extends RealtimeEventBase {
|
|
|
2315
2328
|
newStatus: JobStatus;
|
|
2316
2329
|
};
|
|
2317
2330
|
}
|
|
2331
|
+
/** Queue stats update event (backend `QueueStats`) */
|
|
2332
|
+
interface QueueStatsEvent extends RealtimeEventBase {
|
|
2333
|
+
type: 'queue.stats';
|
|
2334
|
+
data: {
|
|
2335
|
+
queueName: string;
|
|
2336
|
+
pending: number;
|
|
2337
|
+
processing: number;
|
|
2338
|
+
completed: number;
|
|
2339
|
+
failed: number;
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
/** Worker heartbeat event (backend `WorkerHeartbeat`) */
|
|
2343
|
+
interface WorkerHeartbeatEvent extends RealtimeEventBase {
|
|
2344
|
+
type: 'worker.heartbeat';
|
|
2345
|
+
data: {
|
|
2346
|
+
workerId: string;
|
|
2347
|
+
status: string;
|
|
2348
|
+
currentJobId?: string;
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2318
2351
|
/** Queue paused event */
|
|
2319
2352
|
interface QueuePausedEvent extends RealtimeEventBase {
|
|
2320
2353
|
type: 'queue.paused';
|
|
@@ -2363,7 +2396,7 @@ interface HeartbeatEvent extends RealtimeEventBase {
|
|
|
2363
2396
|
};
|
|
2364
2397
|
}
|
|
2365
2398
|
/** All realtime event types */
|
|
2366
|
-
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2399
|
+
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueueStatsEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | WorkerHeartbeatEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2367
2400
|
/** Event type names */
|
|
2368
2401
|
type RealtimeEventType = RealtimeEvent['type'];
|
|
2369
2402
|
/** Extract event data type from event type name */
|
|
@@ -2582,6 +2615,12 @@ interface GrpcJob {
|
|
|
2582
2615
|
leaseExpiresAt?: GrpcTimestamp | string | null;
|
|
2583
2616
|
assignedWorkerId?: string | null;
|
|
2584
2617
|
idempotencyKey?: string | null;
|
|
2618
|
+
/**
|
|
2619
|
+
* Lease fencing token (proto `lease_id`). Returned on dequeue; echo it back
|
|
2620
|
+
* in Complete/Fail/RenewLease so the operation applies only to the lease
|
|
2621
|
+
* this worker actually holds (empty = legacy worker_id fence).
|
|
2622
|
+
*/
|
|
2623
|
+
leaseId?: string;
|
|
2585
2624
|
}
|
|
2586
2625
|
/** Enqueue request */
|
|
2587
2626
|
interface GrpcEnqueueRequest {
|
|
@@ -2617,6 +2656,8 @@ interface GrpcCompleteRequest {
|
|
|
2617
2656
|
workerId: string;
|
|
2618
2657
|
/** Result as object (will be converted to google.protobuf.Struct) */
|
|
2619
2658
|
result?: Record<string, unknown>;
|
|
2659
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2660
|
+
leaseId?: string;
|
|
2620
2661
|
}
|
|
2621
2662
|
/** Complete response */
|
|
2622
2663
|
interface GrpcCompleteResponse {
|
|
@@ -2628,6 +2669,8 @@ interface GrpcFailRequest {
|
|
|
2628
2669
|
workerId: string;
|
|
2629
2670
|
error: string;
|
|
2630
2671
|
retry?: boolean;
|
|
2672
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2673
|
+
leaseId?: string;
|
|
2631
2674
|
}
|
|
2632
2675
|
/** Fail response */
|
|
2633
2676
|
interface GrpcFailResponse {
|
|
@@ -2640,6 +2683,8 @@ interface GrpcRenewLeaseRequest {
|
|
|
2640
2683
|
jobId: string;
|
|
2641
2684
|
workerId: string;
|
|
2642
2685
|
extensionSecs: number;
|
|
2686
|
+
/** Lease fencing token from the dequeued job (proto `lease_id`) */
|
|
2687
|
+
leaseId?: string;
|
|
2643
2688
|
}
|
|
2644
2689
|
/** Renew lease response */
|
|
2645
2690
|
interface GrpcRenewLeaseResponse {
|
package/dist/index.cjs
CHANGED
|
@@ -49,10 +49,10 @@ var DEFAULT_CONFIG = {
|
|
|
49
49
|
successThreshold: 3,
|
|
50
50
|
timeout: 3e4
|
|
51
51
|
},
|
|
52
|
-
userAgent: "@spooled/sdk-nodejs/1.0.
|
|
52
|
+
userAgent: "@spooled/sdk-nodejs/1.0.33",
|
|
53
53
|
autoRefreshToken: true
|
|
54
54
|
};
|
|
55
|
-
var SDK_VERSION = "1.0.
|
|
55
|
+
var SDK_VERSION = "1.0.33";
|
|
56
56
|
var API_VERSION = "v1";
|
|
57
57
|
var API_BASE_PATH = `/api/${API_VERSION}`;
|
|
58
58
|
function normalizeCredential(value) {
|
|
@@ -327,22 +327,33 @@ function parseRateLimitHeaders(headers) {
|
|
|
327
327
|
}
|
|
328
328
|
return info;
|
|
329
329
|
}
|
|
330
|
+
var MAX_RAW_ERROR_BODY_CHARS = 500;
|
|
330
331
|
async function parseErrorBody(response) {
|
|
331
332
|
const contentType = response.headers.get("Content-Type") || "";
|
|
332
|
-
|
|
333
|
+
let raw;
|
|
334
|
+
try {
|
|
335
|
+
raw = await response.text();
|
|
336
|
+
} catch {
|
|
333
337
|
return null;
|
|
334
338
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
339
|
+
if (contentType.includes("application/json")) {
|
|
340
|
+
try {
|
|
341
|
+
const body = JSON.parse(raw);
|
|
342
|
+
if (typeof body === "object" && body !== null) {
|
|
343
|
+
const message = (body.message ?? body.error) || response.statusText;
|
|
344
|
+
return {
|
|
345
|
+
code: body.code || "UNKNOWN_ERROR",
|
|
346
|
+
message,
|
|
347
|
+
details: body.details
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
} catch {
|
|
344
351
|
}
|
|
345
|
-
}
|
|
352
|
+
}
|
|
353
|
+
const trimmed = raw.trim();
|
|
354
|
+
if (trimmed) {
|
|
355
|
+
const message = trimmed.length > MAX_RAW_ERROR_BODY_CHARS ? `${trimmed.slice(0, MAX_RAW_ERROR_BODY_CHARS)}\u2026` : trimmed;
|
|
356
|
+
return { code: "UNKNOWN_ERROR", message };
|
|
346
357
|
}
|
|
347
358
|
return null;
|
|
348
359
|
}
|
|
@@ -1848,6 +1859,24 @@ var WebhookIngestionResource = class {
|
|
|
1848
1859
|
}
|
|
1849
1860
|
};
|
|
1850
1861
|
|
|
1862
|
+
// src/realtime/event-map.ts
|
|
1863
|
+
var BACKEND_EVENT_TYPE_MAP = {
|
|
1864
|
+
JobStatusChange: "job.status_changed",
|
|
1865
|
+
JobCreated: "job.created",
|
|
1866
|
+
JobCompleted: "job.completed",
|
|
1867
|
+
JobFailed: "job.failed",
|
|
1868
|
+
QueueStats: "queue.stats",
|
|
1869
|
+
WorkerHeartbeat: "worker.heartbeat",
|
|
1870
|
+
WorkerRegistered: "worker.registered",
|
|
1871
|
+
WorkerDeregistered: "worker.deregistered",
|
|
1872
|
+
SystemHealth: "system.health",
|
|
1873
|
+
Ping: "ping",
|
|
1874
|
+
Error: "error"
|
|
1875
|
+
};
|
|
1876
|
+
function mapEventType(type) {
|
|
1877
|
+
return BACKEND_EVENT_TYPE_MAP[type] ?? type;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1851
1880
|
// src/realtime/websocket.ts
|
|
1852
1881
|
var WebSocketRealtimeClient = class {
|
|
1853
1882
|
options;
|
|
@@ -1863,7 +1892,6 @@ var WebSocketRealtimeClient = class {
|
|
|
1863
1892
|
*/
|
|
1864
1893
|
authFailure = false;
|
|
1865
1894
|
subscriptions = /* @__PURE__ */ new Map();
|
|
1866
|
-
pendingCommands = /* @__PURE__ */ new Map();
|
|
1867
1895
|
// Event handlers
|
|
1868
1896
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
1869
1897
|
allEventsHandlers = /* @__PURE__ */ new Set();
|
|
@@ -1968,10 +1996,13 @@ var WebSocketRealtimeClient = class {
|
|
|
1968
1996
|
}
|
|
1969
1997
|
this.setState("disconnected");
|
|
1970
1998
|
this.subscriptions.clear();
|
|
1971
|
-
this.clearPendingCommands();
|
|
1972
1999
|
}
|
|
1973
2000
|
/**
|
|
1974
|
-
* Subscribe to events matching a filter
|
|
2001
|
+
* Subscribe to events matching a filter.
|
|
2002
|
+
*
|
|
2003
|
+
* The server applies filtering itself and sends no acknowledgement, so this
|
|
2004
|
+
* resolves as soon as the command has been written to the socket. The filter
|
|
2005
|
+
* is tracked locally so it is replayed automatically on reconnect.
|
|
1975
2006
|
*/
|
|
1976
2007
|
async subscribe(filter) {
|
|
1977
2008
|
const filterId = this.filterToId(filter);
|
|
@@ -1980,11 +2011,13 @@ var WebSocketRealtimeClient = class {
|
|
|
1980
2011
|
}
|
|
1981
2012
|
this.subscriptions.set(filterId, filter);
|
|
1982
2013
|
if (this.state === "connected") {
|
|
1983
|
-
|
|
2014
|
+
this.sendCommand("Subscribe", filter);
|
|
1984
2015
|
}
|
|
1985
2016
|
}
|
|
1986
2017
|
/**
|
|
1987
|
-
* Unsubscribe from events matching a filter
|
|
2018
|
+
* Unsubscribe from events matching a filter.
|
|
2019
|
+
*
|
|
2020
|
+
* Fire-and-forget, like {@link subscribe} — the server sends no ack.
|
|
1988
2021
|
*/
|
|
1989
2022
|
async unsubscribe(filter) {
|
|
1990
2023
|
const filterId = this.filterToId(filter);
|
|
@@ -1993,7 +2026,7 @@ var WebSocketRealtimeClient = class {
|
|
|
1993
2026
|
}
|
|
1994
2027
|
this.subscriptions.delete(filterId);
|
|
1995
2028
|
if (this.state === "connected") {
|
|
1996
|
-
|
|
2029
|
+
this.sendCommand("Unsubscribe", filter);
|
|
1997
2030
|
}
|
|
1998
2031
|
}
|
|
1999
2032
|
/**
|
|
@@ -2046,13 +2079,11 @@ var WebSocketRealtimeClient = class {
|
|
|
2046
2079
|
handleMessage(data) {
|
|
2047
2080
|
try {
|
|
2048
2081
|
const message = convertResponse(JSON.parse(data));
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
return;
|
|
2052
|
-
}
|
|
2082
|
+
const eventType = mapEventType(String(message.type));
|
|
2083
|
+
message.type = eventType;
|
|
2053
2084
|
const event = message;
|
|
2054
|
-
this.options.debug(`Received event: ${
|
|
2055
|
-
const handlers = this.eventHandlers.get(
|
|
2085
|
+
this.options.debug(`Received event: ${eventType}`, event);
|
|
2086
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
2056
2087
|
if (handlers) {
|
|
2057
2088
|
const eventData = event.data;
|
|
2058
2089
|
handlers.forEach((handler) => {
|
|
@@ -2074,25 +2105,8 @@ var WebSocketRealtimeClient = class {
|
|
|
2074
2105
|
this.options.debug("Failed to parse message", { data, error });
|
|
2075
2106
|
}
|
|
2076
2107
|
}
|
|
2077
|
-
handleCommandResponse(response) {
|
|
2078
|
-
if (!response.requestId) {
|
|
2079
|
-
return;
|
|
2080
|
-
}
|
|
2081
|
-
const pending = this.pendingCommands.get(response.requestId);
|
|
2082
|
-
if (!pending) {
|
|
2083
|
-
return;
|
|
2084
|
-
}
|
|
2085
|
-
clearTimeout(pending.timeout);
|
|
2086
|
-
this.pendingCommands.delete(response.requestId);
|
|
2087
|
-
if (response.type === "error") {
|
|
2088
|
-
pending.reject(new Error(response.error || "Unknown error"));
|
|
2089
|
-
} else {
|
|
2090
|
-
pending.resolve();
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
2108
|
handleDisconnect() {
|
|
2094
2109
|
this.ws = null;
|
|
2095
|
-
this.clearPendingCommands();
|
|
2096
2110
|
if (this.options.autoReconnect && this.reconnectAttempts < this.options.maxReconnectAttempts) {
|
|
2097
2111
|
this.scheduleReconnect();
|
|
2098
2112
|
} else {
|
|
@@ -2116,43 +2130,37 @@ var WebSocketRealtimeClient = class {
|
|
|
2116
2130
|
}
|
|
2117
2131
|
}, delay);
|
|
2118
2132
|
}
|
|
2119
|
-
|
|
2133
|
+
resubscribeAll() {
|
|
2120
2134
|
for (const filter of this.subscriptions.values()) {
|
|
2121
2135
|
try {
|
|
2122
|
-
|
|
2136
|
+
this.sendCommand("Subscribe", filter);
|
|
2123
2137
|
} catch (error) {
|
|
2124
2138
|
this.options.debug("Failed to resubscribe", { filter, error });
|
|
2125
2139
|
}
|
|
2126
2140
|
}
|
|
2127
2141
|
}
|
|
2128
|
-
|
|
2142
|
+
/**
|
|
2143
|
+
* Send a subscribe/unsubscribe command to the server.
|
|
2144
|
+
*
|
|
2145
|
+
* The backend `ClientCommand` shape is `{ cmd, queue, job_id }` and it sends
|
|
2146
|
+
* no acknowledgement, so this is fire-and-forget — it writes to the socket
|
|
2147
|
+
* and returns. The `SubscriptionFilter`'s `workerId`/`scheduleId` have no
|
|
2148
|
+
* server-side equivalent and are ignored.
|
|
2149
|
+
*/
|
|
2150
|
+
sendCommand(cmd, filter) {
|
|
2129
2151
|
if (!this.ws || this.state !== "connected") {
|
|
2130
2152
|
throw new Error("WebSocket not connected");
|
|
2131
2153
|
}
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
}, 1e4);
|
|
2139
|
-
this.pendingCommands.set(requestId, { resolve, reject, timeout });
|
|
2140
|
-
this.ws.send(JSON.stringify(fullCommand));
|
|
2141
|
-
});
|
|
2142
|
-
}
|
|
2143
|
-
clearPendingCommands() {
|
|
2144
|
-
for (const pending of this.pendingCommands.values()) {
|
|
2145
|
-
clearTimeout(pending.timeout);
|
|
2146
|
-
pending.reject(new Error("Connection closed"));
|
|
2147
|
-
}
|
|
2148
|
-
this.pendingCommands.clear();
|
|
2154
|
+
const command = {
|
|
2155
|
+
cmd,
|
|
2156
|
+
queue: filter.queueName,
|
|
2157
|
+
job_id: filter.jobId
|
|
2158
|
+
};
|
|
2159
|
+
this.ws.send(JSON.stringify(command));
|
|
2149
2160
|
}
|
|
2150
2161
|
filterToId(filter) {
|
|
2151
2162
|
return JSON.stringify(filter);
|
|
2152
2163
|
}
|
|
2153
|
-
generateRequestId() {
|
|
2154
|
-
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
2155
|
-
}
|
|
2156
2164
|
};
|
|
2157
2165
|
function redactToken(url) {
|
|
2158
2166
|
return url.replace(/([?&](?:token|api_key)=)[^&]*/gi, "$1***");
|
|
@@ -2351,9 +2359,12 @@ var SseRealtimeClient = class {
|
|
|
2351
2359
|
}
|
|
2352
2360
|
handleMessage(data) {
|
|
2353
2361
|
try {
|
|
2354
|
-
const
|
|
2355
|
-
|
|
2356
|
-
|
|
2362
|
+
const parsed = convertResponse(JSON.parse(data));
|
|
2363
|
+
const eventType = mapEventType(String(parsed.type));
|
|
2364
|
+
parsed.type = eventType;
|
|
2365
|
+
const event = parsed;
|
|
2366
|
+
this.options.debug(`Received SSE event: ${eventType}`, event);
|
|
2367
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
2357
2368
|
if (handlers) {
|
|
2358
2369
|
const eventData = event.data;
|
|
2359
2370
|
handlers.forEach((handler) => {
|
|
@@ -3277,7 +3288,7 @@ var SpooledWorker = class {
|
|
|
3277
3288
|
...DEFAULT_OPTIONS,
|
|
3278
3289
|
hostname: os.hostname(),
|
|
3279
3290
|
workerType: "nodejs",
|
|
3280
|
-
version: "1.0.
|
|
3291
|
+
version: "1.0.34",
|
|
3281
3292
|
metadata: {},
|
|
3282
3293
|
...options
|
|
3283
3294
|
};
|
|
@@ -3522,7 +3533,8 @@ var SpooledWorker = class {
|
|
|
3522
3533
|
try {
|
|
3523
3534
|
await this.client.jobs.complete(job.id, {
|
|
3524
3535
|
workerId: this.workerId,
|
|
3525
|
-
result
|
|
3536
|
+
result,
|
|
3537
|
+
...job.leaseId !== void 0 && { leaseId: job.leaseId }
|
|
3526
3538
|
});
|
|
3527
3539
|
this.emit("job:completed", {
|
|
3528
3540
|
jobId: job.id,
|
|
@@ -3539,7 +3551,8 @@ var SpooledWorker = class {
|
|
|
3539
3551
|
try {
|
|
3540
3552
|
await this.client.jobs.fail(job.id, {
|
|
3541
3553
|
workerId: this.workerId,
|
|
3542
|
-
error: errorMessage
|
|
3554
|
+
error: errorMessage,
|
|
3555
|
+
...job.leaseId !== void 0 && { leaseId: job.leaseId }
|
|
3543
3556
|
});
|
|
3544
3557
|
this.emit("job:failed", {
|
|
3545
3558
|
jobId: job.id,
|
|
@@ -3560,10 +3573,12 @@ var SpooledWorker = class {
|
|
|
3560
3573
|
}
|
|
3561
3574
|
async sendJobHeartbeat(jobId) {
|
|
3562
3575
|
if (!this.workerId) return;
|
|
3576
|
+
const leaseId = this.activeJobs.get(jobId)?.job.leaseId;
|
|
3563
3577
|
try {
|
|
3564
3578
|
await this.client.jobs.heartbeat(jobId, {
|
|
3565
3579
|
workerId: this.workerId,
|
|
3566
|
-
leaseDurationSecs: this.options.leaseDuration
|
|
3580
|
+
leaseDurationSecs: this.options.leaseDuration,
|
|
3581
|
+
...leaseId !== void 0 && { leaseId }
|
|
3567
3582
|
});
|
|
3568
3583
|
} catch (error) {
|
|
3569
3584
|
this.debug(`Job heartbeat failed for ${jobId}`, error);
|