@spooled/sdk 1.0.38 → 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/dist/index.js CHANGED
@@ -2,8 +2,9 @@ import { createHmac } from 'crypto';
2
2
  import { Buffer } from 'buffer';
3
3
  import * as grpc2 from '@grpc/grpc-js';
4
4
  import * as protoLoader from '@grpc/proto-loader';
5
+ import { existsSync } from 'fs';
5
6
  import { fileURLToPath } from 'url';
6
- import { dirname, join } from 'path';
7
+ import { join, dirname } from 'path';
7
8
  import { hostname } from 'os';
8
9
 
9
10
  // src/config.ts
@@ -25,10 +26,10 @@ var DEFAULT_CONFIG = {
25
26
  successThreshold: 3,
26
27
  timeout: 3e4
27
28
  },
28
- userAgent: "@spooled/sdk-nodejs/1.0.38",
29
+ userAgent: "@spooled/sdk-nodejs/1.0.40",
29
30
  autoRefreshToken: true
30
31
  };
31
- var SDK_VERSION = "1.0.38";
32
+ var SDK_VERSION = "1.0.40";
32
33
  var API_VERSION = "v1";
33
34
  var API_BASE_PATH = `/api/${API_VERSION}`;
34
35
  function normalizeCredential(value) {
@@ -354,13 +355,31 @@ async function createErrorFromResponse(response) {
354
355
  return new PayloadTooLargeError(message, code, details, requestId);
355
356
  case 429: {
356
357
  const rateLimitInfo = parseRateLimitHeaders(response.headers);
357
- return new RateLimitError(message, code, rateLimitInfo, details, requestId);
358
+ return new RateLimitError(
359
+ message,
360
+ code,
361
+ rateLimitInfo,
362
+ details,
363
+ requestId
364
+ );
358
365
  }
359
366
  default:
360
367
  if (response.status >= 500) {
361
- 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
+ );
362
375
  }
363
- 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
+ );
364
383
  }
365
384
  }
366
385
  function isSpooledError(error) {
@@ -618,7 +637,9 @@ var HttpClient = class {
618
637
  if (externalSignal.aborted) {
619
638
  controller.abort();
620
639
  } else {
621
- externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
640
+ externalSignal.addEventListener("abort", () => controller.abort(), {
641
+ once: true
642
+ });
622
643
  }
623
644
  }
624
645
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -633,7 +654,10 @@ var HttpClient = class {
633
654
  if (externalSignal?.aborted) {
634
655
  throw error;
635
656
  }
636
- throw new TimeoutError(`Request timed out after ${timeoutMs}ms`, timeoutMs);
657
+ throw new TimeoutError(
658
+ `Request timed out after ${timeoutMs}ms`,
659
+ timeoutMs
660
+ );
637
661
  }
638
662
  throw error;
639
663
  } finally {
@@ -662,13 +686,21 @@ var HttpClient = class {
662
686
  this.debug?.(`${method} ${url}`, { timeout, hasBody: !!options.body });
663
687
  let response;
664
688
  try {
665
- response = await this.fetchWithTimeout(url, init, timeout, options.signal);
689
+ response = await this.fetchWithTimeout(
690
+ url,
691
+ init,
692
+ timeout,
693
+ options.signal
694
+ );
666
695
  } catch (error) {
667
696
  if (error instanceof TimeoutError || error instanceof SpooledError) {
668
697
  throw error;
669
698
  }
670
699
  const cause = error instanceof Error ? error : void 0;
671
- 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
+ );
672
704
  }
673
705
  this.debug?.(`Response: ${response.status}`, { url });
674
706
  if (!response.ok) {
@@ -715,7 +747,9 @@ var HttpClient = class {
715
747
  const url = this.buildUrl(path, options.params, options.skipApiPrefix);
716
748
  const method = options.method ?? "GET";
717
749
  const execute = async () => {
718
- return this.circuitBreaker.execute(() => this.executeRequest(url, options));
750
+ return this.circuitBreaker.execute(
751
+ () => this.executeRequest(url, options)
752
+ );
719
753
  };
720
754
  if (options.skipRetry) {
721
755
  return execute();
@@ -724,7 +758,9 @@ var HttpClient = class {
724
758
  config: this.resolveRetryConfig(method, options),
725
759
  signal: options.signal,
726
760
  onRetry: (attempt, error, delayMs) => {
727
- 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
+ });
728
764
  }
729
765
  });
730
766
  }
@@ -736,7 +772,9 @@ var HttpClient = class {
736
772
  if (!options.headers) {
737
773
  return false;
738
774
  }
739
- 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
+ );
740
778
  }
741
779
  /**
742
780
  * Resolve the retry configuration for a request.
@@ -774,28 +812,43 @@ var HttpClient = class {
774
812
  * Make a POST request
775
813
  */
776
814
  async post(path, body, options) {
777
- 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
+ });
778
820
  return response.data;
779
821
  }
780
822
  /**
781
823
  * Make a PUT request
782
824
  */
783
825
  async put(path, body, options) {
784
- 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
+ });
785
831
  return response.data;
786
832
  }
787
833
  /**
788
834
  * Make a PATCH request
789
835
  */
790
836
  async patch(path, body, options) {
791
- 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
+ });
792
842
  return response.data;
793
843
  }
794
844
  /**
795
845
  * Make a DELETE request
796
846
  */
797
847
  async delete(path, options) {
798
- const response = await this.request(path, { ...options, method: "DELETE" });
848
+ const response = await this.request(path, {
849
+ ...options,
850
+ method: "DELETE"
851
+ });
799
852
  return response.data;
800
853
  }
801
854
  };
@@ -989,7 +1042,10 @@ var AuthResource = class {
989
1042
  */
990
1043
  async logout(refreshToken) {
991
1044
  const token = refreshToken ?? this.getRefreshToken?.();
992
- 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
+ );
993
1049
  }
994
1050
  /**
995
1051
  * Get current user/session info
@@ -1007,7 +1063,10 @@ var AuthResource = class {
1007
1063
  * Start email-based login flow (sends magic link)
1008
1064
  */
1009
1065
  async startEmailLogin(email) {
1010
- return this.http.post("/auth/email/start", { email });
1066
+ return this.http.post(
1067
+ "/auth/email/start",
1068
+ { email }
1069
+ );
1011
1070
  }
1012
1071
  /**
1013
1072
  * Check if an email address exists in the system
@@ -1048,7 +1107,9 @@ var JobsResource = class {
1048
1107
  * List jobs with optional filtering
1049
1108
  */
1050
1109
  async list(params) {
1051
- return this.http.get("/jobs", { params });
1110
+ return this.http.get("/jobs", {
1111
+ params
1112
+ });
1052
1113
  }
1053
1114
  /**
1054
1115
  * Get a job by ID
@@ -1072,7 +1133,9 @@ var JobsResource = class {
1072
1133
  * Boost job priority
1073
1134
  */
1074
1135
  async boostPriority(id, priority) {
1075
- return this.http.put(`/jobs/${id}/priority`, { priority });
1136
+ return this.http.put(`/jobs/${id}/priority`, {
1137
+ priority
1138
+ });
1076
1139
  }
1077
1140
  /**
1078
1141
  * Get job statistics
@@ -1117,17 +1180,25 @@ var JobsResource = class {
1117
1180
  * Fail a job (worker nack)
1118
1181
  */
1119
1182
  async fail(id, params) {
1120
- return this.http.post(`/jobs/${id}/fail`, params);
1183
+ return this.http.post(
1184
+ `/jobs/${id}/fail`,
1185
+ params
1186
+ );
1121
1187
  }
1122
1188
  /**
1123
1189
  * Extend job lease (heartbeat)
1124
1190
  */
1125
1191
  async heartbeat(id, params) {
1126
- return this.http.post(`/jobs/${id}/heartbeat`, params);
1192
+ return this.http.post(
1193
+ `/jobs/${id}/heartbeat`,
1194
+ params
1195
+ );
1127
1196
  }
1128
1197
  // DLQ operations (private implementations)
1129
1198
  async listDlq(params) {
1130
- return this.http.get("/jobs/dlq", { params });
1199
+ return this.http.get("/jobs/dlq", {
1200
+ params
1201
+ });
1131
1202
  }
1132
1203
  async retryDlq(params) {
1133
1204
  return this.http.post("/jobs/dlq/retry", params);
@@ -1158,13 +1229,18 @@ var QueuesResource = class {
1158
1229
  * Update queue configuration
1159
1230
  */
1160
1231
  async updateConfig(name, params) {
1161
- return this.http.put(`/queues/${encodeURIComponent(name)}/config`, params);
1232
+ return this.http.put(
1233
+ `/queues/${encodeURIComponent(name)}/config`,
1234
+ params
1235
+ );
1162
1236
  }
1163
1237
  /**
1164
1238
  * Get queue statistics
1165
1239
  */
1166
1240
  async getStats(name) {
1167
- return this.http.get(`/queues/${encodeURIComponent(name)}/stats`);
1241
+ return this.http.get(
1242
+ `/queues/${encodeURIComponent(name)}/stats`
1243
+ );
1168
1244
  }
1169
1245
  /**
1170
1246
  * Pause a queue
@@ -1179,7 +1255,9 @@ var QueuesResource = class {
1179
1255
  * Resume a paused queue
1180
1256
  */
1181
1257
  async resume(name) {
1182
- return this.http.post(`/queues/${encodeURIComponent(name)}/resume`);
1258
+ return this.http.post(
1259
+ `/queues/${encodeURIComponent(name)}/resume`
1260
+ );
1183
1261
  }
1184
1262
  /**
1185
1263
  * Delete a queue configuration
@@ -1235,7 +1313,9 @@ var SchedulesResource = class {
1235
1313
  * List all schedules
1236
1314
  */
1237
1315
  async list(params) {
1238
- return this.http.get("/schedules", { params });
1316
+ return this.http.get("/schedules", {
1317
+ params
1318
+ });
1239
1319
  }
1240
1320
  /**
1241
1321
  * Create a new schedule
@@ -1307,7 +1387,9 @@ var WorkflowsResource = class {
1307
1387
  * List all workflows
1308
1388
  */
1309
1389
  async list(params) {
1310
- return this.http.get("/workflows", { params });
1390
+ return this.http.get("/workflows", {
1391
+ params
1392
+ });
1311
1393
  }
1312
1394
  /**
1313
1395
  * Create a new workflow
@@ -1344,13 +1426,18 @@ var WorkflowsResource = class {
1344
1426
  return this.http.get(`/workflows/${workflowId}/jobs/${jobId}`);
1345
1427
  }
1346
1428
  async getWorkflowJobsStatus(workflowId) {
1347
- return this.http.get(`/workflows/${workflowId}/jobs/status`);
1429
+ return this.http.get(
1430
+ `/workflows/${workflowId}/jobs/status`
1431
+ );
1348
1432
  }
1349
1433
  async getJobDependencies(jobId) {
1350
1434
  return this.http.get(`/jobs/${jobId}/dependencies`);
1351
1435
  }
1352
1436
  async addJobDependencies(jobId, params) {
1353
- return this.http.post(`/jobs/${jobId}/dependencies`, params);
1437
+ return this.http.post(
1438
+ `/jobs/${jobId}/dependencies`,
1439
+ params
1440
+ );
1354
1441
  }
1355
1442
  };
1356
1443
 
@@ -1399,7 +1486,9 @@ var WebhooksResource = class {
1399
1486
  * Get webhook delivery history
1400
1487
  */
1401
1488
  async getDeliveries(id) {
1402
- return this.http.get(`/outgoing-webhooks/${id}/deliveries`);
1489
+ return this.http.get(
1490
+ `/outgoing-webhooks/${id}/deliveries`
1491
+ );
1403
1492
  }
1404
1493
  /**
1405
1494
  * Retry a specific webhook delivery
@@ -1507,7 +1596,9 @@ var OrganizationsResource = class {
1507
1596
  * Generate a unique slug from an organization name
1508
1597
  */
1509
1598
  async generateSlug(name) {
1510
- return this.http.post("/organizations/generate-slug", { name });
1599
+ return this.http.post("/organizations/generate-slug", {
1600
+ name
1601
+ });
1511
1602
  }
1512
1603
  /**
1513
1604
  * Get the webhook token for the current organization.
@@ -1537,7 +1628,9 @@ var OrganizationsResource = class {
1537
1628
  * ```
1538
1629
  */
1539
1630
  async regenerateWebhookToken() {
1540
- return this.http.post("/organizations/webhook-token/regenerate");
1631
+ return this.http.post(
1632
+ "/organizations/webhook-token/regenerate"
1633
+ );
1541
1634
  }
1542
1635
  /**
1543
1636
  * Clear/delete the webhook token for the current organization.
@@ -1574,7 +1667,10 @@ var BillingResource = class {
1574
1667
  * POST /api/v1/billing/portal
1575
1668
  */
1576
1669
  async createPortal(params) {
1577
- return this.http.post("/billing/portal", params);
1670
+ return this.http.post(
1671
+ "/billing/portal",
1672
+ params
1673
+ );
1578
1674
  }
1579
1675
  };
1580
1676
 
@@ -1669,7 +1765,9 @@ var AdminResource = class {
1669
1765
  }
1670
1766
  headers() {
1671
1767
  if (!this.adminKey) {
1672
- 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
+ );
1673
1771
  }
1674
1772
  return { "X-Admin-Key": this.adminKey };
1675
1773
  }
@@ -1690,15 +1788,22 @@ var AdminResource = class {
1690
1788
  }
1691
1789
  /** POST /api/v1/admin/organizations */
1692
1790
  async createOrganization(params) {
1693
- return this.http.post("/admin/organizations", params, {
1694
- headers: this.headers()
1695
- });
1791
+ return this.http.post(
1792
+ "/admin/organizations",
1793
+ params,
1794
+ {
1795
+ headers: this.headers()
1796
+ }
1797
+ );
1696
1798
  }
1697
1799
  /** GET /api/v1/admin/organizations/{id} */
1698
1800
  async getOrganization(id) {
1699
- return this.http.get(`/admin/organizations/${id}`, {
1700
- headers: this.headers()
1701
- });
1801
+ return this.http.get(
1802
+ `/admin/organizations/${id}`,
1803
+ {
1804
+ headers: this.headers()
1805
+ }
1806
+ );
1702
1807
  }
1703
1808
  /** PATCH /api/v1/admin/organizations/{id} */
1704
1809
  async updateOrganization(id, params) {
@@ -1716,15 +1821,23 @@ var AdminResource = class {
1716
1821
  }
1717
1822
  /** POST /api/v1/admin/organizations/{id}/api-keys */
1718
1823
  async createApiKey(orgId, params) {
1719
- return this.http.post(`/admin/organizations/${orgId}/api-keys`, params, {
1720
- headers: this.headers()
1721
- });
1824
+ return this.http.post(
1825
+ `/admin/organizations/${orgId}/api-keys`,
1826
+ params,
1827
+ {
1828
+ headers: this.headers()
1829
+ }
1830
+ );
1722
1831
  }
1723
1832
  /** POST /api/v1/admin/organizations/{id}/reset-usage */
1724
1833
  async resetUsage(orgId) {
1725
- await this.http.post(`/admin/organizations/${orgId}/reset-usage`, void 0, {
1726
- headers: this.headers()
1727
- });
1834
+ await this.http.post(
1835
+ `/admin/organizations/${orgId}/reset-usage`,
1836
+ void 0,
1837
+ {
1838
+ headers: this.headers()
1839
+ }
1840
+ );
1728
1841
  }
1729
1842
  /** GET /api/v1/admin/stats */
1730
1843
  async getStats() {
@@ -1770,7 +1883,9 @@ var WebhookIngestionResource = class {
1770
1883
  const bytes = toBytes(body);
1771
1884
  const signature = options.signature ?? (options.secret ? githubSignature(options.secret, bytes) : void 0);
1772
1885
  if (!signature) {
1773
- 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
+ );
1774
1889
  }
1775
1890
  const headers = {
1776
1891
  "Content-Type": "application/json",
@@ -1801,7 +1916,9 @@ var WebhookIngestionResource = class {
1801
1916
  const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
1802
1917
  const signature = options.signature ?? (options.secret ? stripeSignature(options.secret, bytes, timestamp) : void 0);
1803
1918
  if (!signature) {
1804
- 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
+ );
1805
1922
  }
1806
1923
  const headers = {
1807
1924
  "Content-Type": "application/json",
@@ -1938,14 +2055,20 @@ var WebSocketRealtimeClient = class {
1938
2055
  resolve();
1939
2056
  };
1940
2057
  this.ws.onmessage = (event) => {
1941
- 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
+ );
1942
2061
  };
1943
2062
  this.ws.onclose = (event) => {
1944
2063
  this.options.debug(`WebSocket closed: ${event.code} ${event.reason}`);
1945
2064
  const wasConnecting = this.state === "connecting";
1946
2065
  this.handleDisconnect();
1947
2066
  if (wasConnecting) {
1948
- 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
+ );
1949
2072
  }
1950
2073
  };
1951
2074
  this.ws.onerror = (event) => {
@@ -2100,7 +2223,9 @@ var WebSocketRealtimeClient = class {
2100
2223
  this.options.maxReconnectDelay
2101
2224
  );
2102
2225
  const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
2103
- 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
+ );
2104
2229
  this.reconnectTimer = setTimeout(async () => {
2105
2230
  try {
2106
2231
  await this.connect();
@@ -2153,11 +2278,13 @@ function isAuthFailureEvent(event) {
2153
2278
  if (!event) {
2154
2279
  return false;
2155
2280
  }
2156
- const status = event.status ?? event.statusCode ?? event.error?.status;
2157
- if (status === 401 || status === 403) {
2281
+ const status2 = event.status ?? event.statusCode ?? event.error?.status;
2282
+ if (status2 === 401 || status2 === 403) {
2158
2283
  return true;
2159
2284
  }
2160
- const text = String(event.message ?? event.error?.message ?? event.reason ?? "");
2285
+ const text = String(
2286
+ event.message ?? event.error?.message ?? event.reason ?? ""
2287
+ );
2161
2288
  return /\b(401|403)\b/.test(text);
2162
2289
  }
2163
2290
 
@@ -2220,7 +2347,9 @@ var SseRealtimeClient = class {
2220
2347
  EventSourceImpl = mod.default || mod.EventSource || mod;
2221
2348
  } catch {
2222
2349
  this.setState("disconnected");
2223
- 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
+ );
2224
2353
  }
2225
2354
  }
2226
2355
  let token;
@@ -2389,7 +2518,9 @@ var SseRealtimeClient = class {
2389
2518
  this.options.maxReconnectDelay
2390
2519
  );
2391
2520
  const delay = Math.floor(baseDelay + Math.random() * baseDelay * 0.25);
2392
- 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
+ );
2393
2524
  this.reconnectTimer = setTimeout(async () => {
2394
2525
  try {
2395
2526
  await this.connect(this.filter || void 0);
@@ -2535,20 +2666,40 @@ var PROTO_LOADER_OPTIONS = {
2535
2666
  // Support oneofs
2536
2667
  };
2537
2668
  var cachedDefinition = null;
2538
- function getProtoPath() {
2669
+ function getModuleDir() {
2539
2670
  if (typeof import.meta?.url !== "undefined") {
2540
- const __filename = fileURLToPath(import.meta.url);
2541
- const __dirname2 = dirname(__filename);
2542
- return join(__dirname2, "../../proto/spooled.proto");
2671
+ return dirname(fileURLToPath(import.meta.url));
2543
2672
  }
2544
- return join(__dirname, "../../proto/spooled.proto");
2673
+ return __dirname;
2674
+ }
2675
+ function getProtoPath() {
2676
+ const moduleDir = getModuleDir();
2677
+ const candidates = [
2678
+ // Bundled ESM/CJS: dist/index.js → ../proto/spooled.proto
2679
+ join(moduleDir, "../proto/spooled.proto"),
2680
+ // Source / unbundled: src/grpc/loader.ts → ../../proto/spooled.proto
2681
+ join(moduleDir, "../../proto/spooled.proto"),
2682
+ // Extra safety if moduleDir is package root
2683
+ join(moduleDir, "proto/spooled.proto")
2684
+ ];
2685
+ for (const candidate of candidates) {
2686
+ if (existsSync(candidate)) {
2687
+ return candidate;
2688
+ }
2689
+ }
2690
+ throw new Error(
2691
+ `Spooled gRPC proto not found. Tried: ${candidates.join(", ")}. Ensure the package's proto/spooled.proto is installed next to dist/.`
2692
+ );
2545
2693
  }
2546
2694
  function loadProtoDefinition() {
2547
2695
  if (cachedDefinition) {
2548
2696
  return cachedDefinition;
2549
2697
  }
2550
2698
  const protoPath = getProtoPath();
2551
- const packageDefinition = protoLoader.loadSync(protoPath, PROTO_LOADER_OPTIONS);
2699
+ const packageDefinition = protoLoader.loadSync(
2700
+ protoPath,
2701
+ PROTO_LOADER_OPTIONS
2702
+ );
2552
2703
  const grpcObject = grpc2.loadPackageDefinition(packageDefinition);
2553
2704
  cachedDefinition = grpcObject;
2554
2705
  return cachedDefinition;
@@ -2558,7 +2709,10 @@ async function loadProtoDefinitionAsync() {
2558
2709
  return cachedDefinition;
2559
2710
  }
2560
2711
  const protoPath = getProtoPath();
2561
- const packageDefinition = await protoLoader.load(protoPath, PROTO_LOADER_OPTIONS);
2712
+ const packageDefinition = await protoLoader.load(
2713
+ protoPath,
2714
+ PROTO_LOADER_OPTIONS
2715
+ );
2562
2716
  const grpcObject = grpc2.loadPackageDefinition(packageDefinition);
2563
2717
  cachedDefinition = grpcObject;
2564
2718
  return cachedDefinition;
@@ -2575,7 +2729,11 @@ async function* asyncIterableFromStream(stream, options) {
2575
2729
  stream.cancel();
2576
2730
  });
2577
2731
  }
2578
- return yield* new AsyncIterableStream(stream, { onConnected, onError, onEnd });
2732
+ return yield* new AsyncIterableStream(stream, {
2733
+ onConnected,
2734
+ onError,
2735
+ onEnd
2736
+ });
2579
2737
  }
2580
2738
  var AsyncIterableStream = class {
2581
2739
  stream;
@@ -2604,8 +2762,8 @@ var AsyncIterableStream = class {
2604
2762
  onEnd?.();
2605
2763
  resolve?.();
2606
2764
  });
2607
- this.stream.on("status", (status) => {
2608
- if (status.code === 0) {
2765
+ this.stream.on("status", (status2) => {
2766
+ if (status2.code === 0) {
2609
2767
  onConnected?.();
2610
2768
  }
2611
2769
  });
@@ -2706,7 +2864,9 @@ function decodeStruct(value) {
2706
2864
  return value;
2707
2865
  }
2708
2866
  const fields = value.fields ?? {};
2709
- 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
+ );
2710
2870
  }
2711
2871
  function decodeValue(value) {
2712
2872
  if ("nullValue" in value) {
@@ -2755,7 +2915,10 @@ function encodeEnqueueRequest(params) {
2755
2915
  return encoded;
2756
2916
  }
2757
2917
  function encodeCompleteRequest(params) {
2758
- return { ...params, result: encodeStruct(params.result) };
2918
+ return {
2919
+ ...params,
2920
+ result: encodeStruct(params.result)
2921
+ };
2759
2922
  }
2760
2923
  function decodeJob(job) {
2761
2924
  return {
@@ -2764,17 +2927,60 @@ function decodeJob(job) {
2764
2927
  result: decodeStruct(job.result)
2765
2928
  };
2766
2929
  }
2767
- function promisify(client, method, request, metadata) {
2930
+ function promisify(client, method, request, metadata, timeoutMs) {
2768
2931
  return new Promise((resolve, reject) => {
2769
- method.call(client, request, metadata, (error, response) => {
2932
+ const callback = (error, response) => {
2770
2933
  if (error) {
2771
- reject(error);
2934
+ reject(mapGrpcError(error, timeoutMs));
2772
2935
  } else {
2773
2936
  resolve(response);
2774
2937
  }
2775
- });
2938
+ };
2939
+ method.call(
2940
+ client,
2941
+ request,
2942
+ metadata,
2943
+ createUnaryCallOptions(timeoutMs),
2944
+ callback
2945
+ );
2776
2946
  });
2777
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
+ }
2778
2984
  function shouldUseTls(address, explicitTls) {
2779
2985
  if (explicitTls !== void 0) {
2780
2986
  return explicitTls;
@@ -2783,53 +2989,99 @@ function shouldUseTls(address, explicitTls) {
2783
2989
  return host !== "localhost" && host !== "127.0.0.1" && !host.startsWith("[::1]");
2784
2990
  }
2785
2991
  var GrpcQueueOperations = class {
2786
- constructor(client, metadata) {
2992
+ constructor(client, metadata, timeoutMs) {
2787
2993
  this.client = client;
2788
2994
  this.metadata = metadata;
2995
+ this.timeoutMs = timeoutMs;
2789
2996
  }
2790
2997
  /**
2791
2998
  * Enqueue a new job
2792
2999
  */
2793
3000
  async enqueue(params) {
2794
- 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
+ );
2795
3008
  }
2796
3009
  /**
2797
3010
  * Dequeue a job (for workers)
2798
3011
  */
2799
3012
  async dequeue(params) {
2800
- 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
+ );
2801
3020
  return { ...response, jobs: response.jobs.map(decodeJob) };
2802
3021
  }
2803
3022
  /**
2804
3023
  * Complete a job successfully
2805
3024
  */
2806
3025
  async complete(params) {
2807
- 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
+ );
2808
3033
  }
2809
3034
  /**
2810
3035
  * Fail a job
2811
3036
  */
2812
3037
  async fail(params) {
2813
- 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
+ );
2814
3045
  }
2815
3046
  /**
2816
3047
  * Renew a job's lease
2817
3048
  */
2818
3049
  async renewLease(params) {
2819
- 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
+ );
2820
3057
  }
2821
3058
  /**
2822
3059
  * Get a job by ID
2823
3060
  */
2824
3061
  async getJob(jobId) {
2825
- const response = await promisify(this.client, this.client.GetJob, { jobId }, this.metadata);
2826
- 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
+ };
2827
3073
  }
2828
3074
  /**
2829
3075
  * Get queue statistics
2830
3076
  */
2831
3077
  async getQueueStats(queueName) {
2832
- 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
+ );
2833
3085
  }
2834
3086
  /**
2835
3087
  * Stream jobs from a queue (server-side streaming)
@@ -2877,27 +3129,46 @@ var GrpcQueueOperations = class {
2877
3129
  }
2878
3130
  };
2879
3131
  var GrpcWorkerOperations = class {
2880
- constructor(client, metadata) {
3132
+ constructor(client, metadata, timeoutMs) {
2881
3133
  this.client = client;
2882
3134
  this.metadata = metadata;
3135
+ this.timeoutMs = timeoutMs;
2883
3136
  }
2884
3137
  /**
2885
3138
  * Register a new worker
2886
3139
  */
2887
3140
  async register(params) {
2888
- 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
+ );
2889
3148
  }
2890
3149
  /**
2891
3150
  * Send heartbeat
2892
3151
  */
2893
3152
  async heartbeat(params) {
2894
- 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
+ );
2895
3160
  }
2896
3161
  /**
2897
3162
  * Deregister a worker
2898
3163
  */
2899
3164
  async deregister(workerId) {
2900
- 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
+ );
2901
3172
  }
2902
3173
  };
2903
3174
  var SpooledGrpcClient = class {
@@ -2909,7 +3180,7 @@ var SpooledGrpcClient = class {
2909
3180
  /** Worker operations */
2910
3181
  workers;
2911
3182
  constructor(options) {
2912
- const { address, apiKey, useTls, credentials: credentials2, channelOptions } = options;
3183
+ const { address, apiKey, useTls, credentials: credentials2, channelOptions, timeout } = options;
2913
3184
  const creds = credentials2 ?? (shouldUseTls(address, useTls) ? grpc2.credentials.createSsl() : grpc2.credentials.createInsecure());
2914
3185
  this.metadata = new grpc2.Metadata();
2915
3186
  this.metadata.add("x-api-key", apiKey);
@@ -2924,8 +3195,16 @@ var SpooledGrpcClient = class {
2924
3195
  creds,
2925
3196
  channelOptions
2926
3197
  );
2927
- this.queue = new GrpcQueueOperations(this.queueClient, this.metadata);
2928
- 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
+ );
2929
3208
  }
2930
3209
  /**
2931
3210
  * Close all gRPC connections
@@ -3074,7 +3353,8 @@ var SpooledClient = class _SpooledClient {
3074
3353
  }
3075
3354
  this._grpc = new SpooledGrpcClient({
3076
3355
  address: grpcAddress,
3077
- apiKey
3356
+ apiKey,
3357
+ timeout: this.config.timeout
3078
3358
  });
3079
3359
  }
3080
3360
  return this._grpc;
@@ -3141,7 +3421,9 @@ var SpooledClient = class _SpooledClient {
3141
3421
  }
3142
3422
  return this.loginForJwt();
3143
3423
  }
3144
- throw new AuthenticationError("No authentication method available for realtime connection");
3424
+ throw new AuthenticationError(
3425
+ "No authentication method available for realtime connection"
3426
+ );
3145
3427
  }
3146
3428
  /**
3147
3429
  * Exchange the API key for a JWT via /auth/login and cache the result.
@@ -3438,7 +3720,10 @@ var SpooledWorker = class {
3438
3720
  this.sendWorkerHeartbeat();
3439
3721
  }, heartbeatInterval);
3440
3722
  this.state = "running";
3441
- this.emit("started", { workerId: this.workerId, queueName: this.options.queueName });
3723
+ this.emit("started", {
3724
+ workerId: this.workerId,
3725
+ queueName: this.options.queueName
3726
+ });
3442
3727
  this.schedulePoll();
3443
3728
  } catch (error) {
3444
3729
  this.state = "error";
@@ -3474,14 +3759,18 @@ var SpooledWorker = class {
3474
3759
  active.abortController.abort();
3475
3760
  }
3476
3761
  if (this.activeJobs.size > 0) {
3477
- this.debug(`Waiting for ${this.activeJobs.size} active jobs to complete...`);
3762
+ this.debug(
3763
+ `Waiting for ${this.activeJobs.size} active jobs to complete...`
3764
+ );
3478
3765
  await Promise.race([
3479
3766
  this.waitForActiveJobs(),
3480
3767
  this.sleep(this.options.shutdownTimeout)
3481
3768
  ]);
3482
3769
  const remaining = Array.from(this.activeJobs.values());
3483
3770
  for (const active of remaining) {
3484
- this.debug(`Force-failing job ${active.job.id} due to shutdown timeout`);
3771
+ this.debug(
3772
+ `Force-failing job ${active.job.id} due to shutdown timeout`
3773
+ );
3485
3774
  await this.failJob(active.job, "Worker shutdown timeout");
3486
3775
  this.cleanupJob(active);
3487
3776
  }
@@ -3589,7 +3878,9 @@ var SpooledWorker = class {
3589
3878
  retryCount: job.retryCount,
3590
3879
  maxRetries: job.maxRetries,
3591
3880
  signal,
3592
- progress: async (_percent, _message) => {
3881
+ progress: async (percent, message) => {
3882
+ const boundedPercent = Math.max(0, Math.min(100, percent));
3883
+ this.debug(`[${job.id}] progress ${boundedPercent}%`, message);
3593
3884
  },
3594
3885
  log: (level, message, meta) => {
3595
3886
  this.debug(`[${job.id}] [${level}] ${message}`, meta);
@@ -3692,6 +3983,6 @@ var SpooledWorker = class {
3692
3983
  }
3693
3984
  };
3694
3985
 
3695
- export { API_VERSION, AdminResource, ApiKeysResource, AuthResource, AuthenticationError, AuthorizationError, BillingResource, CircuitBreaker, CircuitBreakerOpenError, CircuitState, ConflictError, DEFAULT_CONFIG, DashboardResource, GrpcJobStatus, GrpcJobStatusNumber, GrpcQueueOperations, GrpcWorkerOperations, HealthResource, HttpClient, JobsResource, MetricsResource, NetworkError, NotFoundError, OrganizationsResource, PROTO_LOADER_OPTIONS, PayloadTooLargeError, QueuesResource, RateLimitError, SDK_VERSION, SchedulesResource, ServerError, SpooledClient, SpooledError, SpooledGrpcClient, SpooledRealtime, SpooledWorker, SseRealtimeClient, TimeoutError, ValidationError, WebSocketRealtimeClient, WebhookIngestionResource, WebhooksResource, WorkersResource, WorkflowsResource, asyncIterableFromStream, calculateDelay, camelToSnake, clearProtoCache, convertQueryParams, convertRequest, convertResponse, createCircuitBreaker, createClient, createErrorFromResponse, createHttpClient, createJobStream, createPaginatedResponse, createProcessJobsStream, createRetryWrapper, dateToTimestamp, isRetryableError, isSpooledError, loadProtoDefinition, loadProtoDefinitionAsync, parseRateLimitHeaders, resolveConfig, shouldRetry, sleep, snakeToCamel, timestampToDate, toCamelCase, toSnakeCase, validateConfig, withRetry };
3986
+ export { API_VERSION, AdminResource, ApiKeysResource, AuthResource, AuthenticationError, AuthorizationError, BillingResource, CircuitBreaker, CircuitBreakerOpenError, CircuitState, ConflictError, DEFAULT_CONFIG, DashboardResource, GrpcJobStatus, GrpcJobStatusNumber, GrpcQueueOperations, GrpcWorkerOperations, HealthResource, HttpClient, JobsResource, MetricsResource, NetworkError, NotFoundError, OrganizationsResource, PROTO_LOADER_OPTIONS, PayloadTooLargeError, QueuesResource, RateLimitError, SDK_VERSION, SchedulesResource, ServerError, SpooledClient, SpooledError, SpooledGrpcClient, SpooledRealtime, SpooledWorker, SseRealtimeClient, TimeoutError, ValidationError, WebSocketRealtimeClient, WebhookIngestionResource, WebhooksResource, WorkersResource, WorkflowsResource, asyncIterableFromStream, calculateDelay, camelToSnake, clearProtoCache, convertQueryParams, convertRequest, convertResponse, createCircuitBreaker, createClient, createErrorFromResponse, createHttpClient, createJobStream, createPaginatedResponse, createProcessJobsStream, createRetryWrapper, dateToTimestamp, getProtoPath, isRetryableError, isSpooledError, loadProtoDefinition, loadProtoDefinitionAsync, parseRateLimitHeaders, resolveConfig, shouldRetry, sleep, snakeToCamel, timestampToDate, toCamelCase, toSnakeCase, validateConfig, withRetry };
3696
3987
  //# sourceMappingURL=index.js.map
3697
3988
  //# sourceMappingURL=index.js.map