@spooled/sdk 1.3.0 → 1.4.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
@@ -24,10 +24,10 @@ var DEFAULT_CONFIG = {
24
24
  successThreshold: 3,
25
25
  timeout: 3e4
26
26
  },
27
- userAgent: "@spooled/sdk-nodejs/1.3.0",
27
+ userAgent: "@spooled/sdk-nodejs/1.4.0",
28
28
  autoRefreshToken: true
29
29
  };
30
- var SDK_VERSION = "1.3.0";
30
+ var SDK_VERSION = "1.4.0";
31
31
  var API_VERSION = "v1";
32
32
  var API_BASE_PATH = `/api/${API_VERSION}`;
33
33
  function normalizeCredential(value) {
@@ -340,6 +340,10 @@ function parseRateLimitHeaders(headers) {
340
340
  info.reset = new Date(timestamp * 1e3);
341
341
  }
342
342
  }
343
+ const scope = headers.get("X-RateLimit-Scope");
344
+ if (scope) {
345
+ info.scope = scope.trim();
346
+ }
343
347
  return info;
344
348
  }
345
349
  var MAX_RAW_ERROR_BODY_CHARS = 500;
@@ -619,6 +623,8 @@ var HttpClient = class {
619
623
  * refresh and fail even though the token was about to be replaced.
620
624
  */
621
625
  refreshInFlight = null;
626
+ /** Rate-limit headers of the most recent response that carried them */
627
+ lastRateLimit;
622
628
  constructor(config, circuitBreaker) {
623
629
  this.config = config;
624
630
  this.circuitBreaker = circuitBreaker;
@@ -631,6 +637,14 @@ var HttpClient = class {
631
637
  setAuthToken(token) {
632
638
  this.authToken = token;
633
639
  }
640
+ /**
641
+ * The `X-RateLimit-*` (and `Retry-After`) values of the most recent
642
+ * response that carried them, successful or not. `undefined` until such a
643
+ * response arrives. With concurrent requests it is the last one to finish.
644
+ */
645
+ getLastRateLimitInfo() {
646
+ return this.lastRateLimit ? { ...this.lastRateLimit } : void 0;
647
+ }
634
648
  /**
635
649
  * Set the token refresh function.
636
650
  *
@@ -777,6 +791,7 @@ var HttpClient = class {
777
791
  );
778
792
  }
779
793
  this.debug?.(`Response: ${response.status}`, { url });
794
+ this.recordRateLimit(response.headers);
780
795
  if (!response.ok) {
781
796
  if (response.status === 401 && this.refreshTokenFn && !hasRefreshed && !options.skipAuthRefresh) {
782
797
  const alreadyRefreshed = this.authToken !== tokenUsed;
@@ -803,6 +818,13 @@ var HttpClient = class {
803
818
  data
804
819
  };
805
820
  }
821
+ /** Remember the rate-limit headers of a response that has them. */
822
+ recordRateLimit(headers) {
823
+ if (!headers || typeof headers.get !== "function" || headers.get("X-RateLimit-Limit") === null && headers.get("X-RateLimit-Remaining") === null) {
824
+ return;
825
+ }
826
+ this.lastRateLimit = parseRateLimitHeaders(headers);
827
+ }
806
828
  /**
807
829
  * Make an HTTP request with retry and circuit breaker
808
830
  */
@@ -930,6 +952,12 @@ var CircuitState = /* @__PURE__ */ ((CircuitState2) => {
930
952
  CircuitState2["HALF_OPEN"] = "HALF_OPEN";
931
953
  return CircuitState2;
932
954
  })(CircuitState || {});
955
+ function isCircuitBreakerFailure(error) {
956
+ if (error instanceof RateLimitError) {
957
+ return false;
958
+ }
959
+ return isRetryableError(error);
960
+ }
933
961
  var CircuitBreaker = class {
934
962
  state = "CLOSED" /* CLOSED */;
935
963
  failureCount = 0;
@@ -990,7 +1018,7 @@ var CircuitBreaker = class {
990
1018
  if (!this.config.enabled) {
991
1019
  return;
992
1020
  }
993
- const shouldCount = this.config.isFailure ? this.config.isFailure(error) : isRetryableError(error);
1021
+ const shouldCount = this.config.isFailure ? this.config.isFailure(error) : isCircuitBreakerFailure(error);
994
1022
  if (!shouldCount) {
995
1023
  return;
996
1024
  }
@@ -1188,12 +1216,31 @@ function coerceFailureMessage(message) {
1188
1216
  return codePoints.length <= MAX_FAILURE_MESSAGE_CHARS ? text : codePoints.slice(0, MAX_FAILURE_MESSAGE_CHARS).join("");
1189
1217
  }
1190
1218
 
1219
+ // src/utils/paging.ts
1220
+ var HAS_MORE_HEADER = "X-Has-More";
1221
+ function hasMoreFromHeaders(headers, count, limit, defaultLimit, maxLimit) {
1222
+ const header = headers.get(HAS_MORE_HEADER);
1223
+ if (header !== null) {
1224
+ return header.trim().toLowerCase() === "true";
1225
+ }
1226
+ const applied = Math.min(Math.max(limit ?? defaultLimit, 1), maxLimit);
1227
+ return count >= applied;
1228
+ }
1229
+ function toQueryTimestamp(value) {
1230
+ return value instanceof Date ? value.toISOString() : value;
1231
+ }
1232
+
1191
1233
  // src/resources/jobs.ts
1234
+ var JOB_LIST_DEFAULT_LIMIT = 50;
1235
+ var JOB_LIST_MAX_LIMIT = 100;
1236
+ var JOB_HISTORY_DEFAULT_LIMIT = 100;
1237
+ var JOB_HISTORY_MAX_LIMIT = 500;
1192
1238
  var JobsResource = class {
1193
1239
  constructor(http) {
1194
1240
  this.http = http;
1195
1241
  this.dlq = {
1196
1242
  list: this.listDlq.bind(this),
1243
+ listPage: this.listDlqPage.bind(this),
1197
1244
  retry: this.retryDlq.bind(this),
1198
1245
  purge: this.purgeDlq.bind(this)
1199
1246
  };
@@ -1217,15 +1264,36 @@ var JobsResource = class {
1217
1264
  }
1218
1265
  /**
1219
1266
  * List jobs with optional filtering
1267
+ *
1268
+ * `status` takes one status or several, and `q`, `jobType`, `createdAfter`
1269
+ * and `createdBefore` filter on the server (API 0.1.122+). Use
1270
+ * {@link JobsResource.listPage} to also learn whether another page follows.
1220
1271
  */
1221
1272
  async list(params) {
1222
- const rows = await this.http.get("/jobs", {
1223
- params
1224
- });
1225
- return rows.map((row) => ({
1226
- ...row,
1227
- jobType: row.jobType ?? jobTypeFromPayload(row)
1228
- }));
1273
+ return (await this.listPage(params)).data;
1274
+ }
1275
+ /**
1276
+ * List one page of jobs with `hasMore` from the `X-Has-More` header
1277
+ * (API 0.1.122+). Takes the same filters as {@link JobsResource.list}.
1278
+ *
1279
+ * @example
1280
+ * ```typescript
1281
+ * let offset = 0;
1282
+ * for (;;) {
1283
+ * const page = await client.jobs.listPage({
1284
+ * status: ["failed", "deadletter"],
1285
+ * createdAfter: new Date(Date.now() - 86_400_000),
1286
+ * limit: 100,
1287
+ * offset,
1288
+ * });
1289
+ * handle(page.data);
1290
+ * if (!page.hasMore) break;
1291
+ * offset += page.data.length;
1292
+ * }
1293
+ * ```
1294
+ */
1295
+ async listPage(params) {
1296
+ return this.listSummaries("/jobs", params);
1229
1297
  }
1230
1298
  /**
1231
1299
  * Get a job by ID
@@ -1255,6 +1323,46 @@ var JobsResource = class {
1255
1323
  priority
1256
1324
  });
1257
1325
  }
1326
+ /**
1327
+ * Get the recorded lifecycle events of a job (`GET /jobs/{id}/history`,
1328
+ * API 0.1.122+), oldest first unless `order: "desc"`.
1329
+ *
1330
+ * The history is sparse: the server records REST claims (`processing`),
1331
+ * completions (`completed`) and failures (`retry_scheduled`,
1332
+ * `deadlettered`) and the scheduler's dead-letter sweeps, so a job settled
1333
+ * over gRPC may have few or no events. An unknown job is a `NotFoundError`.
1334
+ */
1335
+ async history(id, params) {
1336
+ return (await this.historyPage(id, params)).data;
1337
+ }
1338
+ /**
1339
+ * One page of {@link JobsResource.history} with `hasMore` from the
1340
+ * `X-Has-More` header. `limit` defaults to 100 (at most 500).
1341
+ */
1342
+ async historyPage(id, params) {
1343
+ const response = await this.http.request(
1344
+ `/jobs/${id}/history`,
1345
+ {
1346
+ method: "GET",
1347
+ params: {
1348
+ order: params?.order,
1349
+ limit: params?.limit,
1350
+ offset: params?.offset
1351
+ }
1352
+ }
1353
+ );
1354
+ const data = response.data ?? [];
1355
+ return {
1356
+ data,
1357
+ hasMore: hasMoreFromHeaders(
1358
+ response.headers,
1359
+ data.length,
1360
+ params?.limit,
1361
+ JOB_HISTORY_DEFAULT_LIMIT,
1362
+ JOB_HISTORY_MAX_LIMIT
1363
+ )
1364
+ };
1365
+ }
1258
1366
  /**
1259
1367
  * Get job statistics
1260
1368
  */
@@ -1331,13 +1439,30 @@ var JobsResource = class {
1331
1439
  }
1332
1440
  // DLQ operations (private implementations)
1333
1441
  async listDlq(params) {
1334
- const rows = await this.http.get("/jobs/dlq", {
1335
- params
1442
+ return (await this.listDlqPage(params)).data;
1443
+ }
1444
+ async listDlqPage(params) {
1445
+ return this.listSummaries("/jobs/dlq", params);
1446
+ }
1447
+ async listSummaries(path, params) {
1448
+ const response = await this.http.request(path, {
1449
+ method: "GET",
1450
+ params: jobListQuery(params)
1336
1451
  });
1337
- return rows.map((row) => ({
1338
- ...row,
1339
- jobType: row.jobType ?? jobTypeFromPayload(row)
1340
- }));
1452
+ const rows = response.data ?? [];
1453
+ return {
1454
+ data: rows.map((row) => ({
1455
+ ...row,
1456
+ jobType: row.jobType ?? jobTypeFromPayload(row)
1457
+ })),
1458
+ hasMore: hasMoreFromHeaders(
1459
+ response.headers,
1460
+ rows.length,
1461
+ params?.limit,
1462
+ JOB_LIST_DEFAULT_LIMIT,
1463
+ JOB_LIST_MAX_LIMIT
1464
+ )
1465
+ };
1341
1466
  }
1342
1467
  async retryDlq(params) {
1343
1468
  return this.http.post("/jobs/dlq/retry", params);
@@ -1346,6 +1471,24 @@ var JobsResource = class {
1346
1471
  return this.http.post("/jobs/dlq/purge", params);
1347
1472
  }
1348
1473
  };
1474
+ function jobListQuery(params) {
1475
+ if (!params) {
1476
+ return void 0;
1477
+ }
1478
+ const { status: status2, createdAfter, createdBefore, ...rest } = params;
1479
+ let statusParam;
1480
+ if (typeof status2 === "string") {
1481
+ statusParam = status2;
1482
+ } else if (status2 && status2.length > 0) {
1483
+ statusParam = status2.join(",");
1484
+ }
1485
+ return {
1486
+ ...rest,
1487
+ status: statusParam,
1488
+ createdAfter: toQueryTimestamp(createdAfter),
1489
+ createdBefore: toQueryTimestamp(createdBefore)
1490
+ };
1491
+ }
1349
1492
  function withJobType(job) {
1350
1493
  return {
1351
1494
  ...job,
@@ -2169,6 +2312,31 @@ var WebhookIngestionResource = class {
2169
2312
  status: raw.status
2170
2313
  };
2171
2314
  }
2315
+ /**
2316
+ * The inbound webhook log: accepted requests to
2317
+ * `POST /webhooks/{org_id}/custom`, newest first
2318
+ * (`GET /webhooks/deliveries`, API 0.1.122+).
2319
+ *
2320
+ * Needs an API key without a queue restriction (a queue-scoped key gets a
2321
+ * 403 `AuthorizationError`). Entries carry no payload and no signature;
2322
+ * requests that were rejected are not logged. `limit` defaults to 50 (at
2323
+ * most 100); an invalid filter is a 400 `ValidationError`.
2324
+ */
2325
+ async listDeliveries(params) {
2326
+ const rows = await this.http.get(
2327
+ "/webhooks/deliveries",
2328
+ {
2329
+ params: {
2330
+ status: params?.status,
2331
+ since: toQueryTimestamp(params?.since),
2332
+ queueName: params?.queueName,
2333
+ limit: params?.limit,
2334
+ offset: params?.offset
2335
+ }
2336
+ }
2337
+ );
2338
+ return rows ?? [];
2339
+ }
2172
2340
  };
2173
2341
 
2174
2342
  // src/realtime/event-map.ts
@@ -3006,6 +3174,120 @@ function clearProtoCache() {
3006
3174
  function encodeFailRequest(params) {
3007
3175
  return { ...params, retry: params.retry ?? true };
3008
3176
  }
3177
+ function encodeStruct(value) {
3178
+ if (value == null) {
3179
+ return void 0;
3180
+ }
3181
+ return {
3182
+ fields: Object.fromEntries(
3183
+ Object.entries(value).map(([key, entry]) => [key, encodeValue(entry)])
3184
+ )
3185
+ };
3186
+ }
3187
+ function encodeValue(value) {
3188
+ if (value == null) {
3189
+ return { nullValue: 0 };
3190
+ }
3191
+ if (Array.isArray(value)) {
3192
+ return { listValue: { values: value.map(encodeValue) } };
3193
+ }
3194
+ switch (typeof value) {
3195
+ case "number":
3196
+ return { numberValue: value };
3197
+ case "string":
3198
+ return { stringValue: value };
3199
+ case "boolean":
3200
+ return { boolValue: value };
3201
+ case "object":
3202
+ return { structValue: encodeStruct(value) };
3203
+ default:
3204
+ return { stringValue: String(value) };
3205
+ }
3206
+ }
3207
+ function decodeStruct(value) {
3208
+ if (!value || typeof value !== "object" || !("fields" in value)) {
3209
+ return value;
3210
+ }
3211
+ const fields = value.fields ?? {};
3212
+ return Object.fromEntries(
3213
+ Object.entries(fields).map(([key, entry]) => [key, decodeValue(entry)])
3214
+ );
3215
+ }
3216
+ function decodeValue(value) {
3217
+ if ("nullValue" in value) {
3218
+ return null;
3219
+ }
3220
+ if ("numberValue" in value) {
3221
+ return value.numberValue;
3222
+ }
3223
+ if ("stringValue" in value) {
3224
+ return value.stringValue;
3225
+ }
3226
+ if ("boolValue" in value) {
3227
+ return value.boolValue;
3228
+ }
3229
+ if ("structValue" in value) {
3230
+ return decodeStruct(value.structValue);
3231
+ }
3232
+ if ("listValue" in value) {
3233
+ return (value.listValue.values ?? []).map(decodeValue);
3234
+ }
3235
+ return void 0;
3236
+ }
3237
+ function encodeEnqueueRequest(params) {
3238
+ const encoded = {
3239
+ queueName: params.queueName,
3240
+ payload: encodeStruct(params.payload)
3241
+ };
3242
+ if (params.priority !== void 0) {
3243
+ encoded.priority = params.priority;
3244
+ }
3245
+ if (params.maxRetries !== void 0) {
3246
+ encoded.maxRetries = params.maxRetries;
3247
+ }
3248
+ if (params.timeoutSeconds !== void 0) {
3249
+ encoded.timeoutSeconds = params.timeoutSeconds;
3250
+ }
3251
+ if (params.idempotencyKey !== void 0 && params.idempotencyKey !== "") {
3252
+ encoded.idempotencyKey = params.idempotencyKey;
3253
+ }
3254
+ if (params.scheduledAt !== void 0) {
3255
+ encoded.scheduledAt = params.scheduledAt;
3256
+ }
3257
+ if (params.tags !== void 0) {
3258
+ encoded.tags = params.tags;
3259
+ }
3260
+ return encoded;
3261
+ }
3262
+ function encodeCompleteRequest(params) {
3263
+ return {
3264
+ ...params,
3265
+ result: encodeStruct(params.result)
3266
+ };
3267
+ }
3268
+ function decodeJob(job) {
3269
+ return {
3270
+ ...job,
3271
+ // proto-loader keeps an enum number it does not know (a status added to
3272
+ // the server's proto after this SDK) as a number; keep it a string so
3273
+ // `status` always matches its type.
3274
+ status: typeof job.status === "number" ? String(job.status) : job.status,
3275
+ payload: decodeStruct(job.payload),
3276
+ result: decodeStruct(job.result)
3277
+ };
3278
+ }
3279
+ function encodeProcessRequest(request) {
3280
+ if (request.fail) {
3281
+ return { ...request, fail: encodeFailRequest(request.fail) };
3282
+ }
3283
+ if (request.complete) {
3284
+ return { ...request, complete: encodeCompleteRequest(request.complete) };
3285
+ }
3286
+ return request;
3287
+ }
3288
+ function decodeProcessResponse(response) {
3289
+ return response.job ? { ...response, job: decodeJob(response.job) } : response;
3290
+ }
3009
3291
 
3010
3292
  // src/grpc/streaming.ts
3011
3293
  async function* asyncIterableFromStream(stream, options) {
@@ -3024,21 +3306,39 @@ async function* asyncIterableFromStream(stream, options) {
3024
3306
  var AsyncIterableStream = class {
3025
3307
  stream;
3026
3308
  options;
3027
- constructor(stream, options = {}) {
3309
+ decode;
3310
+ constructor(stream, options = {}, decode = (item) => item) {
3028
3311
  this.stream = stream;
3029
3312
  this.options = options;
3313
+ this.decode = decode;
3030
3314
  }
3031
3315
  async *[Symbol.asyncIterator]() {
3032
3316
  const { onConnected, onError, onEnd } = this.options;
3033
3317
  const queue = [];
3034
3318
  let error = null;
3035
3319
  let ended = false;
3320
+ let decodeFailed = false;
3036
3321
  let resolve = null;
3037
3322
  this.stream.on("data", (data) => {
3038
- queue.push(data);
3323
+ if (decodeFailed) {
3324
+ return;
3325
+ }
3326
+ try {
3327
+ queue.push(this.decode(data));
3328
+ } catch (decodeError) {
3329
+ decodeFailed = true;
3330
+ error = decodeError instanceof Error ? decodeError : new Error(String(decodeError));
3331
+ try {
3332
+ this.stream.cancel?.();
3333
+ } catch {
3334
+ }
3335
+ }
3039
3336
  resolve?.();
3040
3337
  });
3041
3338
  this.stream.on("error", (err) => {
3339
+ if (decodeFailed) {
3340
+ return;
3341
+ }
3042
3342
  error = err;
3043
3343
  onError?.(err);
3044
3344
  resolve?.();
@@ -3079,12 +3379,14 @@ function createProcessJobsStream(call, options) {
3079
3379
  }
3080
3380
  return {
3081
3381
  send(request) {
3082
- call.write(
3083
- request.fail ? { ...request, fail: encodeFailRequest(request.fail) } : request
3084
- );
3382
+ call.write(encodeProcessRequest(request));
3085
3383
  },
3086
3384
  receive() {
3087
- return new AsyncIterableStream(call, { onError, onEnd });
3385
+ return new AsyncIterableStream(
3386
+ call,
3387
+ { onError, onEnd },
3388
+ decodeProcessResponse
3389
+ );
3088
3390
  },
3089
3391
  end() {
3090
3392
  call.end();
@@ -3101,11 +3403,11 @@ function createJobStream(call, options) {
3101
3403
  call.cancel();
3102
3404
  });
3103
3405
  }
3104
- const iterable = new AsyncIterableStream(call, {
3105
- onConnected,
3106
- onError,
3107
- onEnd
3108
- });
3406
+ const iterable = new AsyncIterableStream(
3407
+ call,
3408
+ { onConnected, onError, onEnd },
3409
+ decodeJob
3410
+ );
3109
3411
  return {
3110
3412
  [Symbol.asyncIterator]() {
3111
3413
  return iterable[Symbol.asyncIterator]();
@@ -3117,104 +3419,6 @@ function createJobStream(call, options) {
3117
3419
  }
3118
3420
 
3119
3421
  // src/grpc/client.ts
3120
- function encodeStruct(value) {
3121
- if (value == null) {
3122
- return void 0;
3123
- }
3124
- return {
3125
- fields: Object.fromEntries(
3126
- Object.entries(value).map(([key, entry]) => [key, encodeValue(entry)])
3127
- )
3128
- };
3129
- }
3130
- function encodeValue(value) {
3131
- if (value == null) {
3132
- return { nullValue: 0 };
3133
- }
3134
- if (Array.isArray(value)) {
3135
- return { listValue: { values: value.map(encodeValue) } };
3136
- }
3137
- switch (typeof value) {
3138
- case "number":
3139
- return { numberValue: value };
3140
- case "string":
3141
- return { stringValue: value };
3142
- case "boolean":
3143
- return { boolValue: value };
3144
- case "object":
3145
- return { structValue: encodeStruct(value) };
3146
- default:
3147
- return { stringValue: String(value) };
3148
- }
3149
- }
3150
- function decodeStruct(value) {
3151
- if (!value || typeof value !== "object" || !("fields" in value)) {
3152
- return value;
3153
- }
3154
- const fields = value.fields ?? {};
3155
- return Object.fromEntries(
3156
- Object.entries(fields).map(([key, entry]) => [key, decodeValue(entry)])
3157
- );
3158
- }
3159
- function decodeValue(value) {
3160
- if ("nullValue" in value) {
3161
- return null;
3162
- }
3163
- if ("numberValue" in value) {
3164
- return value.numberValue;
3165
- }
3166
- if ("stringValue" in value) {
3167
- return value.stringValue;
3168
- }
3169
- if ("boolValue" in value) {
3170
- return value.boolValue;
3171
- }
3172
- if ("structValue" in value) {
3173
- return decodeStruct(value.structValue);
3174
- }
3175
- if ("listValue" in value) {
3176
- return (value.listValue.values ?? []).map(decodeValue);
3177
- }
3178
- return void 0;
3179
- }
3180
- function encodeEnqueueRequest(params) {
3181
- const encoded = {
3182
- queueName: params.queueName,
3183
- payload: encodeStruct(params.payload)
3184
- };
3185
- if (params.priority !== void 0) {
3186
- encoded.priority = params.priority;
3187
- }
3188
- if (params.maxRetries !== void 0) {
3189
- encoded.maxRetries = params.maxRetries;
3190
- }
3191
- if (params.timeoutSeconds !== void 0) {
3192
- encoded.timeoutSeconds = params.timeoutSeconds;
3193
- }
3194
- if (params.idempotencyKey !== void 0 && params.idempotencyKey !== "") {
3195
- encoded.idempotencyKey = params.idempotencyKey;
3196
- }
3197
- if (params.scheduledAt !== void 0) {
3198
- encoded.scheduledAt = params.scheduledAt;
3199
- }
3200
- if (params.tags !== void 0) {
3201
- encoded.tags = params.tags;
3202
- }
3203
- return encoded;
3204
- }
3205
- function encodeCompleteRequest(params) {
3206
- return {
3207
- ...params,
3208
- result: encodeStruct(params.result)
3209
- };
3210
- }
3211
- function decodeJob(job) {
3212
- return {
3213
- ...job,
3214
- payload: decodeStruct(job.payload),
3215
- result: decodeStruct(job.result)
3216
- };
3217
- }
3218
3422
  function promisify(client, method, request, metadata, timeoutMs) {
3219
3423
  return new Promise((resolve, reject) => {
3220
3424
  const callback = (error, response) => {
@@ -3794,6 +3998,17 @@ var SpooledClient = class _SpooledClient {
3794
3998
  getConfig() {
3795
3999
  return this.config;
3796
4000
  }
4001
+ /**
4002
+ * Rate-limit state from the most recent response that carried
4003
+ * `X-RateLimit-*` headers (API 0.1.122+): `limit`, `remaining`, `reset`
4004
+ * (from the Unix-seconds header), `scope` and, after a 429, `retryAfter`.
4005
+ * `undefined` until such a response arrives, and for servers or routes that
4006
+ * do not send the headers. A 429 also carries the same values on
4007
+ * `RateLimitError.rateLimitInfo`.
4008
+ */
4009
+ getRateLimitInfo() {
4010
+ return this.http.getLastRateLimitInfo();
4011
+ }
3797
4012
  /**
3798
4013
  * Get circuit breaker statistics
3799
4014
  */
@@ -4392,6 +4607,6 @@ var SpooledWorker = class {
4392
4607
  }
4393
4608
  };
4394
4609
 
4395
- 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, UnsupportedOperationError, 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 };
4610
+ 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, UnsupportedOperationError, ValidationError, WebSocketRealtimeClient, WebhookIngestionResource, WebhooksResource, WorkersResource, WorkflowsResource, asyncIterableFromStream, calculateDelay, camelToSnake, clearProtoCache, convertQueryParams, convertRequest, convertResponse, createCircuitBreaker, createClient, createErrorFromResponse, createHttpClient, createJobStream, createPaginatedResponse, createProcessJobsStream, createRetryWrapper, dateToTimestamp, getProtoPath, isCircuitBreakerFailure, isRetryableError, isSpooledError, loadProtoDefinition, loadProtoDefinitionAsync, parseRateLimitHeaders, resolveConfig, shouldRetry, sleep, snakeToCamel, timestampToDate, toCamelCase, toSnakeCase, validateConfig, withRetry };
4396
4611
  //# sourceMappingURL=index.js.map
4397
4612
  //# sourceMappingURL=index.js.map