@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.cjs
CHANGED
|
@@ -50,10 +50,10 @@ var DEFAULT_CONFIG = {
|
|
|
50
50
|
successThreshold: 3,
|
|
51
51
|
timeout: 3e4
|
|
52
52
|
},
|
|
53
|
-
userAgent: "@spooled/sdk-nodejs/1.0.
|
|
53
|
+
userAgent: "@spooled/sdk-nodejs/1.0.40",
|
|
54
54
|
autoRefreshToken: true
|
|
55
55
|
};
|
|
56
|
-
var SDK_VERSION = "1.0.
|
|
56
|
+
var SDK_VERSION = "1.0.40";
|
|
57
57
|
var API_VERSION = "v1";
|
|
58
58
|
var API_BASE_PATH = `/api/${API_VERSION}`;
|
|
59
59
|
function normalizeCredential(value) {
|
|
@@ -379,13 +379,31 @@ async function createErrorFromResponse(response) {
|
|
|
379
379
|
return new PayloadTooLargeError(message, code, details, requestId);
|
|
380
380
|
case 429: {
|
|
381
381
|
const rateLimitInfo = parseRateLimitHeaders(response.headers);
|
|
382
|
-
return new RateLimitError(
|
|
382
|
+
return new RateLimitError(
|
|
383
|
+
message,
|
|
384
|
+
code,
|
|
385
|
+
rateLimitInfo,
|
|
386
|
+
details,
|
|
387
|
+
requestId
|
|
388
|
+
);
|
|
383
389
|
}
|
|
384
390
|
default:
|
|
385
391
|
if (response.status >= 500) {
|
|
386
|
-
return new ServerError(
|
|
392
|
+
return new ServerError(
|
|
393
|
+
message,
|
|
394
|
+
response.status,
|
|
395
|
+
code,
|
|
396
|
+
details,
|
|
397
|
+
requestId
|
|
398
|
+
);
|
|
387
399
|
}
|
|
388
|
-
return new SpooledError(
|
|
400
|
+
return new SpooledError(
|
|
401
|
+
message,
|
|
402
|
+
response.status,
|
|
403
|
+
code,
|
|
404
|
+
details,
|
|
405
|
+
requestId
|
|
406
|
+
);
|
|
389
407
|
}
|
|
390
408
|
}
|
|
391
409
|
function isSpooledError(error) {
|
|
@@ -643,7 +661,9 @@ var HttpClient = class {
|
|
|
643
661
|
if (externalSignal.aborted) {
|
|
644
662
|
controller.abort();
|
|
645
663
|
} else {
|
|
646
|
-
externalSignal.addEventListener("abort", () => controller.abort(), {
|
|
664
|
+
externalSignal.addEventListener("abort", () => controller.abort(), {
|
|
665
|
+
once: true
|
|
666
|
+
});
|
|
647
667
|
}
|
|
648
668
|
}
|
|
649
669
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -658,7 +678,10 @@ var HttpClient = class {
|
|
|
658
678
|
if (externalSignal?.aborted) {
|
|
659
679
|
throw error;
|
|
660
680
|
}
|
|
661
|
-
throw new TimeoutError(
|
|
681
|
+
throw new TimeoutError(
|
|
682
|
+
`Request timed out after ${timeoutMs}ms`,
|
|
683
|
+
timeoutMs
|
|
684
|
+
);
|
|
662
685
|
}
|
|
663
686
|
throw error;
|
|
664
687
|
} finally {
|
|
@@ -687,13 +710,21 @@ var HttpClient = class {
|
|
|
687
710
|
this.debug?.(`${method} ${url}`, { timeout, hasBody: !!options.body });
|
|
688
711
|
let response;
|
|
689
712
|
try {
|
|
690
|
-
response = await this.fetchWithTimeout(
|
|
713
|
+
response = await this.fetchWithTimeout(
|
|
714
|
+
url,
|
|
715
|
+
init,
|
|
716
|
+
timeout,
|
|
717
|
+
options.signal
|
|
718
|
+
);
|
|
691
719
|
} catch (error) {
|
|
692
720
|
if (error instanceof TimeoutError || error instanceof SpooledError) {
|
|
693
721
|
throw error;
|
|
694
722
|
}
|
|
695
723
|
const cause = error instanceof Error ? error : void 0;
|
|
696
|
-
throw new NetworkError(
|
|
724
|
+
throw new NetworkError(
|
|
725
|
+
`Network request failed: ${cause?.message ?? "Unknown error"}`,
|
|
726
|
+
cause
|
|
727
|
+
);
|
|
697
728
|
}
|
|
698
729
|
this.debug?.(`Response: ${response.status}`, { url });
|
|
699
730
|
if (!response.ok) {
|
|
@@ -740,7 +771,9 @@ var HttpClient = class {
|
|
|
740
771
|
const url = this.buildUrl(path, options.params, options.skipApiPrefix);
|
|
741
772
|
const method = options.method ?? "GET";
|
|
742
773
|
const execute = async () => {
|
|
743
|
-
return this.circuitBreaker.execute(
|
|
774
|
+
return this.circuitBreaker.execute(
|
|
775
|
+
() => this.executeRequest(url, options)
|
|
776
|
+
);
|
|
744
777
|
};
|
|
745
778
|
if (options.skipRetry) {
|
|
746
779
|
return execute();
|
|
@@ -749,7 +782,9 @@ var HttpClient = class {
|
|
|
749
782
|
config: this.resolveRetryConfig(method, options),
|
|
750
783
|
signal: options.signal,
|
|
751
784
|
onRetry: (attempt, error, delayMs) => {
|
|
752
|
-
this.debug?.(`Retry attempt ${attempt} after ${delayMs}ms`, {
|
|
785
|
+
this.debug?.(`Retry attempt ${attempt} after ${delayMs}ms`, {
|
|
786
|
+
error: error.message
|
|
787
|
+
});
|
|
753
788
|
}
|
|
754
789
|
});
|
|
755
790
|
}
|
|
@@ -761,7 +796,9 @@ var HttpClient = class {
|
|
|
761
796
|
if (!options.headers) {
|
|
762
797
|
return false;
|
|
763
798
|
}
|
|
764
|
-
return Object.keys(options.headers).some(
|
|
799
|
+
return Object.keys(options.headers).some(
|
|
800
|
+
(key) => key.toLowerCase() === "idempotency-key"
|
|
801
|
+
);
|
|
765
802
|
}
|
|
766
803
|
/**
|
|
767
804
|
* Resolve the retry configuration for a request.
|
|
@@ -799,28 +836,43 @@ var HttpClient = class {
|
|
|
799
836
|
* Make a POST request
|
|
800
837
|
*/
|
|
801
838
|
async post(path, body, options) {
|
|
802
|
-
const response = await this.request(path, {
|
|
839
|
+
const response = await this.request(path, {
|
|
840
|
+
...options,
|
|
841
|
+
method: "POST",
|
|
842
|
+
body
|
|
843
|
+
});
|
|
803
844
|
return response.data;
|
|
804
845
|
}
|
|
805
846
|
/**
|
|
806
847
|
* Make a PUT request
|
|
807
848
|
*/
|
|
808
849
|
async put(path, body, options) {
|
|
809
|
-
const response = await this.request(path, {
|
|
850
|
+
const response = await this.request(path, {
|
|
851
|
+
...options,
|
|
852
|
+
method: "PUT",
|
|
853
|
+
body
|
|
854
|
+
});
|
|
810
855
|
return response.data;
|
|
811
856
|
}
|
|
812
857
|
/**
|
|
813
858
|
* Make a PATCH request
|
|
814
859
|
*/
|
|
815
860
|
async patch(path, body, options) {
|
|
816
|
-
const response = await this.request(path, {
|
|
861
|
+
const response = await this.request(path, {
|
|
862
|
+
...options,
|
|
863
|
+
method: "PATCH",
|
|
864
|
+
body
|
|
865
|
+
});
|
|
817
866
|
return response.data;
|
|
818
867
|
}
|
|
819
868
|
/**
|
|
820
869
|
* Make a DELETE request
|
|
821
870
|
*/
|
|
822
871
|
async delete(path, options) {
|
|
823
|
-
const response = await this.request(path, {
|
|
872
|
+
const response = await this.request(path, {
|
|
873
|
+
...options,
|
|
874
|
+
method: "DELETE"
|
|
875
|
+
});
|
|
824
876
|
return response.data;
|
|
825
877
|
}
|
|
826
878
|
};
|
|
@@ -1014,7 +1066,10 @@ var AuthResource = class {
|
|
|
1014
1066
|
*/
|
|
1015
1067
|
async logout(refreshToken) {
|
|
1016
1068
|
const token = refreshToken ?? this.getRefreshToken?.();
|
|
1017
|
-
await this.http.post(
|
|
1069
|
+
await this.http.post(
|
|
1070
|
+
"/auth/logout",
|
|
1071
|
+
token ? { refreshToken: token } : void 0
|
|
1072
|
+
);
|
|
1018
1073
|
}
|
|
1019
1074
|
/**
|
|
1020
1075
|
* Get current user/session info
|
|
@@ -1032,7 +1087,10 @@ var AuthResource = class {
|
|
|
1032
1087
|
* Start email-based login flow (sends magic link)
|
|
1033
1088
|
*/
|
|
1034
1089
|
async startEmailLogin(email) {
|
|
1035
|
-
return this.http.post(
|
|
1090
|
+
return this.http.post(
|
|
1091
|
+
"/auth/email/start",
|
|
1092
|
+
{ email }
|
|
1093
|
+
);
|
|
1036
1094
|
}
|
|
1037
1095
|
/**
|
|
1038
1096
|
* Check if an email address exists in the system
|
|
@@ -1073,7 +1131,9 @@ var JobsResource = class {
|
|
|
1073
1131
|
* List jobs with optional filtering
|
|
1074
1132
|
*/
|
|
1075
1133
|
async list(params) {
|
|
1076
|
-
return this.http.get("/jobs", {
|
|
1134
|
+
return this.http.get("/jobs", {
|
|
1135
|
+
params
|
|
1136
|
+
});
|
|
1077
1137
|
}
|
|
1078
1138
|
/**
|
|
1079
1139
|
* Get a job by ID
|
|
@@ -1097,7 +1157,9 @@ var JobsResource = class {
|
|
|
1097
1157
|
* Boost job priority
|
|
1098
1158
|
*/
|
|
1099
1159
|
async boostPriority(id, priority) {
|
|
1100
|
-
return this.http.put(`/jobs/${id}/priority`, {
|
|
1160
|
+
return this.http.put(`/jobs/${id}/priority`, {
|
|
1161
|
+
priority
|
|
1162
|
+
});
|
|
1101
1163
|
}
|
|
1102
1164
|
/**
|
|
1103
1165
|
* Get job statistics
|
|
@@ -1142,17 +1204,25 @@ var JobsResource = class {
|
|
|
1142
1204
|
* Fail a job (worker nack)
|
|
1143
1205
|
*/
|
|
1144
1206
|
async fail(id, params) {
|
|
1145
|
-
return this.http.post(
|
|
1207
|
+
return this.http.post(
|
|
1208
|
+
`/jobs/${id}/fail`,
|
|
1209
|
+
params
|
|
1210
|
+
);
|
|
1146
1211
|
}
|
|
1147
1212
|
/**
|
|
1148
1213
|
* Extend job lease (heartbeat)
|
|
1149
1214
|
*/
|
|
1150
1215
|
async heartbeat(id, params) {
|
|
1151
|
-
return this.http.post(
|
|
1216
|
+
return this.http.post(
|
|
1217
|
+
`/jobs/${id}/heartbeat`,
|
|
1218
|
+
params
|
|
1219
|
+
);
|
|
1152
1220
|
}
|
|
1153
1221
|
// DLQ operations (private implementations)
|
|
1154
1222
|
async listDlq(params) {
|
|
1155
|
-
return this.http.get("/jobs/dlq", {
|
|
1223
|
+
return this.http.get("/jobs/dlq", {
|
|
1224
|
+
params
|
|
1225
|
+
});
|
|
1156
1226
|
}
|
|
1157
1227
|
async retryDlq(params) {
|
|
1158
1228
|
return this.http.post("/jobs/dlq/retry", params);
|
|
@@ -1183,13 +1253,18 @@ var QueuesResource = class {
|
|
|
1183
1253
|
* Update queue configuration
|
|
1184
1254
|
*/
|
|
1185
1255
|
async updateConfig(name, params) {
|
|
1186
|
-
return this.http.put(
|
|
1256
|
+
return this.http.put(
|
|
1257
|
+
`/queues/${encodeURIComponent(name)}/config`,
|
|
1258
|
+
params
|
|
1259
|
+
);
|
|
1187
1260
|
}
|
|
1188
1261
|
/**
|
|
1189
1262
|
* Get queue statistics
|
|
1190
1263
|
*/
|
|
1191
1264
|
async getStats(name) {
|
|
1192
|
-
return this.http.get(
|
|
1265
|
+
return this.http.get(
|
|
1266
|
+
`/queues/${encodeURIComponent(name)}/stats`
|
|
1267
|
+
);
|
|
1193
1268
|
}
|
|
1194
1269
|
/**
|
|
1195
1270
|
* Pause a queue
|
|
@@ -1204,7 +1279,9 @@ var QueuesResource = class {
|
|
|
1204
1279
|
* Resume a paused queue
|
|
1205
1280
|
*/
|
|
1206
1281
|
async resume(name) {
|
|
1207
|
-
return this.http.post(
|
|
1282
|
+
return this.http.post(
|
|
1283
|
+
`/queues/${encodeURIComponent(name)}/resume`
|
|
1284
|
+
);
|
|
1208
1285
|
}
|
|
1209
1286
|
/**
|
|
1210
1287
|
* Delete a queue configuration
|
|
@@ -1260,7 +1337,9 @@ var SchedulesResource = class {
|
|
|
1260
1337
|
* List all schedules
|
|
1261
1338
|
*/
|
|
1262
1339
|
async list(params) {
|
|
1263
|
-
return this.http.get("/schedules", {
|
|
1340
|
+
return this.http.get("/schedules", {
|
|
1341
|
+
params
|
|
1342
|
+
});
|
|
1264
1343
|
}
|
|
1265
1344
|
/**
|
|
1266
1345
|
* Create a new schedule
|
|
@@ -1332,7 +1411,9 @@ var WorkflowsResource = class {
|
|
|
1332
1411
|
* List all workflows
|
|
1333
1412
|
*/
|
|
1334
1413
|
async list(params) {
|
|
1335
|
-
return this.http.get("/workflows", {
|
|
1414
|
+
return this.http.get("/workflows", {
|
|
1415
|
+
params
|
|
1416
|
+
});
|
|
1336
1417
|
}
|
|
1337
1418
|
/**
|
|
1338
1419
|
* Create a new workflow
|
|
@@ -1369,13 +1450,18 @@ var WorkflowsResource = class {
|
|
|
1369
1450
|
return this.http.get(`/workflows/${workflowId}/jobs/${jobId}`);
|
|
1370
1451
|
}
|
|
1371
1452
|
async getWorkflowJobsStatus(workflowId) {
|
|
1372
|
-
return this.http.get(
|
|
1453
|
+
return this.http.get(
|
|
1454
|
+
`/workflows/${workflowId}/jobs/status`
|
|
1455
|
+
);
|
|
1373
1456
|
}
|
|
1374
1457
|
async getJobDependencies(jobId) {
|
|
1375
1458
|
return this.http.get(`/jobs/${jobId}/dependencies`);
|
|
1376
1459
|
}
|
|
1377
1460
|
async addJobDependencies(jobId, params) {
|
|
1378
|
-
return this.http.post(
|
|
1461
|
+
return this.http.post(
|
|
1462
|
+
`/jobs/${jobId}/dependencies`,
|
|
1463
|
+
params
|
|
1464
|
+
);
|
|
1379
1465
|
}
|
|
1380
1466
|
};
|
|
1381
1467
|
|
|
@@ -1424,7 +1510,9 @@ var WebhooksResource = class {
|
|
|
1424
1510
|
* Get webhook delivery history
|
|
1425
1511
|
*/
|
|
1426
1512
|
async getDeliveries(id) {
|
|
1427
|
-
return this.http.get(
|
|
1513
|
+
return this.http.get(
|
|
1514
|
+
`/outgoing-webhooks/${id}/deliveries`
|
|
1515
|
+
);
|
|
1428
1516
|
}
|
|
1429
1517
|
/**
|
|
1430
1518
|
* Retry a specific webhook delivery
|
|
@@ -1532,7 +1620,9 @@ var OrganizationsResource = class {
|
|
|
1532
1620
|
* Generate a unique slug from an organization name
|
|
1533
1621
|
*/
|
|
1534
1622
|
async generateSlug(name) {
|
|
1535
|
-
return this.http.post("/organizations/generate-slug", {
|
|
1623
|
+
return this.http.post("/organizations/generate-slug", {
|
|
1624
|
+
name
|
|
1625
|
+
});
|
|
1536
1626
|
}
|
|
1537
1627
|
/**
|
|
1538
1628
|
* Get the webhook token for the current organization.
|
|
@@ -1562,7 +1652,9 @@ var OrganizationsResource = class {
|
|
|
1562
1652
|
* ```
|
|
1563
1653
|
*/
|
|
1564
1654
|
async regenerateWebhookToken() {
|
|
1565
|
-
return this.http.post(
|
|
1655
|
+
return this.http.post(
|
|
1656
|
+
"/organizations/webhook-token/regenerate"
|
|
1657
|
+
);
|
|
1566
1658
|
}
|
|
1567
1659
|
/**
|
|
1568
1660
|
* Clear/delete the webhook token for the current organization.
|
|
@@ -1599,7 +1691,10 @@ var BillingResource = class {
|
|
|
1599
1691
|
* POST /api/v1/billing/portal
|
|
1600
1692
|
*/
|
|
1601
1693
|
async createPortal(params) {
|
|
1602
|
-
return this.http.post(
|
|
1694
|
+
return this.http.post(
|
|
1695
|
+
"/billing/portal",
|
|
1696
|
+
params
|
|
1697
|
+
);
|
|
1603
1698
|
}
|
|
1604
1699
|
};
|
|
1605
1700
|
|
|
@@ -1694,7 +1789,9 @@ var AdminResource = class {
|
|
|
1694
1789
|
}
|
|
1695
1790
|
headers() {
|
|
1696
1791
|
if (!this.adminKey) {
|
|
1697
|
-
throw new AuthenticationError(
|
|
1792
|
+
throw new AuthenticationError(
|
|
1793
|
+
"Admin key is required for admin endpoints. Provide `adminKey` in SpooledClient config."
|
|
1794
|
+
);
|
|
1698
1795
|
}
|
|
1699
1796
|
return { "X-Admin-Key": this.adminKey };
|
|
1700
1797
|
}
|
|
@@ -1715,15 +1812,22 @@ var AdminResource = class {
|
|
|
1715
1812
|
}
|
|
1716
1813
|
/** POST /api/v1/admin/organizations */
|
|
1717
1814
|
async createOrganization(params) {
|
|
1718
|
-
return this.http.post(
|
|
1719
|
-
|
|
1720
|
-
|
|
1815
|
+
return this.http.post(
|
|
1816
|
+
"/admin/organizations",
|
|
1817
|
+
params,
|
|
1818
|
+
{
|
|
1819
|
+
headers: this.headers()
|
|
1820
|
+
}
|
|
1821
|
+
);
|
|
1721
1822
|
}
|
|
1722
1823
|
/** GET /api/v1/admin/organizations/{id} */
|
|
1723
1824
|
async getOrganization(id) {
|
|
1724
|
-
return this.http.get(
|
|
1725
|
-
|
|
1726
|
-
|
|
1825
|
+
return this.http.get(
|
|
1826
|
+
`/admin/organizations/${id}`,
|
|
1827
|
+
{
|
|
1828
|
+
headers: this.headers()
|
|
1829
|
+
}
|
|
1830
|
+
);
|
|
1727
1831
|
}
|
|
1728
1832
|
/** PATCH /api/v1/admin/organizations/{id} */
|
|
1729
1833
|
async updateOrganization(id, params) {
|
|
@@ -1741,15 +1845,23 @@ var AdminResource = class {
|
|
|
1741
1845
|
}
|
|
1742
1846
|
/** POST /api/v1/admin/organizations/{id}/api-keys */
|
|
1743
1847
|
async createApiKey(orgId, params) {
|
|
1744
|
-
return this.http.post(
|
|
1745
|
-
|
|
1746
|
-
|
|
1848
|
+
return this.http.post(
|
|
1849
|
+
`/admin/organizations/${orgId}/api-keys`,
|
|
1850
|
+
params,
|
|
1851
|
+
{
|
|
1852
|
+
headers: this.headers()
|
|
1853
|
+
}
|
|
1854
|
+
);
|
|
1747
1855
|
}
|
|
1748
1856
|
/** POST /api/v1/admin/organizations/{id}/reset-usage */
|
|
1749
1857
|
async resetUsage(orgId) {
|
|
1750
|
-
await this.http.post(
|
|
1751
|
-
|
|
1752
|
-
|
|
1858
|
+
await this.http.post(
|
|
1859
|
+
`/admin/organizations/${orgId}/reset-usage`,
|
|
1860
|
+
void 0,
|
|
1861
|
+
{
|
|
1862
|
+
headers: this.headers()
|
|
1863
|
+
}
|
|
1864
|
+
);
|
|
1753
1865
|
}
|
|
1754
1866
|
/** GET /api/v1/admin/stats */
|
|
1755
1867
|
async getStats() {
|
|
@@ -1795,7 +1907,9 @@ var WebhookIngestionResource = class {
|
|
|
1795
1907
|
const bytes = toBytes(body);
|
|
1796
1908
|
const signature = options.signature ?? (options.secret ? githubSignature(options.secret, bytes) : void 0);
|
|
1797
1909
|
if (!signature) {
|
|
1798
|
-
throw new ValidationError(
|
|
1910
|
+
throw new ValidationError(
|
|
1911
|
+
"GitHub webhook signature is required (provide `signature` or `secret`)"
|
|
1912
|
+
);
|
|
1799
1913
|
}
|
|
1800
1914
|
const headers = {
|
|
1801
1915
|
"Content-Type": "application/json",
|
|
@@ -1826,7 +1940,9 @@ var WebhookIngestionResource = class {
|
|
|
1826
1940
|
const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
|
|
1827
1941
|
const signature = options.signature ?? (options.secret ? stripeSignature(options.secret, bytes, timestamp) : void 0);
|
|
1828
1942
|
if (!signature) {
|
|
1829
|
-
throw new ValidationError(
|
|
1943
|
+
throw new ValidationError(
|
|
1944
|
+
"Stripe webhook signature is required (provide `signature` or `secret`)"
|
|
1945
|
+
);
|
|
1830
1946
|
}
|
|
1831
1947
|
const headers = {
|
|
1832
1948
|
"Content-Type": "application/json",
|
|
@@ -1963,14 +2079,20 @@ var WebSocketRealtimeClient = class {
|
|
|
1963
2079
|
resolve();
|
|
1964
2080
|
};
|
|
1965
2081
|
this.ws.onmessage = (event) => {
|
|
1966
|
-
this.handleMessage(
|
|
2082
|
+
this.handleMessage(
|
|
2083
|
+
typeof event.data === "string" ? event.data : String(event.data)
|
|
2084
|
+
);
|
|
1967
2085
|
};
|
|
1968
2086
|
this.ws.onclose = (event) => {
|
|
1969
2087
|
this.options.debug(`WebSocket closed: ${event.code} ${event.reason}`);
|
|
1970
2088
|
const wasConnecting = this.state === "connecting";
|
|
1971
2089
|
this.handleDisconnect();
|
|
1972
2090
|
if (wasConnecting) {
|
|
1973
|
-
reject(
|
|
2091
|
+
reject(
|
|
2092
|
+
new Error(
|
|
2093
|
+
`WebSocket connection failed: ${event.reason || "Unknown error"}`
|
|
2094
|
+
)
|
|
2095
|
+
);
|
|
1974
2096
|
}
|
|
1975
2097
|
};
|
|
1976
2098
|
this.ws.onerror = (event) => {
|
|
@@ -2125,7 +2247,9 @@ var WebSocketRealtimeClient = class {
|
|
|
2125
2247
|
this.options.maxReconnectDelay
|
|
2126
2248
|
);
|
|
2127
2249
|
const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
|
|
2128
|
-
this.options.debug(
|
|
2250
|
+
this.options.debug(
|
|
2251
|
+
`Scheduling reconnect attempt ${this.reconnectAttempts} in ${delay}ms`
|
|
2252
|
+
);
|
|
2129
2253
|
this.reconnectTimer = setTimeout(async () => {
|
|
2130
2254
|
try {
|
|
2131
2255
|
await this.connect();
|
|
@@ -2178,11 +2302,13 @@ function isAuthFailureEvent(event) {
|
|
|
2178
2302
|
if (!event) {
|
|
2179
2303
|
return false;
|
|
2180
2304
|
}
|
|
2181
|
-
const
|
|
2182
|
-
if (
|
|
2305
|
+
const status2 = event.status ?? event.statusCode ?? event.error?.status;
|
|
2306
|
+
if (status2 === 401 || status2 === 403) {
|
|
2183
2307
|
return true;
|
|
2184
2308
|
}
|
|
2185
|
-
const text = String(
|
|
2309
|
+
const text = String(
|
|
2310
|
+
event.message ?? event.error?.message ?? event.reason ?? ""
|
|
2311
|
+
);
|
|
2186
2312
|
return /\b(401|403)\b/.test(text);
|
|
2187
2313
|
}
|
|
2188
2314
|
|
|
@@ -2245,7 +2371,9 @@ var SseRealtimeClient = class {
|
|
|
2245
2371
|
EventSourceImpl = mod.default || mod.EventSource || mod;
|
|
2246
2372
|
} catch {
|
|
2247
2373
|
this.setState("disconnected");
|
|
2248
|
-
throw new Error(
|
|
2374
|
+
throw new Error(
|
|
2375
|
+
"eventsource package is required for SSE in Node.js. Install it with: npm install eventsource"
|
|
2376
|
+
);
|
|
2249
2377
|
}
|
|
2250
2378
|
}
|
|
2251
2379
|
let token;
|
|
@@ -2414,7 +2542,9 @@ var SseRealtimeClient = class {
|
|
|
2414
2542
|
this.options.maxReconnectDelay
|
|
2415
2543
|
);
|
|
2416
2544
|
const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
|
|
2417
|
-
this.options.debug(
|
|
2545
|
+
this.options.debug(
|
|
2546
|
+
`Scheduling SSE reconnect attempt ${this.reconnectAttempts} in ${delay}ms`
|
|
2547
|
+
);
|
|
2418
2548
|
this.reconnectTimer = setTimeout(async () => {
|
|
2419
2549
|
try {
|
|
2420
2550
|
await this.connect(this.filter || void 0);
|
|
@@ -2590,7 +2720,10 @@ function loadProtoDefinition() {
|
|
|
2590
2720
|
return cachedDefinition;
|
|
2591
2721
|
}
|
|
2592
2722
|
const protoPath = getProtoPath();
|
|
2593
|
-
const packageDefinition = protoLoader__namespace.loadSync(
|
|
2723
|
+
const packageDefinition = protoLoader__namespace.loadSync(
|
|
2724
|
+
protoPath,
|
|
2725
|
+
PROTO_LOADER_OPTIONS
|
|
2726
|
+
);
|
|
2594
2727
|
const grpcObject = grpc2__namespace.loadPackageDefinition(packageDefinition);
|
|
2595
2728
|
cachedDefinition = grpcObject;
|
|
2596
2729
|
return cachedDefinition;
|
|
@@ -2600,7 +2733,10 @@ async function loadProtoDefinitionAsync() {
|
|
|
2600
2733
|
return cachedDefinition;
|
|
2601
2734
|
}
|
|
2602
2735
|
const protoPath = getProtoPath();
|
|
2603
|
-
const packageDefinition = await protoLoader__namespace.load(
|
|
2736
|
+
const packageDefinition = await protoLoader__namespace.load(
|
|
2737
|
+
protoPath,
|
|
2738
|
+
PROTO_LOADER_OPTIONS
|
|
2739
|
+
);
|
|
2604
2740
|
const grpcObject = grpc2__namespace.loadPackageDefinition(packageDefinition);
|
|
2605
2741
|
cachedDefinition = grpcObject;
|
|
2606
2742
|
return cachedDefinition;
|
|
@@ -2617,7 +2753,11 @@ async function* asyncIterableFromStream(stream, options) {
|
|
|
2617
2753
|
stream.cancel();
|
|
2618
2754
|
});
|
|
2619
2755
|
}
|
|
2620
|
-
return yield* new AsyncIterableStream(stream, {
|
|
2756
|
+
return yield* new AsyncIterableStream(stream, {
|
|
2757
|
+
onConnected,
|
|
2758
|
+
onError,
|
|
2759
|
+
onEnd
|
|
2760
|
+
});
|
|
2621
2761
|
}
|
|
2622
2762
|
var AsyncIterableStream = class {
|
|
2623
2763
|
stream;
|
|
@@ -2646,8 +2786,8 @@ var AsyncIterableStream = class {
|
|
|
2646
2786
|
onEnd?.();
|
|
2647
2787
|
resolve?.();
|
|
2648
2788
|
});
|
|
2649
|
-
this.stream.on("status", (
|
|
2650
|
-
if (
|
|
2789
|
+
this.stream.on("status", (status2) => {
|
|
2790
|
+
if (status2.code === 0) {
|
|
2651
2791
|
onConnected?.();
|
|
2652
2792
|
}
|
|
2653
2793
|
});
|
|
@@ -2748,7 +2888,9 @@ function decodeStruct(value) {
|
|
|
2748
2888
|
return value;
|
|
2749
2889
|
}
|
|
2750
2890
|
const fields = value.fields ?? {};
|
|
2751
|
-
return Object.fromEntries(
|
|
2891
|
+
return Object.fromEntries(
|
|
2892
|
+
Object.entries(fields).map(([key, entry]) => [key, decodeValue(entry)])
|
|
2893
|
+
);
|
|
2752
2894
|
}
|
|
2753
2895
|
function decodeValue(value) {
|
|
2754
2896
|
if ("nullValue" in value) {
|
|
@@ -2797,7 +2939,10 @@ function encodeEnqueueRequest(params) {
|
|
|
2797
2939
|
return encoded;
|
|
2798
2940
|
}
|
|
2799
2941
|
function encodeCompleteRequest(params) {
|
|
2800
|
-
return {
|
|
2942
|
+
return {
|
|
2943
|
+
...params,
|
|
2944
|
+
result: encodeStruct(params.result)
|
|
2945
|
+
};
|
|
2801
2946
|
}
|
|
2802
2947
|
function decodeJob(job) {
|
|
2803
2948
|
return {
|
|
@@ -2806,17 +2951,60 @@ function decodeJob(job) {
|
|
|
2806
2951
|
result: decodeStruct(job.result)
|
|
2807
2952
|
};
|
|
2808
2953
|
}
|
|
2809
|
-
function promisify(client, method, request, metadata) {
|
|
2954
|
+
function promisify(client, method, request, metadata, timeoutMs) {
|
|
2810
2955
|
return new Promise((resolve, reject) => {
|
|
2811
|
-
|
|
2956
|
+
const callback = (error, response) => {
|
|
2812
2957
|
if (error) {
|
|
2813
|
-
reject(error);
|
|
2958
|
+
reject(mapGrpcError(error, timeoutMs));
|
|
2814
2959
|
} else {
|
|
2815
2960
|
resolve(response);
|
|
2816
2961
|
}
|
|
2817
|
-
}
|
|
2962
|
+
};
|
|
2963
|
+
method.call(
|
|
2964
|
+
client,
|
|
2965
|
+
request,
|
|
2966
|
+
metadata,
|
|
2967
|
+
createUnaryCallOptions(timeoutMs),
|
|
2968
|
+
callback
|
|
2969
|
+
);
|
|
2818
2970
|
});
|
|
2819
2971
|
}
|
|
2972
|
+
function createUnaryCallOptions(timeoutMs) {
|
|
2973
|
+
if (timeoutMs === void 0) {
|
|
2974
|
+
return {};
|
|
2975
|
+
}
|
|
2976
|
+
return { deadline: new Date(Date.now() + timeoutMs) };
|
|
2977
|
+
}
|
|
2978
|
+
function mapGrpcError(error, timeoutMs) {
|
|
2979
|
+
const message = error.details || error.message || "gRPC request failed";
|
|
2980
|
+
switch (error.code) {
|
|
2981
|
+
case grpc2__namespace.status.DEADLINE_EXCEEDED:
|
|
2982
|
+
return new TimeoutError(message, timeoutMs ?? 0);
|
|
2983
|
+
case grpc2__namespace.status.UNAUTHENTICATED:
|
|
2984
|
+
return new AuthenticationError(message, "AUTHENTICATION_FAILED");
|
|
2985
|
+
case grpc2__namespace.status.PERMISSION_DENIED:
|
|
2986
|
+
return new AuthorizationError(message, "ACCESS_DENIED");
|
|
2987
|
+
case grpc2__namespace.status.NOT_FOUND:
|
|
2988
|
+
return new NotFoundError(message, "NOT_FOUND");
|
|
2989
|
+
case grpc2__namespace.status.INVALID_ARGUMENT:
|
|
2990
|
+
case grpc2__namespace.status.OUT_OF_RANGE:
|
|
2991
|
+
return new ValidationError(message, "VALIDATION_ERROR");
|
|
2992
|
+
case grpc2__namespace.status.ALREADY_EXISTS:
|
|
2993
|
+
case grpc2__namespace.status.ABORTED:
|
|
2994
|
+
case grpc2__namespace.status.FAILED_PRECONDITION:
|
|
2995
|
+
return new ConflictError(message, "CONFLICT");
|
|
2996
|
+
case grpc2__namespace.status.RESOURCE_EXHAUSTED:
|
|
2997
|
+
return new RateLimitError(message, "RATE_LIMIT_EXCEEDED");
|
|
2998
|
+
case grpc2__namespace.status.UNAVAILABLE:
|
|
2999
|
+
case grpc2__namespace.status.CANCELLED:
|
|
3000
|
+
return new NetworkError(message, error);
|
|
3001
|
+
default:
|
|
3002
|
+
if (error.code >= grpc2__namespace.status.INTERNAL) {
|
|
3003
|
+
return new ServerError(message, 500, "GRPC_SERVER_ERROR");
|
|
3004
|
+
}
|
|
3005
|
+
return new ServerError(message, 500, "GRPC_ERROR");
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
2820
3008
|
function shouldUseTls(address, explicitTls) {
|
|
2821
3009
|
if (explicitTls !== void 0) {
|
|
2822
3010
|
return explicitTls;
|
|
@@ -2825,53 +3013,99 @@ function shouldUseTls(address, explicitTls) {
|
|
|
2825
3013
|
return host !== "localhost" && host !== "127.0.0.1" && !host.startsWith("[::1]");
|
|
2826
3014
|
}
|
|
2827
3015
|
var GrpcQueueOperations = class {
|
|
2828
|
-
constructor(client, metadata) {
|
|
3016
|
+
constructor(client, metadata, timeoutMs) {
|
|
2829
3017
|
this.client = client;
|
|
2830
3018
|
this.metadata = metadata;
|
|
3019
|
+
this.timeoutMs = timeoutMs;
|
|
2831
3020
|
}
|
|
2832
3021
|
/**
|
|
2833
3022
|
* Enqueue a new job
|
|
2834
3023
|
*/
|
|
2835
3024
|
async enqueue(params) {
|
|
2836
|
-
return promisify(
|
|
3025
|
+
return promisify(
|
|
3026
|
+
this.client,
|
|
3027
|
+
this.client.Enqueue,
|
|
3028
|
+
encodeEnqueueRequest(params),
|
|
3029
|
+
this.metadata,
|
|
3030
|
+
this.timeoutMs
|
|
3031
|
+
);
|
|
2837
3032
|
}
|
|
2838
3033
|
/**
|
|
2839
3034
|
* Dequeue a job (for workers)
|
|
2840
3035
|
*/
|
|
2841
3036
|
async dequeue(params) {
|
|
2842
|
-
const response = await promisify(
|
|
3037
|
+
const response = await promisify(
|
|
3038
|
+
this.client,
|
|
3039
|
+
this.client.Dequeue,
|
|
3040
|
+
params,
|
|
3041
|
+
this.metadata,
|
|
3042
|
+
this.timeoutMs
|
|
3043
|
+
);
|
|
2843
3044
|
return { ...response, jobs: response.jobs.map(decodeJob) };
|
|
2844
3045
|
}
|
|
2845
3046
|
/**
|
|
2846
3047
|
* Complete a job successfully
|
|
2847
3048
|
*/
|
|
2848
3049
|
async complete(params) {
|
|
2849
|
-
return promisify(
|
|
3050
|
+
return promisify(
|
|
3051
|
+
this.client,
|
|
3052
|
+
this.client.Complete,
|
|
3053
|
+
encodeCompleteRequest(params),
|
|
3054
|
+
this.metadata,
|
|
3055
|
+
this.timeoutMs
|
|
3056
|
+
);
|
|
2850
3057
|
}
|
|
2851
3058
|
/**
|
|
2852
3059
|
* Fail a job
|
|
2853
3060
|
*/
|
|
2854
3061
|
async fail(params) {
|
|
2855
|
-
return promisify(
|
|
3062
|
+
return promisify(
|
|
3063
|
+
this.client,
|
|
3064
|
+
this.client.Fail,
|
|
3065
|
+
params,
|
|
3066
|
+
this.metadata,
|
|
3067
|
+
this.timeoutMs
|
|
3068
|
+
);
|
|
2856
3069
|
}
|
|
2857
3070
|
/**
|
|
2858
3071
|
* Renew a job's lease
|
|
2859
3072
|
*/
|
|
2860
3073
|
async renewLease(params) {
|
|
2861
|
-
return promisify(
|
|
3074
|
+
return promisify(
|
|
3075
|
+
this.client,
|
|
3076
|
+
this.client.RenewLease,
|
|
3077
|
+
params,
|
|
3078
|
+
this.metadata,
|
|
3079
|
+
this.timeoutMs
|
|
3080
|
+
);
|
|
2862
3081
|
}
|
|
2863
3082
|
/**
|
|
2864
3083
|
* Get a job by ID
|
|
2865
3084
|
*/
|
|
2866
3085
|
async getJob(jobId) {
|
|
2867
|
-
const response = await promisify(
|
|
2868
|
-
|
|
3086
|
+
const response = await promisify(
|
|
3087
|
+
this.client,
|
|
3088
|
+
this.client.GetJob,
|
|
3089
|
+
{ jobId },
|
|
3090
|
+
this.metadata,
|
|
3091
|
+
this.timeoutMs
|
|
3092
|
+
);
|
|
3093
|
+
return {
|
|
3094
|
+
...response,
|
|
3095
|
+
job: response.job ? decodeJob(response.job) : response.job
|
|
3096
|
+
};
|
|
2869
3097
|
}
|
|
2870
3098
|
/**
|
|
2871
3099
|
* Get queue statistics
|
|
2872
3100
|
*/
|
|
2873
3101
|
async getQueueStats(queueName) {
|
|
2874
|
-
return promisify(
|
|
3102
|
+
return promisify(
|
|
3103
|
+
this.client,
|
|
3104
|
+
this.client.GetQueueStats,
|
|
3105
|
+
{ queueName },
|
|
3106
|
+
this.metadata,
|
|
3107
|
+
this.timeoutMs
|
|
3108
|
+
);
|
|
2875
3109
|
}
|
|
2876
3110
|
/**
|
|
2877
3111
|
* Stream jobs from a queue (server-side streaming)
|
|
@@ -2919,27 +3153,46 @@ var GrpcQueueOperations = class {
|
|
|
2919
3153
|
}
|
|
2920
3154
|
};
|
|
2921
3155
|
var GrpcWorkerOperations = class {
|
|
2922
|
-
constructor(client, metadata) {
|
|
3156
|
+
constructor(client, metadata, timeoutMs) {
|
|
2923
3157
|
this.client = client;
|
|
2924
3158
|
this.metadata = metadata;
|
|
3159
|
+
this.timeoutMs = timeoutMs;
|
|
2925
3160
|
}
|
|
2926
3161
|
/**
|
|
2927
3162
|
* Register a new worker
|
|
2928
3163
|
*/
|
|
2929
3164
|
async register(params) {
|
|
2930
|
-
return promisify(
|
|
3165
|
+
return promisify(
|
|
3166
|
+
this.client,
|
|
3167
|
+
this.client.Register,
|
|
3168
|
+
params,
|
|
3169
|
+
this.metadata,
|
|
3170
|
+
this.timeoutMs
|
|
3171
|
+
);
|
|
2931
3172
|
}
|
|
2932
3173
|
/**
|
|
2933
3174
|
* Send heartbeat
|
|
2934
3175
|
*/
|
|
2935
3176
|
async heartbeat(params) {
|
|
2936
|
-
return promisify(
|
|
3177
|
+
return promisify(
|
|
3178
|
+
this.client,
|
|
3179
|
+
this.client.Heartbeat,
|
|
3180
|
+
params,
|
|
3181
|
+
this.metadata,
|
|
3182
|
+
this.timeoutMs
|
|
3183
|
+
);
|
|
2937
3184
|
}
|
|
2938
3185
|
/**
|
|
2939
3186
|
* Deregister a worker
|
|
2940
3187
|
*/
|
|
2941
3188
|
async deregister(workerId) {
|
|
2942
|
-
return promisify(
|
|
3189
|
+
return promisify(
|
|
3190
|
+
this.client,
|
|
3191
|
+
this.client.Deregister,
|
|
3192
|
+
{ workerId },
|
|
3193
|
+
this.metadata,
|
|
3194
|
+
this.timeoutMs
|
|
3195
|
+
);
|
|
2943
3196
|
}
|
|
2944
3197
|
};
|
|
2945
3198
|
var SpooledGrpcClient = class {
|
|
@@ -2951,7 +3204,7 @@ var SpooledGrpcClient = class {
|
|
|
2951
3204
|
/** Worker operations */
|
|
2952
3205
|
workers;
|
|
2953
3206
|
constructor(options) {
|
|
2954
|
-
const { address, apiKey, useTls, credentials: credentials2, channelOptions } = options;
|
|
3207
|
+
const { address, apiKey, useTls, credentials: credentials2, channelOptions, timeout } = options;
|
|
2955
3208
|
const creds = credentials2 ?? (shouldUseTls(address, useTls) ? grpc2__namespace.credentials.createSsl() : grpc2__namespace.credentials.createInsecure());
|
|
2956
3209
|
this.metadata = new grpc2__namespace.Metadata();
|
|
2957
3210
|
this.metadata.add("x-api-key", apiKey);
|
|
@@ -2966,8 +3219,16 @@ var SpooledGrpcClient = class {
|
|
|
2966
3219
|
creds,
|
|
2967
3220
|
channelOptions
|
|
2968
3221
|
);
|
|
2969
|
-
this.queue = new GrpcQueueOperations(
|
|
2970
|
-
|
|
3222
|
+
this.queue = new GrpcQueueOperations(
|
|
3223
|
+
this.queueClient,
|
|
3224
|
+
this.metadata,
|
|
3225
|
+
timeout
|
|
3226
|
+
);
|
|
3227
|
+
this.workers = new GrpcWorkerOperations(
|
|
3228
|
+
this.workerClient,
|
|
3229
|
+
this.metadata,
|
|
3230
|
+
timeout
|
|
3231
|
+
);
|
|
2971
3232
|
}
|
|
2972
3233
|
/**
|
|
2973
3234
|
* Close all gRPC connections
|
|
@@ -3116,7 +3377,8 @@ var SpooledClient = class _SpooledClient {
|
|
|
3116
3377
|
}
|
|
3117
3378
|
this._grpc = new SpooledGrpcClient({
|
|
3118
3379
|
address: grpcAddress,
|
|
3119
|
-
apiKey
|
|
3380
|
+
apiKey,
|
|
3381
|
+
timeout: this.config.timeout
|
|
3120
3382
|
});
|
|
3121
3383
|
}
|
|
3122
3384
|
return this._grpc;
|
|
@@ -3183,7 +3445,9 @@ var SpooledClient = class _SpooledClient {
|
|
|
3183
3445
|
}
|
|
3184
3446
|
return this.loginForJwt();
|
|
3185
3447
|
}
|
|
3186
|
-
throw new AuthenticationError(
|
|
3448
|
+
throw new AuthenticationError(
|
|
3449
|
+
"No authentication method available for realtime connection"
|
|
3450
|
+
);
|
|
3187
3451
|
}
|
|
3188
3452
|
/**
|
|
3189
3453
|
* Exchange the API key for a JWT via /auth/login and cache the result.
|
|
@@ -3480,7 +3744,10 @@ var SpooledWorker = class {
|
|
|
3480
3744
|
this.sendWorkerHeartbeat();
|
|
3481
3745
|
}, heartbeatInterval);
|
|
3482
3746
|
this.state = "running";
|
|
3483
|
-
this.emit("started", {
|
|
3747
|
+
this.emit("started", {
|
|
3748
|
+
workerId: this.workerId,
|
|
3749
|
+
queueName: this.options.queueName
|
|
3750
|
+
});
|
|
3484
3751
|
this.schedulePoll();
|
|
3485
3752
|
} catch (error) {
|
|
3486
3753
|
this.state = "error";
|
|
@@ -3516,14 +3783,18 @@ var SpooledWorker = class {
|
|
|
3516
3783
|
active.abortController.abort();
|
|
3517
3784
|
}
|
|
3518
3785
|
if (this.activeJobs.size > 0) {
|
|
3519
|
-
this.debug(
|
|
3786
|
+
this.debug(
|
|
3787
|
+
`Waiting for ${this.activeJobs.size} active jobs to complete...`
|
|
3788
|
+
);
|
|
3520
3789
|
await Promise.race([
|
|
3521
3790
|
this.waitForActiveJobs(),
|
|
3522
3791
|
this.sleep(this.options.shutdownTimeout)
|
|
3523
3792
|
]);
|
|
3524
3793
|
const remaining = Array.from(this.activeJobs.values());
|
|
3525
3794
|
for (const active of remaining) {
|
|
3526
|
-
this.debug(
|
|
3795
|
+
this.debug(
|
|
3796
|
+
`Force-failing job ${active.job.id} due to shutdown timeout`
|
|
3797
|
+
);
|
|
3527
3798
|
await this.failJob(active.job, "Worker shutdown timeout");
|
|
3528
3799
|
this.cleanupJob(active);
|
|
3529
3800
|
}
|
|
@@ -3631,7 +3902,9 @@ var SpooledWorker = class {
|
|
|
3631
3902
|
retryCount: job.retryCount,
|
|
3632
3903
|
maxRetries: job.maxRetries,
|
|
3633
3904
|
signal,
|
|
3634
|
-
progress: async (
|
|
3905
|
+
progress: async (percent, message) => {
|
|
3906
|
+
const boundedPercent = Math.max(0, Math.min(100, percent));
|
|
3907
|
+
this.debug(`[${job.id}] progress ${boundedPercent}%`, message);
|
|
3635
3908
|
},
|
|
3636
3909
|
log: (level, message, meta) => {
|
|
3637
3910
|
this.debug(`[${job.id}] [${level}] ${message}`, meta);
|