@spooled/sdk 1.0.39 → 1.0.40
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/README.md +116 -94
- package/dist/{index-Lgo8JxCV.d.cts → index-DA_znF4h.d.cts} +80 -66
- package/dist/{index-Lgo8JxCV.d.ts → index-DA_znF4h.d.ts} +80 -66
- package/dist/index.cjs +363 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +363 -90
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +14 -5
- 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 +14 -5
- package/dist/worker/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -26,10 +26,10 @@ var DEFAULT_CONFIG = {
|
|
|
26
26
|
successThreshold: 3,
|
|
27
27
|
timeout: 3e4
|
|
28
28
|
},
|
|
29
|
-
userAgent: "@spooled/sdk-nodejs/1.0.
|
|
29
|
+
userAgent: "@spooled/sdk-nodejs/1.0.40",
|
|
30
30
|
autoRefreshToken: true
|
|
31
31
|
};
|
|
32
|
-
var SDK_VERSION = "1.0.
|
|
32
|
+
var SDK_VERSION = "1.0.40";
|
|
33
33
|
var API_VERSION = "v1";
|
|
34
34
|
var API_BASE_PATH = `/api/${API_VERSION}`;
|
|
35
35
|
function normalizeCredential(value) {
|
|
@@ -355,13 +355,31 @@ async function createErrorFromResponse(response) {
|
|
|
355
355
|
return new PayloadTooLargeError(message, code, details, requestId);
|
|
356
356
|
case 429: {
|
|
357
357
|
const rateLimitInfo = parseRateLimitHeaders(response.headers);
|
|
358
|
-
return new RateLimitError(
|
|
358
|
+
return new RateLimitError(
|
|
359
|
+
message,
|
|
360
|
+
code,
|
|
361
|
+
rateLimitInfo,
|
|
362
|
+
details,
|
|
363
|
+
requestId
|
|
364
|
+
);
|
|
359
365
|
}
|
|
360
366
|
default:
|
|
361
367
|
if (response.status >= 500) {
|
|
362
|
-
return new ServerError(
|
|
368
|
+
return new ServerError(
|
|
369
|
+
message,
|
|
370
|
+
response.status,
|
|
371
|
+
code,
|
|
372
|
+
details,
|
|
373
|
+
requestId
|
|
374
|
+
);
|
|
363
375
|
}
|
|
364
|
-
return new SpooledError(
|
|
376
|
+
return new SpooledError(
|
|
377
|
+
message,
|
|
378
|
+
response.status,
|
|
379
|
+
code,
|
|
380
|
+
details,
|
|
381
|
+
requestId
|
|
382
|
+
);
|
|
365
383
|
}
|
|
366
384
|
}
|
|
367
385
|
function isSpooledError(error) {
|
|
@@ -619,7 +637,9 @@ var HttpClient = class {
|
|
|
619
637
|
if (externalSignal.aborted) {
|
|
620
638
|
controller.abort();
|
|
621
639
|
} else {
|
|
622
|
-
externalSignal.addEventListener("abort", () => controller.abort(), {
|
|
640
|
+
externalSignal.addEventListener("abort", () => controller.abort(), {
|
|
641
|
+
once: true
|
|
642
|
+
});
|
|
623
643
|
}
|
|
624
644
|
}
|
|
625
645
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -634,7 +654,10 @@ var HttpClient = class {
|
|
|
634
654
|
if (externalSignal?.aborted) {
|
|
635
655
|
throw error;
|
|
636
656
|
}
|
|
637
|
-
throw new TimeoutError(
|
|
657
|
+
throw new TimeoutError(
|
|
658
|
+
`Request timed out after ${timeoutMs}ms`,
|
|
659
|
+
timeoutMs
|
|
660
|
+
);
|
|
638
661
|
}
|
|
639
662
|
throw error;
|
|
640
663
|
} finally {
|
|
@@ -663,13 +686,21 @@ var HttpClient = class {
|
|
|
663
686
|
this.debug?.(`${method} ${url}`, { timeout, hasBody: !!options.body });
|
|
664
687
|
let response;
|
|
665
688
|
try {
|
|
666
|
-
response = await this.fetchWithTimeout(
|
|
689
|
+
response = await this.fetchWithTimeout(
|
|
690
|
+
url,
|
|
691
|
+
init,
|
|
692
|
+
timeout,
|
|
693
|
+
options.signal
|
|
694
|
+
);
|
|
667
695
|
} catch (error) {
|
|
668
696
|
if (error instanceof TimeoutError || error instanceof SpooledError) {
|
|
669
697
|
throw error;
|
|
670
698
|
}
|
|
671
699
|
const cause = error instanceof Error ? error : void 0;
|
|
672
|
-
throw new NetworkError(
|
|
700
|
+
throw new NetworkError(
|
|
701
|
+
`Network request failed: ${cause?.message ?? "Unknown error"}`,
|
|
702
|
+
cause
|
|
703
|
+
);
|
|
673
704
|
}
|
|
674
705
|
this.debug?.(`Response: ${response.status}`, { url });
|
|
675
706
|
if (!response.ok) {
|
|
@@ -716,7 +747,9 @@ var HttpClient = class {
|
|
|
716
747
|
const url = this.buildUrl(path, options.params, options.skipApiPrefix);
|
|
717
748
|
const method = options.method ?? "GET";
|
|
718
749
|
const execute = async () => {
|
|
719
|
-
return this.circuitBreaker.execute(
|
|
750
|
+
return this.circuitBreaker.execute(
|
|
751
|
+
() => this.executeRequest(url, options)
|
|
752
|
+
);
|
|
720
753
|
};
|
|
721
754
|
if (options.skipRetry) {
|
|
722
755
|
return execute();
|
|
@@ -725,7 +758,9 @@ var HttpClient = class {
|
|
|
725
758
|
config: this.resolveRetryConfig(method, options),
|
|
726
759
|
signal: options.signal,
|
|
727
760
|
onRetry: (attempt, error, delayMs) => {
|
|
728
|
-
this.debug?.(`Retry attempt ${attempt} after ${delayMs}ms`, {
|
|
761
|
+
this.debug?.(`Retry attempt ${attempt} after ${delayMs}ms`, {
|
|
762
|
+
error: error.message
|
|
763
|
+
});
|
|
729
764
|
}
|
|
730
765
|
});
|
|
731
766
|
}
|
|
@@ -737,7 +772,9 @@ var HttpClient = class {
|
|
|
737
772
|
if (!options.headers) {
|
|
738
773
|
return false;
|
|
739
774
|
}
|
|
740
|
-
return Object.keys(options.headers).some(
|
|
775
|
+
return Object.keys(options.headers).some(
|
|
776
|
+
(key) => key.toLowerCase() === "idempotency-key"
|
|
777
|
+
);
|
|
741
778
|
}
|
|
742
779
|
/**
|
|
743
780
|
* Resolve the retry configuration for a request.
|
|
@@ -775,28 +812,43 @@ var HttpClient = class {
|
|
|
775
812
|
* Make a POST request
|
|
776
813
|
*/
|
|
777
814
|
async post(path, body, options) {
|
|
778
|
-
const response = await this.request(path, {
|
|
815
|
+
const response = await this.request(path, {
|
|
816
|
+
...options,
|
|
817
|
+
method: "POST",
|
|
818
|
+
body
|
|
819
|
+
});
|
|
779
820
|
return response.data;
|
|
780
821
|
}
|
|
781
822
|
/**
|
|
782
823
|
* Make a PUT request
|
|
783
824
|
*/
|
|
784
825
|
async put(path, body, options) {
|
|
785
|
-
const response = await this.request(path, {
|
|
826
|
+
const response = await this.request(path, {
|
|
827
|
+
...options,
|
|
828
|
+
method: "PUT",
|
|
829
|
+
body
|
|
830
|
+
});
|
|
786
831
|
return response.data;
|
|
787
832
|
}
|
|
788
833
|
/**
|
|
789
834
|
* Make a PATCH request
|
|
790
835
|
*/
|
|
791
836
|
async patch(path, body, options) {
|
|
792
|
-
const response = await this.request(path, {
|
|
837
|
+
const response = await this.request(path, {
|
|
838
|
+
...options,
|
|
839
|
+
method: "PATCH",
|
|
840
|
+
body
|
|
841
|
+
});
|
|
793
842
|
return response.data;
|
|
794
843
|
}
|
|
795
844
|
/**
|
|
796
845
|
* Make a DELETE request
|
|
797
846
|
*/
|
|
798
847
|
async delete(path, options) {
|
|
799
|
-
const response = await this.request(path, {
|
|
848
|
+
const response = await this.request(path, {
|
|
849
|
+
...options,
|
|
850
|
+
method: "DELETE"
|
|
851
|
+
});
|
|
800
852
|
return response.data;
|
|
801
853
|
}
|
|
802
854
|
};
|
|
@@ -990,7 +1042,10 @@ var AuthResource = class {
|
|
|
990
1042
|
*/
|
|
991
1043
|
async logout(refreshToken) {
|
|
992
1044
|
const token = refreshToken ?? this.getRefreshToken?.();
|
|
993
|
-
await this.http.post(
|
|
1045
|
+
await this.http.post(
|
|
1046
|
+
"/auth/logout",
|
|
1047
|
+
token ? { refreshToken: token } : void 0
|
|
1048
|
+
);
|
|
994
1049
|
}
|
|
995
1050
|
/**
|
|
996
1051
|
* Get current user/session info
|
|
@@ -1008,7 +1063,10 @@ var AuthResource = class {
|
|
|
1008
1063
|
* Start email-based login flow (sends magic link)
|
|
1009
1064
|
*/
|
|
1010
1065
|
async startEmailLogin(email) {
|
|
1011
|
-
return this.http.post(
|
|
1066
|
+
return this.http.post(
|
|
1067
|
+
"/auth/email/start",
|
|
1068
|
+
{ email }
|
|
1069
|
+
);
|
|
1012
1070
|
}
|
|
1013
1071
|
/**
|
|
1014
1072
|
* Check if an email address exists in the system
|
|
@@ -1049,7 +1107,9 @@ var JobsResource = class {
|
|
|
1049
1107
|
* List jobs with optional filtering
|
|
1050
1108
|
*/
|
|
1051
1109
|
async list(params) {
|
|
1052
|
-
return this.http.get("/jobs", {
|
|
1110
|
+
return this.http.get("/jobs", {
|
|
1111
|
+
params
|
|
1112
|
+
});
|
|
1053
1113
|
}
|
|
1054
1114
|
/**
|
|
1055
1115
|
* Get a job by ID
|
|
@@ -1073,7 +1133,9 @@ var JobsResource = class {
|
|
|
1073
1133
|
* Boost job priority
|
|
1074
1134
|
*/
|
|
1075
1135
|
async boostPriority(id, priority) {
|
|
1076
|
-
return this.http.put(`/jobs/${id}/priority`, {
|
|
1136
|
+
return this.http.put(`/jobs/${id}/priority`, {
|
|
1137
|
+
priority
|
|
1138
|
+
});
|
|
1077
1139
|
}
|
|
1078
1140
|
/**
|
|
1079
1141
|
* Get job statistics
|
|
@@ -1118,17 +1180,25 @@ var JobsResource = class {
|
|
|
1118
1180
|
* Fail a job (worker nack)
|
|
1119
1181
|
*/
|
|
1120
1182
|
async fail(id, params) {
|
|
1121
|
-
return this.http.post(
|
|
1183
|
+
return this.http.post(
|
|
1184
|
+
`/jobs/${id}/fail`,
|
|
1185
|
+
params
|
|
1186
|
+
);
|
|
1122
1187
|
}
|
|
1123
1188
|
/**
|
|
1124
1189
|
* Extend job lease (heartbeat)
|
|
1125
1190
|
*/
|
|
1126
1191
|
async heartbeat(id, params) {
|
|
1127
|
-
return this.http.post(
|
|
1192
|
+
return this.http.post(
|
|
1193
|
+
`/jobs/${id}/heartbeat`,
|
|
1194
|
+
params
|
|
1195
|
+
);
|
|
1128
1196
|
}
|
|
1129
1197
|
// DLQ operations (private implementations)
|
|
1130
1198
|
async listDlq(params) {
|
|
1131
|
-
return this.http.get("/jobs/dlq", {
|
|
1199
|
+
return this.http.get("/jobs/dlq", {
|
|
1200
|
+
params
|
|
1201
|
+
});
|
|
1132
1202
|
}
|
|
1133
1203
|
async retryDlq(params) {
|
|
1134
1204
|
return this.http.post("/jobs/dlq/retry", params);
|
|
@@ -1159,13 +1229,18 @@ var QueuesResource = class {
|
|
|
1159
1229
|
* Update queue configuration
|
|
1160
1230
|
*/
|
|
1161
1231
|
async updateConfig(name, params) {
|
|
1162
|
-
return this.http.put(
|
|
1232
|
+
return this.http.put(
|
|
1233
|
+
`/queues/${encodeURIComponent(name)}/config`,
|
|
1234
|
+
params
|
|
1235
|
+
);
|
|
1163
1236
|
}
|
|
1164
1237
|
/**
|
|
1165
1238
|
* Get queue statistics
|
|
1166
1239
|
*/
|
|
1167
1240
|
async getStats(name) {
|
|
1168
|
-
return this.http.get(
|
|
1241
|
+
return this.http.get(
|
|
1242
|
+
`/queues/${encodeURIComponent(name)}/stats`
|
|
1243
|
+
);
|
|
1169
1244
|
}
|
|
1170
1245
|
/**
|
|
1171
1246
|
* Pause a queue
|
|
@@ -1180,7 +1255,9 @@ var QueuesResource = class {
|
|
|
1180
1255
|
* Resume a paused queue
|
|
1181
1256
|
*/
|
|
1182
1257
|
async resume(name) {
|
|
1183
|
-
return this.http.post(
|
|
1258
|
+
return this.http.post(
|
|
1259
|
+
`/queues/${encodeURIComponent(name)}/resume`
|
|
1260
|
+
);
|
|
1184
1261
|
}
|
|
1185
1262
|
/**
|
|
1186
1263
|
* Delete a queue configuration
|
|
@@ -1236,7 +1313,9 @@ var SchedulesResource = class {
|
|
|
1236
1313
|
* List all schedules
|
|
1237
1314
|
*/
|
|
1238
1315
|
async list(params) {
|
|
1239
|
-
return this.http.get("/schedules", {
|
|
1316
|
+
return this.http.get("/schedules", {
|
|
1317
|
+
params
|
|
1318
|
+
});
|
|
1240
1319
|
}
|
|
1241
1320
|
/**
|
|
1242
1321
|
* Create a new schedule
|
|
@@ -1308,7 +1387,9 @@ var WorkflowsResource = class {
|
|
|
1308
1387
|
* List all workflows
|
|
1309
1388
|
*/
|
|
1310
1389
|
async list(params) {
|
|
1311
|
-
return this.http.get("/workflows", {
|
|
1390
|
+
return this.http.get("/workflows", {
|
|
1391
|
+
params
|
|
1392
|
+
});
|
|
1312
1393
|
}
|
|
1313
1394
|
/**
|
|
1314
1395
|
* Create a new workflow
|
|
@@ -1345,13 +1426,18 @@ var WorkflowsResource = class {
|
|
|
1345
1426
|
return this.http.get(`/workflows/${workflowId}/jobs/${jobId}`);
|
|
1346
1427
|
}
|
|
1347
1428
|
async getWorkflowJobsStatus(workflowId) {
|
|
1348
|
-
return this.http.get(
|
|
1429
|
+
return this.http.get(
|
|
1430
|
+
`/workflows/${workflowId}/jobs/status`
|
|
1431
|
+
);
|
|
1349
1432
|
}
|
|
1350
1433
|
async getJobDependencies(jobId) {
|
|
1351
1434
|
return this.http.get(`/jobs/${jobId}/dependencies`);
|
|
1352
1435
|
}
|
|
1353
1436
|
async addJobDependencies(jobId, params) {
|
|
1354
|
-
return this.http.post(
|
|
1437
|
+
return this.http.post(
|
|
1438
|
+
`/jobs/${jobId}/dependencies`,
|
|
1439
|
+
params
|
|
1440
|
+
);
|
|
1355
1441
|
}
|
|
1356
1442
|
};
|
|
1357
1443
|
|
|
@@ -1400,7 +1486,9 @@ var WebhooksResource = class {
|
|
|
1400
1486
|
* Get webhook delivery history
|
|
1401
1487
|
*/
|
|
1402
1488
|
async getDeliveries(id) {
|
|
1403
|
-
return this.http.get(
|
|
1489
|
+
return this.http.get(
|
|
1490
|
+
`/outgoing-webhooks/${id}/deliveries`
|
|
1491
|
+
);
|
|
1404
1492
|
}
|
|
1405
1493
|
/**
|
|
1406
1494
|
* Retry a specific webhook delivery
|
|
@@ -1508,7 +1596,9 @@ var OrganizationsResource = class {
|
|
|
1508
1596
|
* Generate a unique slug from an organization name
|
|
1509
1597
|
*/
|
|
1510
1598
|
async generateSlug(name) {
|
|
1511
|
-
return this.http.post("/organizations/generate-slug", {
|
|
1599
|
+
return this.http.post("/organizations/generate-slug", {
|
|
1600
|
+
name
|
|
1601
|
+
});
|
|
1512
1602
|
}
|
|
1513
1603
|
/**
|
|
1514
1604
|
* Get the webhook token for the current organization.
|
|
@@ -1538,7 +1628,9 @@ var OrganizationsResource = class {
|
|
|
1538
1628
|
* ```
|
|
1539
1629
|
*/
|
|
1540
1630
|
async regenerateWebhookToken() {
|
|
1541
|
-
return this.http.post(
|
|
1631
|
+
return this.http.post(
|
|
1632
|
+
"/organizations/webhook-token/regenerate"
|
|
1633
|
+
);
|
|
1542
1634
|
}
|
|
1543
1635
|
/**
|
|
1544
1636
|
* Clear/delete the webhook token for the current organization.
|
|
@@ -1575,7 +1667,10 @@ var BillingResource = class {
|
|
|
1575
1667
|
* POST /api/v1/billing/portal
|
|
1576
1668
|
*/
|
|
1577
1669
|
async createPortal(params) {
|
|
1578
|
-
return this.http.post(
|
|
1670
|
+
return this.http.post(
|
|
1671
|
+
"/billing/portal",
|
|
1672
|
+
params
|
|
1673
|
+
);
|
|
1579
1674
|
}
|
|
1580
1675
|
};
|
|
1581
1676
|
|
|
@@ -1670,7 +1765,9 @@ var AdminResource = class {
|
|
|
1670
1765
|
}
|
|
1671
1766
|
headers() {
|
|
1672
1767
|
if (!this.adminKey) {
|
|
1673
|
-
throw new AuthenticationError(
|
|
1768
|
+
throw new AuthenticationError(
|
|
1769
|
+
"Admin key is required for admin endpoints. Provide `adminKey` in SpooledClient config."
|
|
1770
|
+
);
|
|
1674
1771
|
}
|
|
1675
1772
|
return { "X-Admin-Key": this.adminKey };
|
|
1676
1773
|
}
|
|
@@ -1691,15 +1788,22 @@ var AdminResource = class {
|
|
|
1691
1788
|
}
|
|
1692
1789
|
/** POST /api/v1/admin/organizations */
|
|
1693
1790
|
async createOrganization(params) {
|
|
1694
|
-
return this.http.post(
|
|
1695
|
-
|
|
1696
|
-
|
|
1791
|
+
return this.http.post(
|
|
1792
|
+
"/admin/organizations",
|
|
1793
|
+
params,
|
|
1794
|
+
{
|
|
1795
|
+
headers: this.headers()
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1697
1798
|
}
|
|
1698
1799
|
/** GET /api/v1/admin/organizations/{id} */
|
|
1699
1800
|
async getOrganization(id) {
|
|
1700
|
-
return this.http.get(
|
|
1701
|
-
|
|
1702
|
-
|
|
1801
|
+
return this.http.get(
|
|
1802
|
+
`/admin/organizations/${id}`,
|
|
1803
|
+
{
|
|
1804
|
+
headers: this.headers()
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1703
1807
|
}
|
|
1704
1808
|
/** PATCH /api/v1/admin/organizations/{id} */
|
|
1705
1809
|
async updateOrganization(id, params) {
|
|
@@ -1717,15 +1821,23 @@ var AdminResource = class {
|
|
|
1717
1821
|
}
|
|
1718
1822
|
/** POST /api/v1/admin/organizations/{id}/api-keys */
|
|
1719
1823
|
async createApiKey(orgId, params) {
|
|
1720
|
-
return this.http.post(
|
|
1721
|
-
|
|
1722
|
-
|
|
1824
|
+
return this.http.post(
|
|
1825
|
+
`/admin/organizations/${orgId}/api-keys`,
|
|
1826
|
+
params,
|
|
1827
|
+
{
|
|
1828
|
+
headers: this.headers()
|
|
1829
|
+
}
|
|
1830
|
+
);
|
|
1723
1831
|
}
|
|
1724
1832
|
/** POST /api/v1/admin/organizations/{id}/reset-usage */
|
|
1725
1833
|
async resetUsage(orgId) {
|
|
1726
|
-
await this.http.post(
|
|
1727
|
-
|
|
1728
|
-
|
|
1834
|
+
await this.http.post(
|
|
1835
|
+
`/admin/organizations/${orgId}/reset-usage`,
|
|
1836
|
+
void 0,
|
|
1837
|
+
{
|
|
1838
|
+
headers: this.headers()
|
|
1839
|
+
}
|
|
1840
|
+
);
|
|
1729
1841
|
}
|
|
1730
1842
|
/** GET /api/v1/admin/stats */
|
|
1731
1843
|
async getStats() {
|
|
@@ -1771,7 +1883,9 @@ var WebhookIngestionResource = class {
|
|
|
1771
1883
|
const bytes = toBytes(body);
|
|
1772
1884
|
const signature = options.signature ?? (options.secret ? githubSignature(options.secret, bytes) : void 0);
|
|
1773
1885
|
if (!signature) {
|
|
1774
|
-
throw new ValidationError(
|
|
1886
|
+
throw new ValidationError(
|
|
1887
|
+
"GitHub webhook signature is required (provide `signature` or `secret`)"
|
|
1888
|
+
);
|
|
1775
1889
|
}
|
|
1776
1890
|
const headers = {
|
|
1777
1891
|
"Content-Type": "application/json",
|
|
@@ -1802,7 +1916,9 @@ var WebhookIngestionResource = class {
|
|
|
1802
1916
|
const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
|
|
1803
1917
|
const signature = options.signature ?? (options.secret ? stripeSignature(options.secret, bytes, timestamp) : void 0);
|
|
1804
1918
|
if (!signature) {
|
|
1805
|
-
throw new ValidationError(
|
|
1919
|
+
throw new ValidationError(
|
|
1920
|
+
"Stripe webhook signature is required (provide `signature` or `secret`)"
|
|
1921
|
+
);
|
|
1806
1922
|
}
|
|
1807
1923
|
const headers = {
|
|
1808
1924
|
"Content-Type": "application/json",
|
|
@@ -1939,14 +2055,20 @@ var WebSocketRealtimeClient = class {
|
|
|
1939
2055
|
resolve();
|
|
1940
2056
|
};
|
|
1941
2057
|
this.ws.onmessage = (event) => {
|
|
1942
|
-
this.handleMessage(
|
|
2058
|
+
this.handleMessage(
|
|
2059
|
+
typeof event.data === "string" ? event.data : String(event.data)
|
|
2060
|
+
);
|
|
1943
2061
|
};
|
|
1944
2062
|
this.ws.onclose = (event) => {
|
|
1945
2063
|
this.options.debug(`WebSocket closed: ${event.code} ${event.reason}`);
|
|
1946
2064
|
const wasConnecting = this.state === "connecting";
|
|
1947
2065
|
this.handleDisconnect();
|
|
1948
2066
|
if (wasConnecting) {
|
|
1949
|
-
reject(
|
|
2067
|
+
reject(
|
|
2068
|
+
new Error(
|
|
2069
|
+
`WebSocket connection failed: ${event.reason || "Unknown error"}`
|
|
2070
|
+
)
|
|
2071
|
+
);
|
|
1950
2072
|
}
|
|
1951
2073
|
};
|
|
1952
2074
|
this.ws.onerror = (event) => {
|
|
@@ -2101,7 +2223,9 @@ var WebSocketRealtimeClient = class {
|
|
|
2101
2223
|
this.options.maxReconnectDelay
|
|
2102
2224
|
);
|
|
2103
2225
|
const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
|
|
2104
|
-
this.options.debug(
|
|
2226
|
+
this.options.debug(
|
|
2227
|
+
`Scheduling reconnect attempt ${this.reconnectAttempts} in ${delay}ms`
|
|
2228
|
+
);
|
|
2105
2229
|
this.reconnectTimer = setTimeout(async () => {
|
|
2106
2230
|
try {
|
|
2107
2231
|
await this.connect();
|
|
@@ -2154,11 +2278,13 @@ function isAuthFailureEvent(event) {
|
|
|
2154
2278
|
if (!event) {
|
|
2155
2279
|
return false;
|
|
2156
2280
|
}
|
|
2157
|
-
const
|
|
2158
|
-
if (
|
|
2281
|
+
const status2 = event.status ?? event.statusCode ?? event.error?.status;
|
|
2282
|
+
if (status2 === 401 || status2 === 403) {
|
|
2159
2283
|
return true;
|
|
2160
2284
|
}
|
|
2161
|
-
const text = String(
|
|
2285
|
+
const text = String(
|
|
2286
|
+
event.message ?? event.error?.message ?? event.reason ?? ""
|
|
2287
|
+
);
|
|
2162
2288
|
return /\b(401|403)\b/.test(text);
|
|
2163
2289
|
}
|
|
2164
2290
|
|
|
@@ -2221,7 +2347,9 @@ var SseRealtimeClient = class {
|
|
|
2221
2347
|
EventSourceImpl = mod.default || mod.EventSource || mod;
|
|
2222
2348
|
} catch {
|
|
2223
2349
|
this.setState("disconnected");
|
|
2224
|
-
throw new Error(
|
|
2350
|
+
throw new Error(
|
|
2351
|
+
"eventsource package is required for SSE in Node.js. Install it with: npm install eventsource"
|
|
2352
|
+
);
|
|
2225
2353
|
}
|
|
2226
2354
|
}
|
|
2227
2355
|
let token;
|
|
@@ -2390,7 +2518,9 @@ var SseRealtimeClient = class {
|
|
|
2390
2518
|
this.options.maxReconnectDelay
|
|
2391
2519
|
);
|
|
2392
2520
|
const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
|
|
2393
|
-
this.options.debug(
|
|
2521
|
+
this.options.debug(
|
|
2522
|
+
`Scheduling SSE reconnect attempt ${this.reconnectAttempts} in ${delay}ms`
|
|
2523
|
+
);
|
|
2394
2524
|
this.reconnectTimer = setTimeout(async () => {
|
|
2395
2525
|
try {
|
|
2396
2526
|
await this.connect(this.filter || void 0);
|
|
@@ -2566,7 +2696,10 @@ function loadProtoDefinition() {
|
|
|
2566
2696
|
return cachedDefinition;
|
|
2567
2697
|
}
|
|
2568
2698
|
const protoPath = getProtoPath();
|
|
2569
|
-
const packageDefinition = protoLoader.loadSync(
|
|
2699
|
+
const packageDefinition = protoLoader.loadSync(
|
|
2700
|
+
protoPath,
|
|
2701
|
+
PROTO_LOADER_OPTIONS
|
|
2702
|
+
);
|
|
2570
2703
|
const grpcObject = grpc2.loadPackageDefinition(packageDefinition);
|
|
2571
2704
|
cachedDefinition = grpcObject;
|
|
2572
2705
|
return cachedDefinition;
|
|
@@ -2576,7 +2709,10 @@ async function loadProtoDefinitionAsync() {
|
|
|
2576
2709
|
return cachedDefinition;
|
|
2577
2710
|
}
|
|
2578
2711
|
const protoPath = getProtoPath();
|
|
2579
|
-
const packageDefinition = await protoLoader.load(
|
|
2712
|
+
const packageDefinition = await protoLoader.load(
|
|
2713
|
+
protoPath,
|
|
2714
|
+
PROTO_LOADER_OPTIONS
|
|
2715
|
+
);
|
|
2580
2716
|
const grpcObject = grpc2.loadPackageDefinition(packageDefinition);
|
|
2581
2717
|
cachedDefinition = grpcObject;
|
|
2582
2718
|
return cachedDefinition;
|
|
@@ -2593,7 +2729,11 @@ async function* asyncIterableFromStream(stream, options) {
|
|
|
2593
2729
|
stream.cancel();
|
|
2594
2730
|
});
|
|
2595
2731
|
}
|
|
2596
|
-
return yield* new AsyncIterableStream(stream, {
|
|
2732
|
+
return yield* new AsyncIterableStream(stream, {
|
|
2733
|
+
onConnected,
|
|
2734
|
+
onError,
|
|
2735
|
+
onEnd
|
|
2736
|
+
});
|
|
2597
2737
|
}
|
|
2598
2738
|
var AsyncIterableStream = class {
|
|
2599
2739
|
stream;
|
|
@@ -2622,8 +2762,8 @@ var AsyncIterableStream = class {
|
|
|
2622
2762
|
onEnd?.();
|
|
2623
2763
|
resolve?.();
|
|
2624
2764
|
});
|
|
2625
|
-
this.stream.on("status", (
|
|
2626
|
-
if (
|
|
2765
|
+
this.stream.on("status", (status2) => {
|
|
2766
|
+
if (status2.code === 0) {
|
|
2627
2767
|
onConnected?.();
|
|
2628
2768
|
}
|
|
2629
2769
|
});
|
|
@@ -2724,7 +2864,9 @@ function decodeStruct(value) {
|
|
|
2724
2864
|
return value;
|
|
2725
2865
|
}
|
|
2726
2866
|
const fields = value.fields ?? {};
|
|
2727
|
-
return Object.fromEntries(
|
|
2867
|
+
return Object.fromEntries(
|
|
2868
|
+
Object.entries(fields).map(([key, entry]) => [key, decodeValue(entry)])
|
|
2869
|
+
);
|
|
2728
2870
|
}
|
|
2729
2871
|
function decodeValue(value) {
|
|
2730
2872
|
if ("nullValue" in value) {
|
|
@@ -2773,7 +2915,10 @@ function encodeEnqueueRequest(params) {
|
|
|
2773
2915
|
return encoded;
|
|
2774
2916
|
}
|
|
2775
2917
|
function encodeCompleteRequest(params) {
|
|
2776
|
-
return {
|
|
2918
|
+
return {
|
|
2919
|
+
...params,
|
|
2920
|
+
result: encodeStruct(params.result)
|
|
2921
|
+
};
|
|
2777
2922
|
}
|
|
2778
2923
|
function decodeJob(job) {
|
|
2779
2924
|
return {
|
|
@@ -2782,17 +2927,60 @@ function decodeJob(job) {
|
|
|
2782
2927
|
result: decodeStruct(job.result)
|
|
2783
2928
|
};
|
|
2784
2929
|
}
|
|
2785
|
-
function promisify(client, method, request, metadata) {
|
|
2930
|
+
function promisify(client, method, request, metadata, timeoutMs) {
|
|
2786
2931
|
return new Promise((resolve, reject) => {
|
|
2787
|
-
|
|
2932
|
+
const callback = (error, response) => {
|
|
2788
2933
|
if (error) {
|
|
2789
|
-
reject(error);
|
|
2934
|
+
reject(mapGrpcError(error, timeoutMs));
|
|
2790
2935
|
} else {
|
|
2791
2936
|
resolve(response);
|
|
2792
2937
|
}
|
|
2793
|
-
}
|
|
2938
|
+
};
|
|
2939
|
+
method.call(
|
|
2940
|
+
client,
|
|
2941
|
+
request,
|
|
2942
|
+
metadata,
|
|
2943
|
+
createUnaryCallOptions(timeoutMs),
|
|
2944
|
+
callback
|
|
2945
|
+
);
|
|
2794
2946
|
});
|
|
2795
2947
|
}
|
|
2948
|
+
function createUnaryCallOptions(timeoutMs) {
|
|
2949
|
+
if (timeoutMs === void 0) {
|
|
2950
|
+
return {};
|
|
2951
|
+
}
|
|
2952
|
+
return { deadline: new Date(Date.now() + timeoutMs) };
|
|
2953
|
+
}
|
|
2954
|
+
function mapGrpcError(error, timeoutMs) {
|
|
2955
|
+
const message = error.details || error.message || "gRPC request failed";
|
|
2956
|
+
switch (error.code) {
|
|
2957
|
+
case grpc2.status.DEADLINE_EXCEEDED:
|
|
2958
|
+
return new TimeoutError(message, timeoutMs ?? 0);
|
|
2959
|
+
case grpc2.status.UNAUTHENTICATED:
|
|
2960
|
+
return new AuthenticationError(message, "AUTHENTICATION_FAILED");
|
|
2961
|
+
case grpc2.status.PERMISSION_DENIED:
|
|
2962
|
+
return new AuthorizationError(message, "ACCESS_DENIED");
|
|
2963
|
+
case grpc2.status.NOT_FOUND:
|
|
2964
|
+
return new NotFoundError(message, "NOT_FOUND");
|
|
2965
|
+
case grpc2.status.INVALID_ARGUMENT:
|
|
2966
|
+
case grpc2.status.OUT_OF_RANGE:
|
|
2967
|
+
return new ValidationError(message, "VALIDATION_ERROR");
|
|
2968
|
+
case grpc2.status.ALREADY_EXISTS:
|
|
2969
|
+
case grpc2.status.ABORTED:
|
|
2970
|
+
case grpc2.status.FAILED_PRECONDITION:
|
|
2971
|
+
return new ConflictError(message, "CONFLICT");
|
|
2972
|
+
case grpc2.status.RESOURCE_EXHAUSTED:
|
|
2973
|
+
return new RateLimitError(message, "RATE_LIMIT_EXCEEDED");
|
|
2974
|
+
case grpc2.status.UNAVAILABLE:
|
|
2975
|
+
case grpc2.status.CANCELLED:
|
|
2976
|
+
return new NetworkError(message, error);
|
|
2977
|
+
default:
|
|
2978
|
+
if (error.code >= grpc2.status.INTERNAL) {
|
|
2979
|
+
return new ServerError(message, 500, "GRPC_SERVER_ERROR");
|
|
2980
|
+
}
|
|
2981
|
+
return new ServerError(message, 500, "GRPC_ERROR");
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2796
2984
|
function shouldUseTls(address, explicitTls) {
|
|
2797
2985
|
if (explicitTls !== void 0) {
|
|
2798
2986
|
return explicitTls;
|
|
@@ -2801,53 +2989,99 @@ function shouldUseTls(address, explicitTls) {
|
|
|
2801
2989
|
return host !== "localhost" && host !== "127.0.0.1" && !host.startsWith("[::1]");
|
|
2802
2990
|
}
|
|
2803
2991
|
var GrpcQueueOperations = class {
|
|
2804
|
-
constructor(client, metadata) {
|
|
2992
|
+
constructor(client, metadata, timeoutMs) {
|
|
2805
2993
|
this.client = client;
|
|
2806
2994
|
this.metadata = metadata;
|
|
2995
|
+
this.timeoutMs = timeoutMs;
|
|
2807
2996
|
}
|
|
2808
2997
|
/**
|
|
2809
2998
|
* Enqueue a new job
|
|
2810
2999
|
*/
|
|
2811
3000
|
async enqueue(params) {
|
|
2812
|
-
return promisify(
|
|
3001
|
+
return promisify(
|
|
3002
|
+
this.client,
|
|
3003
|
+
this.client.Enqueue,
|
|
3004
|
+
encodeEnqueueRequest(params),
|
|
3005
|
+
this.metadata,
|
|
3006
|
+
this.timeoutMs
|
|
3007
|
+
);
|
|
2813
3008
|
}
|
|
2814
3009
|
/**
|
|
2815
3010
|
* Dequeue a job (for workers)
|
|
2816
3011
|
*/
|
|
2817
3012
|
async dequeue(params) {
|
|
2818
|
-
const response = await promisify(
|
|
3013
|
+
const response = await promisify(
|
|
3014
|
+
this.client,
|
|
3015
|
+
this.client.Dequeue,
|
|
3016
|
+
params,
|
|
3017
|
+
this.metadata,
|
|
3018
|
+
this.timeoutMs
|
|
3019
|
+
);
|
|
2819
3020
|
return { ...response, jobs: response.jobs.map(decodeJob) };
|
|
2820
3021
|
}
|
|
2821
3022
|
/**
|
|
2822
3023
|
* Complete a job successfully
|
|
2823
3024
|
*/
|
|
2824
3025
|
async complete(params) {
|
|
2825
|
-
return promisify(
|
|
3026
|
+
return promisify(
|
|
3027
|
+
this.client,
|
|
3028
|
+
this.client.Complete,
|
|
3029
|
+
encodeCompleteRequest(params),
|
|
3030
|
+
this.metadata,
|
|
3031
|
+
this.timeoutMs
|
|
3032
|
+
);
|
|
2826
3033
|
}
|
|
2827
3034
|
/**
|
|
2828
3035
|
* Fail a job
|
|
2829
3036
|
*/
|
|
2830
3037
|
async fail(params) {
|
|
2831
|
-
return promisify(
|
|
3038
|
+
return promisify(
|
|
3039
|
+
this.client,
|
|
3040
|
+
this.client.Fail,
|
|
3041
|
+
params,
|
|
3042
|
+
this.metadata,
|
|
3043
|
+
this.timeoutMs
|
|
3044
|
+
);
|
|
2832
3045
|
}
|
|
2833
3046
|
/**
|
|
2834
3047
|
* Renew a job's lease
|
|
2835
3048
|
*/
|
|
2836
3049
|
async renewLease(params) {
|
|
2837
|
-
return promisify(
|
|
3050
|
+
return promisify(
|
|
3051
|
+
this.client,
|
|
3052
|
+
this.client.RenewLease,
|
|
3053
|
+
params,
|
|
3054
|
+
this.metadata,
|
|
3055
|
+
this.timeoutMs
|
|
3056
|
+
);
|
|
2838
3057
|
}
|
|
2839
3058
|
/**
|
|
2840
3059
|
* Get a job by ID
|
|
2841
3060
|
*/
|
|
2842
3061
|
async getJob(jobId) {
|
|
2843
|
-
const response = await promisify(
|
|
2844
|
-
|
|
3062
|
+
const response = await promisify(
|
|
3063
|
+
this.client,
|
|
3064
|
+
this.client.GetJob,
|
|
3065
|
+
{ jobId },
|
|
3066
|
+
this.metadata,
|
|
3067
|
+
this.timeoutMs
|
|
3068
|
+
);
|
|
3069
|
+
return {
|
|
3070
|
+
...response,
|
|
3071
|
+
job: response.job ? decodeJob(response.job) : response.job
|
|
3072
|
+
};
|
|
2845
3073
|
}
|
|
2846
3074
|
/**
|
|
2847
3075
|
* Get queue statistics
|
|
2848
3076
|
*/
|
|
2849
3077
|
async getQueueStats(queueName) {
|
|
2850
|
-
return promisify(
|
|
3078
|
+
return promisify(
|
|
3079
|
+
this.client,
|
|
3080
|
+
this.client.GetQueueStats,
|
|
3081
|
+
{ queueName },
|
|
3082
|
+
this.metadata,
|
|
3083
|
+
this.timeoutMs
|
|
3084
|
+
);
|
|
2851
3085
|
}
|
|
2852
3086
|
/**
|
|
2853
3087
|
* Stream jobs from a queue (server-side streaming)
|
|
@@ -2895,27 +3129,46 @@ var GrpcQueueOperations = class {
|
|
|
2895
3129
|
}
|
|
2896
3130
|
};
|
|
2897
3131
|
var GrpcWorkerOperations = class {
|
|
2898
|
-
constructor(client, metadata) {
|
|
3132
|
+
constructor(client, metadata, timeoutMs) {
|
|
2899
3133
|
this.client = client;
|
|
2900
3134
|
this.metadata = metadata;
|
|
3135
|
+
this.timeoutMs = timeoutMs;
|
|
2901
3136
|
}
|
|
2902
3137
|
/**
|
|
2903
3138
|
* Register a new worker
|
|
2904
3139
|
*/
|
|
2905
3140
|
async register(params) {
|
|
2906
|
-
return promisify(
|
|
3141
|
+
return promisify(
|
|
3142
|
+
this.client,
|
|
3143
|
+
this.client.Register,
|
|
3144
|
+
params,
|
|
3145
|
+
this.metadata,
|
|
3146
|
+
this.timeoutMs
|
|
3147
|
+
);
|
|
2907
3148
|
}
|
|
2908
3149
|
/**
|
|
2909
3150
|
* Send heartbeat
|
|
2910
3151
|
*/
|
|
2911
3152
|
async heartbeat(params) {
|
|
2912
|
-
return promisify(
|
|
3153
|
+
return promisify(
|
|
3154
|
+
this.client,
|
|
3155
|
+
this.client.Heartbeat,
|
|
3156
|
+
params,
|
|
3157
|
+
this.metadata,
|
|
3158
|
+
this.timeoutMs
|
|
3159
|
+
);
|
|
2913
3160
|
}
|
|
2914
3161
|
/**
|
|
2915
3162
|
* Deregister a worker
|
|
2916
3163
|
*/
|
|
2917
3164
|
async deregister(workerId) {
|
|
2918
|
-
return promisify(
|
|
3165
|
+
return promisify(
|
|
3166
|
+
this.client,
|
|
3167
|
+
this.client.Deregister,
|
|
3168
|
+
{ workerId },
|
|
3169
|
+
this.metadata,
|
|
3170
|
+
this.timeoutMs
|
|
3171
|
+
);
|
|
2919
3172
|
}
|
|
2920
3173
|
};
|
|
2921
3174
|
var SpooledGrpcClient = class {
|
|
@@ -2927,7 +3180,7 @@ var SpooledGrpcClient = class {
|
|
|
2927
3180
|
/** Worker operations */
|
|
2928
3181
|
workers;
|
|
2929
3182
|
constructor(options) {
|
|
2930
|
-
const { address, apiKey, useTls, credentials: credentials2, channelOptions } = options;
|
|
3183
|
+
const { address, apiKey, useTls, credentials: credentials2, channelOptions, timeout } = options;
|
|
2931
3184
|
const creds = credentials2 ?? (shouldUseTls(address, useTls) ? grpc2.credentials.createSsl() : grpc2.credentials.createInsecure());
|
|
2932
3185
|
this.metadata = new grpc2.Metadata();
|
|
2933
3186
|
this.metadata.add("x-api-key", apiKey);
|
|
@@ -2942,8 +3195,16 @@ var SpooledGrpcClient = class {
|
|
|
2942
3195
|
creds,
|
|
2943
3196
|
channelOptions
|
|
2944
3197
|
);
|
|
2945
|
-
this.queue = new GrpcQueueOperations(
|
|
2946
|
-
|
|
3198
|
+
this.queue = new GrpcQueueOperations(
|
|
3199
|
+
this.queueClient,
|
|
3200
|
+
this.metadata,
|
|
3201
|
+
timeout
|
|
3202
|
+
);
|
|
3203
|
+
this.workers = new GrpcWorkerOperations(
|
|
3204
|
+
this.workerClient,
|
|
3205
|
+
this.metadata,
|
|
3206
|
+
timeout
|
|
3207
|
+
);
|
|
2947
3208
|
}
|
|
2948
3209
|
/**
|
|
2949
3210
|
* Close all gRPC connections
|
|
@@ -3092,7 +3353,8 @@ var SpooledClient = class _SpooledClient {
|
|
|
3092
3353
|
}
|
|
3093
3354
|
this._grpc = new SpooledGrpcClient({
|
|
3094
3355
|
address: grpcAddress,
|
|
3095
|
-
apiKey
|
|
3356
|
+
apiKey,
|
|
3357
|
+
timeout: this.config.timeout
|
|
3096
3358
|
});
|
|
3097
3359
|
}
|
|
3098
3360
|
return this._grpc;
|
|
@@ -3159,7 +3421,9 @@ var SpooledClient = class _SpooledClient {
|
|
|
3159
3421
|
}
|
|
3160
3422
|
return this.loginForJwt();
|
|
3161
3423
|
}
|
|
3162
|
-
throw new AuthenticationError(
|
|
3424
|
+
throw new AuthenticationError(
|
|
3425
|
+
"No authentication method available for realtime connection"
|
|
3426
|
+
);
|
|
3163
3427
|
}
|
|
3164
3428
|
/**
|
|
3165
3429
|
* Exchange the API key for a JWT via /auth/login and cache the result.
|
|
@@ -3456,7 +3720,10 @@ var SpooledWorker = class {
|
|
|
3456
3720
|
this.sendWorkerHeartbeat();
|
|
3457
3721
|
}, heartbeatInterval);
|
|
3458
3722
|
this.state = "running";
|
|
3459
|
-
this.emit("started", {
|
|
3723
|
+
this.emit("started", {
|
|
3724
|
+
workerId: this.workerId,
|
|
3725
|
+
queueName: this.options.queueName
|
|
3726
|
+
});
|
|
3460
3727
|
this.schedulePoll();
|
|
3461
3728
|
} catch (error) {
|
|
3462
3729
|
this.state = "error";
|
|
@@ -3492,14 +3759,18 @@ var SpooledWorker = class {
|
|
|
3492
3759
|
active.abortController.abort();
|
|
3493
3760
|
}
|
|
3494
3761
|
if (this.activeJobs.size > 0) {
|
|
3495
|
-
this.debug(
|
|
3762
|
+
this.debug(
|
|
3763
|
+
`Waiting for ${this.activeJobs.size} active jobs to complete...`
|
|
3764
|
+
);
|
|
3496
3765
|
await Promise.race([
|
|
3497
3766
|
this.waitForActiveJobs(),
|
|
3498
3767
|
this.sleep(this.options.shutdownTimeout)
|
|
3499
3768
|
]);
|
|
3500
3769
|
const remaining = Array.from(this.activeJobs.values());
|
|
3501
3770
|
for (const active of remaining) {
|
|
3502
|
-
this.debug(
|
|
3771
|
+
this.debug(
|
|
3772
|
+
`Force-failing job ${active.job.id} due to shutdown timeout`
|
|
3773
|
+
);
|
|
3503
3774
|
await this.failJob(active.job, "Worker shutdown timeout");
|
|
3504
3775
|
this.cleanupJob(active);
|
|
3505
3776
|
}
|
|
@@ -3607,7 +3878,9 @@ var SpooledWorker = class {
|
|
|
3607
3878
|
retryCount: job.retryCount,
|
|
3608
3879
|
maxRetries: job.maxRetries,
|
|
3609
3880
|
signal,
|
|
3610
|
-
progress: async (
|
|
3881
|
+
progress: async (percent, message) => {
|
|
3882
|
+
const boundedPercent = Math.max(0, Math.min(100, percent));
|
|
3883
|
+
this.debug(`[${job.id}] progress ${boundedPercent}%`, message);
|
|
3611
3884
|
},
|
|
3612
3885
|
log: (level, message, meta) => {
|
|
3613
3886
|
this.debug(`[${job.id}] [${level}] ${message}`, meta);
|