@spooled/sdk 1.0.39 → 1.1.0

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.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.39",
29
+ userAgent: "@spooled/sdk-nodejs/1.1.0",
30
30
  autoRefreshToken: true
31
31
  };
32
- var SDK_VERSION = "1.0.39";
32
+ var SDK_VERSION = "1.1.0";
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(message, code, rateLimitInfo, details, requestId);
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(message, response.status, code, details, requestId);
368
+ return new ServerError(
369
+ message,
370
+ response.status,
371
+ code,
372
+ details,
373
+ requestId
374
+ );
363
375
  }
364
- return new SpooledError(message, response.status, code, details, requestId);
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(), { once: true });
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(`Request timed out after ${timeoutMs}ms`, timeoutMs);
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(url, init, timeout, options.signal);
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(`Network request failed: ${cause?.message ?? "Unknown error"}`, cause);
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(() => this.executeRequest(url, options));
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`, { error: error.message });
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((key) => key.toLowerCase() === "idempotency-key");
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, { ...options, method: "POST", body });
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, { ...options, method: "PUT", body });
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, { ...options, method: "PATCH", body });
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, { ...options, method: "DELETE" });
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("/auth/logout", token ? { refreshToken: token } : void 0);
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("/auth/email/start", { email });
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", { params });
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`, { 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(`/jobs/${id}/fail`, params);
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(`/jobs/${id}/heartbeat`, params);
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", { params });
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(`/queues/${encodeURIComponent(name)}/config`, params);
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(`/queues/${encodeURIComponent(name)}/stats`);
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(`/queues/${encodeURIComponent(name)}/resume`);
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", { params });
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", { params });
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(`/workflows/${workflowId}/jobs/status`);
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(`/jobs/${jobId}/dependencies`, params);
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(`/outgoing-webhooks/${id}/deliveries`);
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", { name });
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("/organizations/webhook-token/regenerate");
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("/billing/portal", params);
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("Admin key is required for admin endpoints. Provide `adminKey` in SpooledClient config.");
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("/admin/organizations", params, {
1695
- headers: this.headers()
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(`/admin/organizations/${id}`, {
1701
- headers: this.headers()
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(`/admin/organizations/${orgId}/api-keys`, params, {
1721
- headers: this.headers()
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(`/admin/organizations/${orgId}/reset-usage`, void 0, {
1727
- headers: this.headers()
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("GitHub webhook signature is required (provide `signature` or `secret`)");
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("Stripe webhook signature is required (provide `signature` or `secret`)");
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(typeof event.data === "string" ? event.data : String(event.data));
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(new Error(`WebSocket connection failed: ${event.reason || "Unknown error"}`));
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(`Scheduling reconnect attempt ${this.reconnectAttempts} in ${delay}ms`);
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 status = event.status ?? event.statusCode ?? event.error?.status;
2158
- if (status === 401 || status === 403) {
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(event.message ?? event.error?.message ?? event.reason ?? "");
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("eventsource package is required for SSE in Node.js. Install it with: npm install eventsource");
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(`Scheduling SSE reconnect attempt ${this.reconnectAttempts} in ${delay}ms`);
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(protoPath, PROTO_LOADER_OPTIONS);
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(protoPath, PROTO_LOADER_OPTIONS);
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, { onConnected, onError, onEnd });
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", (status) => {
2626
- if (status.code === 0) {
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(Object.entries(fields).map(([key, entry]) => [key, decodeValue(entry)]));
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 { ...params, result: encodeStruct(params.result) };
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
- method.call(client, request, metadata, (error, response) => {
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(this.client, this.client.Enqueue, encodeEnqueueRequest(params), this.metadata);
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(this.client, this.client.Dequeue, params, this.metadata);
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(this.client, this.client.Complete, encodeCompleteRequest(params), this.metadata);
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(this.client, this.client.Fail, params, this.metadata);
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(this.client, this.client.RenewLease, params, this.metadata);
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(this.client, this.client.GetJob, { jobId }, this.metadata);
2844
- return { ...response, job: response.job ? decodeJob(response.job) : response.job };
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(this.client, this.client.GetQueueStats, { queueName }, this.metadata);
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(this.client, this.client.Register, params, this.metadata);
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(this.client, this.client.Heartbeat, params, this.metadata);
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(this.client, this.client.Deregister, { workerId }, this.metadata);
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(this.queueClient, this.metadata);
2946
- this.workers = new GrpcWorkerOperations(this.workerClient, this.metadata);
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("No authentication method available for realtime connection");
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.
@@ -3373,6 +3637,11 @@ var DEFAULT_OPTIONS = {
3373
3637
  };
3374
3638
  var SpooledWorker = class {
3375
3639
  client;
3640
+ /**
3641
+ * Options with every defaultable field filled in. `workerId` stays optional:
3642
+ * there is no sensible default for it, and omitting it is what makes the
3643
+ * server mint a UUID.
3644
+ */
3376
3645
  options;
3377
3646
  debug;
3378
3647
  state = "idle";
@@ -3443,6 +3712,7 @@ var SpooledWorker = class {
3443
3712
  try {
3444
3713
  const registration = await this.client.workers.register({
3445
3714
  queueName: this.options.queueName,
3715
+ workerId: this.options.workerId,
3446
3716
  hostname: this.options.hostname,
3447
3717
  workerType: this.options.workerType,
3448
3718
  maxConcurrency: this.options.concurrency,
@@ -3456,7 +3726,10 @@ var SpooledWorker = class {
3456
3726
  this.sendWorkerHeartbeat();
3457
3727
  }, heartbeatInterval);
3458
3728
  this.state = "running";
3459
- this.emit("started", { workerId: this.workerId, queueName: this.options.queueName });
3729
+ this.emit("started", {
3730
+ workerId: this.workerId,
3731
+ queueName: this.options.queueName
3732
+ });
3460
3733
  this.schedulePoll();
3461
3734
  } catch (error) {
3462
3735
  this.state = "error";
@@ -3492,14 +3765,18 @@ var SpooledWorker = class {
3492
3765
  active.abortController.abort();
3493
3766
  }
3494
3767
  if (this.activeJobs.size > 0) {
3495
- this.debug(`Waiting for ${this.activeJobs.size} active jobs to complete...`);
3768
+ this.debug(
3769
+ `Waiting for ${this.activeJobs.size} active jobs to complete...`
3770
+ );
3496
3771
  await Promise.race([
3497
3772
  this.waitForActiveJobs(),
3498
3773
  this.sleep(this.options.shutdownTimeout)
3499
3774
  ]);
3500
3775
  const remaining = Array.from(this.activeJobs.values());
3501
3776
  for (const active of remaining) {
3502
- this.debug(`Force-failing job ${active.job.id} due to shutdown timeout`);
3777
+ this.debug(
3778
+ `Force-failing job ${active.job.id} due to shutdown timeout`
3779
+ );
3503
3780
  await this.failJob(active.job, "Worker shutdown timeout");
3504
3781
  this.cleanupJob(active);
3505
3782
  }
@@ -3607,7 +3884,9 @@ var SpooledWorker = class {
3607
3884
  retryCount: job.retryCount,
3608
3885
  maxRetries: job.maxRetries,
3609
3886
  signal,
3610
- progress: async (_percent, _message) => {
3887
+ progress: async (percent, message) => {
3888
+ const boundedPercent = Math.max(0, Math.min(100, percent));
3889
+ this.debug(`[${job.id}] progress ${boundedPercent}%`, message);
3611
3890
  },
3612
3891
  log: (level, message, meta) => {
3613
3892
  this.debug(`[${job.id}] [${level}] ${message}`, meta);