@spooled/sdk 1.2.1 → 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/README.md +119 -18
- package/dist/{index-CWVI9LRo.d.cts → index-DzTC8ld3.d.cts} +741 -134
- package/dist/{index-CWVI9LRo.d.ts → index-DzTC8ld3.d.ts} +741 -134
- package/dist/index.cjs +758 -304
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -151
- package/dist/index.d.ts +9 -151
- package/dist/index.js +757 -305
- package/dist/index.js.map +1 -1
- package/dist/worker/index.cjs +164 -45
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +164 -45
- package/dist/worker/index.js.map +1 -1
- package/package.json +4 -3
- package/proto/spooled.proto +19 -1
|
@@ -1,10 +1,124 @@
|
|
|
1
1
|
import * as grpc from '@grpc/grpc-js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Circuit Breaker Utility
|
|
5
|
+
*
|
|
6
|
+
* Implements the circuit breaker pattern to prevent cascading failures.
|
|
7
|
+
* States: CLOSED (normal) -> OPEN (failing) -> HALF_OPEN (testing) -> CLOSED
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Circuit breaker states */
|
|
11
|
+
declare enum CircuitState {
|
|
12
|
+
/** Normal operation - requests flow through */
|
|
13
|
+
CLOSED = "CLOSED",
|
|
14
|
+
/** Circuit is open - requests are rejected immediately */
|
|
15
|
+
OPEN = "OPEN",
|
|
16
|
+
/** Testing state - limited requests allowed to test recovery */
|
|
17
|
+
HALF_OPEN = "HALF_OPEN"
|
|
18
|
+
}
|
|
19
|
+
/** Circuit breaker state change event */
|
|
20
|
+
interface CircuitStateChange {
|
|
21
|
+
from: CircuitState;
|
|
22
|
+
to: CircuitState;
|
|
23
|
+
timestamp: Date;
|
|
24
|
+
failureCount: number;
|
|
25
|
+
}
|
|
26
|
+
/** Circuit breaker options */
|
|
27
|
+
interface CircuitBreakerOptions extends CircuitBreakerConfig {
|
|
28
|
+
/** Callback when state changes */
|
|
29
|
+
onStateChange?: (event: CircuitStateChange) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Custom function to determine if an error should count as a failure.
|
|
32
|
+
* Defaults to {@link isCircuitBreakerFailure}.
|
|
33
|
+
*/
|
|
34
|
+
isFailure?: (error: Error) => boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Default circuit breaker failure predicate.
|
|
38
|
+
*
|
|
39
|
+
* Counts the errors that say the API or the network is unhealthy: the
|
|
40
|
+
* retryable ones (network errors, timeouts, 5xx, 408). A 429 never counts. A
|
|
41
|
+
* rate-limit 429 is the API working as designed and telling this client to
|
|
42
|
+
* slow down for `Retry-After` seconds; counting it let a burst above the plan
|
|
43
|
+
* limit open the breaker and fail every call on the client for the breaker
|
|
44
|
+
* timeout (30 s by default), including the retries that `Retry-After` had
|
|
45
|
+
* already scheduled. The retry layer handles rate limiting on its own. A quota
|
|
46
|
+
* 429 (`RateLimitError.isQuota`) was already excluded.
|
|
47
|
+
*/
|
|
48
|
+
declare function isCircuitBreakerFailure(error: Error): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Circuit Breaker implementation
|
|
51
|
+
*
|
|
52
|
+
* Tracks failures and prevents requests when the failure threshold is reached.
|
|
53
|
+
*/
|
|
54
|
+
declare class CircuitBreaker {
|
|
55
|
+
private state;
|
|
56
|
+
private failureCount;
|
|
57
|
+
private successCount;
|
|
58
|
+
private lastFailureTime;
|
|
59
|
+
private readonly config;
|
|
60
|
+
constructor(config: CircuitBreakerOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Get current circuit state
|
|
63
|
+
*/
|
|
64
|
+
getState(): CircuitState;
|
|
65
|
+
/**
|
|
66
|
+
* Check if circuit breaker is enabled
|
|
67
|
+
*/
|
|
68
|
+
isEnabled(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if requests are currently allowed
|
|
71
|
+
*/
|
|
72
|
+
isAllowed(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Record a successful request
|
|
75
|
+
*/
|
|
76
|
+
recordSuccess(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Record a failed request
|
|
79
|
+
*/
|
|
80
|
+
recordFailure(error: Error): void;
|
|
81
|
+
/**
|
|
82
|
+
* Transition to a new state
|
|
83
|
+
*/
|
|
84
|
+
private transitionTo;
|
|
85
|
+
/**
|
|
86
|
+
* Reset the circuit breaker to closed state
|
|
87
|
+
*/
|
|
88
|
+
reset(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Execute a function with circuit breaker protection
|
|
91
|
+
*
|
|
92
|
+
* @param fn - Async function to execute
|
|
93
|
+
* @returns Promise resolving to the function result
|
|
94
|
+
* @throws CircuitBreakerOpenError if circuit is open
|
|
95
|
+
*/
|
|
96
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
97
|
+
/**
|
|
98
|
+
* Get circuit breaker statistics
|
|
99
|
+
*/
|
|
100
|
+
getStats(): {
|
|
101
|
+
state: CircuitState;
|
|
102
|
+
failureCount: number;
|
|
103
|
+
successCount: number;
|
|
104
|
+
lastFailureTime: Date | null;
|
|
105
|
+
config: CircuitBreakerConfig;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a circuit breaker instance from configuration.
|
|
110
|
+
*
|
|
111
|
+
* Unless the config carries its own `isFailure`, rate-limit 429s do not count
|
|
112
|
+
* as failures (the constructor defaults to {@link isCircuitBreakerFailure}).
|
|
113
|
+
*/
|
|
114
|
+
declare function createCircuitBreaker(config: CircuitBreakerOptions): CircuitBreaker;
|
|
115
|
+
|
|
3
116
|
/**
|
|
4
117
|
* SDK Configuration
|
|
5
118
|
*
|
|
6
119
|
* Defines configuration types and defaults for the Spooled SDK.
|
|
7
120
|
*/
|
|
121
|
+
|
|
8
122
|
/** Retry configuration options */
|
|
9
123
|
interface RetryConfig {
|
|
10
124
|
/** Maximum number of retry attempts (default: 3) */
|
|
@@ -57,8 +171,11 @@ interface SpooledClientConfig {
|
|
|
57
171
|
retryDelay?: number;
|
|
58
172
|
/** Full retry configuration */
|
|
59
173
|
retry?: Partial<RetryConfig>;
|
|
60
|
-
/**
|
|
61
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Circuit breaker configuration. Besides the thresholds it takes
|
|
176
|
+
* `isFailure` (which errors count as failures) and `onStateChange`.
|
|
177
|
+
*/
|
|
178
|
+
circuitBreaker?: Partial<CircuitBreakerOptions>;
|
|
62
179
|
/** Additional headers to include in all requests */
|
|
63
180
|
headers?: Record<string, string>;
|
|
64
181
|
/** Custom fetch implementation (for testing or special runtimes) */
|
|
@@ -81,7 +198,7 @@ interface ResolvedConfig {
|
|
|
81
198
|
grpcAddress: string;
|
|
82
199
|
timeout: number;
|
|
83
200
|
retry: RetryConfig;
|
|
84
|
-
circuitBreaker:
|
|
201
|
+
circuitBreaker: CircuitBreakerOptions;
|
|
85
202
|
headers: Record<string, string>;
|
|
86
203
|
fetch: typeof fetch;
|
|
87
204
|
userAgent: string;
|
|
@@ -107,11 +224,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
224
|
successThreshold: number;
|
|
108
225
|
timeout: number;
|
|
109
226
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.
|
|
227
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.4.0";
|
|
111
228
|
readonly autoRefreshToken: true;
|
|
112
229
|
};
|
|
113
230
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.
|
|
231
|
+
declare const SDK_VERSION = "1.4.0";
|
|
115
232
|
/** API version prefix */
|
|
116
233
|
declare const API_VERSION = "v1";
|
|
117
234
|
/**
|
|
@@ -125,98 +242,206 @@ declare function resolveConfig(options: SpooledClientConfig): ResolvedConfig;
|
|
|
125
242
|
declare function validateConfig(config: ResolvedConfig): void;
|
|
126
243
|
|
|
127
244
|
/**
|
|
128
|
-
*
|
|
245
|
+
* Custom Error Classes
|
|
129
246
|
*
|
|
130
|
-
*
|
|
131
|
-
* States: CLOSED (normal) -> OPEN (failing) -> HALF_OPEN (testing) -> CLOSED
|
|
247
|
+
* Provides a hierarchy of error types for the Spooled SDK.
|
|
132
248
|
*/
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
/** Circuit is open - requests are rejected immediately */
|
|
139
|
-
OPEN = "OPEN",
|
|
140
|
-
/** Testing state - limited requests allowed to test recovery */
|
|
141
|
-
HALF_OPEN = "HALF_OPEN"
|
|
142
|
-
}
|
|
143
|
-
/** Circuit breaker state change event */
|
|
144
|
-
interface CircuitStateChange {
|
|
145
|
-
from: CircuitState;
|
|
146
|
-
to: CircuitState;
|
|
147
|
-
timestamp: Date;
|
|
148
|
-
failureCount: number;
|
|
149
|
-
}
|
|
150
|
-
/** Circuit breaker options */
|
|
151
|
-
interface CircuitBreakerOptions extends CircuitBreakerConfig {
|
|
152
|
-
/** Callback when state changes */
|
|
153
|
-
onStateChange?: (event: CircuitStateChange) => void;
|
|
154
|
-
/** Custom function to determine if an error should count as a failure */
|
|
155
|
-
isFailure?: (error: Error) => boolean;
|
|
249
|
+
/** Error response body from the API */
|
|
250
|
+
interface ApiErrorBody {
|
|
251
|
+
code: string;
|
|
252
|
+
message: string;
|
|
253
|
+
details?: Record<string, unknown>;
|
|
156
254
|
}
|
|
157
255
|
/**
|
|
158
|
-
*
|
|
256
|
+
* Rate limit information parsed from headers.
|
|
159
257
|
*
|
|
160
|
-
*
|
|
258
|
+
* Authenticated responses that went through the plan rate limiter carry
|
|
259
|
+
* `X-RateLimit-Limit`, `-Remaining`, `-Reset` and `-Scope` (API 0.1.122+); a
|
|
260
|
+
* 429 adds `Retry-After`. Every field is optional: the headers are left out
|
|
261
|
+
* when no rate-limit check ran (public and admin routes, a server without
|
|
262
|
+
* Redis, older servers).
|
|
161
263
|
*/
|
|
162
|
-
|
|
163
|
-
private state;
|
|
164
|
-
private failureCount;
|
|
165
|
-
private successCount;
|
|
166
|
-
private lastFailureTime;
|
|
167
|
-
private readonly config;
|
|
168
|
-
constructor(config: CircuitBreakerOptions);
|
|
169
|
-
/**
|
|
170
|
-
* Get current circuit state
|
|
171
|
-
*/
|
|
172
|
-
getState(): CircuitState;
|
|
173
|
-
/**
|
|
174
|
-
* Check if circuit breaker is enabled
|
|
175
|
-
*/
|
|
176
|
-
isEnabled(): boolean;
|
|
264
|
+
interface RateLimitInfo {
|
|
177
265
|
/**
|
|
178
|
-
*
|
|
179
|
-
|
|
180
|
-
isAllowed(): boolean;
|
|
181
|
-
/**
|
|
182
|
-
* Record a successful request
|
|
266
|
+
* The limit the other fields describe: the plan burst (organization token
|
|
267
|
+
* bucket) or an API key's own requests per minute.
|
|
183
268
|
*/
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
|
|
187
|
-
*/
|
|
188
|
-
recordFailure(error: Error): void;
|
|
269
|
+
limit?: number;
|
|
270
|
+
/** Whole requests left after this one */
|
|
271
|
+
remaining?: number;
|
|
189
272
|
/**
|
|
190
|
-
*
|
|
273
|
+
* When `remaining` next goes up (`X-RateLimit-Reset`, a Unix time in
|
|
274
|
+
* seconds; the current time while the bucket is full).
|
|
191
275
|
*/
|
|
192
|
-
|
|
276
|
+
reset?: Date;
|
|
277
|
+
/** Seconds to wait before retrying (`Retry-After`, on a 429) */
|
|
278
|
+
retryAfter?: number;
|
|
193
279
|
/**
|
|
194
|
-
*
|
|
280
|
+
* Which limit the headers describe (`X-RateLimit-Scope`): `organization`
|
|
281
|
+
* (the plan's token bucket) or `api_key` (the key's `rateLimit`).
|
|
195
282
|
*/
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
283
|
+
scope?: "organization" | "api_key" | (string & {});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Base error class for all Spooled SDK errors
|
|
287
|
+
*/
|
|
288
|
+
declare class SpooledError extends Error {
|
|
289
|
+
/** HTTP status code (if applicable) */
|
|
290
|
+
readonly statusCode: number;
|
|
291
|
+
/** Error code from API response */
|
|
292
|
+
readonly code: string;
|
|
293
|
+
/** Additional error details */
|
|
294
|
+
readonly details?: Record<string, unknown>;
|
|
295
|
+
/** Request ID for debugging */
|
|
296
|
+
readonly requestId?: string;
|
|
297
|
+
/** Original cause of the error */
|
|
298
|
+
readonly cause?: Error;
|
|
299
|
+
constructor(message: string, statusCode?: number, code?: string, details?: Record<string, unknown>, requestId?: string, cause?: Error);
|
|
300
|
+
/**
|
|
301
|
+
* Whether this error is retryable.
|
|
199
302
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
303
|
+
* Only 408 (Request Timeout) is retryable among the plain 4xx statuses: the
|
|
304
|
+
* server gave up waiting for the request, so it never ran. Subclasses
|
|
305
|
+
* override this (5xx, network, timeout, rate limit).
|
|
203
306
|
*/
|
|
204
|
-
|
|
307
|
+
isRetryable(): boolean;
|
|
308
|
+
/** Convert to plain object for logging */
|
|
309
|
+
toJSON(): Record<string, unknown>;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Authentication error (401)
|
|
313
|
+
* Thrown when authentication fails (invalid/expired token or API key)
|
|
314
|
+
*/
|
|
315
|
+
declare class AuthenticationError extends SpooledError {
|
|
316
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Authorization error (403)
|
|
320
|
+
* Thrown when the authenticated user lacks permission
|
|
321
|
+
*/
|
|
322
|
+
declare class AuthorizationError extends SpooledError {
|
|
323
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Not found error (404)
|
|
327
|
+
* Thrown when a requested resource doesn't exist
|
|
328
|
+
*/
|
|
329
|
+
declare class NotFoundError extends SpooledError {
|
|
330
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Conflict error (409)
|
|
334
|
+
* Thrown when there's a conflict (e.g., duplicate resource)
|
|
335
|
+
*/
|
|
336
|
+
declare class ConflictError extends SpooledError {
|
|
337
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Validation error (400 or 422)
|
|
341
|
+
* Thrown when request validation fails.
|
|
342
|
+
*
|
|
343
|
+
* The API answers a field-rule failure (length, range) with 400 but a missing
|
|
344
|
+
* or mistyped JSON field with 422; both are the caller's request being invalid,
|
|
345
|
+
* so both surface as this class. `statusCode` tells them apart.
|
|
346
|
+
*/
|
|
347
|
+
declare class ValidationError extends SpooledError {
|
|
348
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string, statusCode?: 400 | 422);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Payload too large error (413)
|
|
352
|
+
* Thrown when request body exceeds size limit
|
|
353
|
+
*/
|
|
354
|
+
declare class PayloadTooLargeError extends SpooledError {
|
|
355
|
+
constructor(message?: string, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Rate limit error (429)
|
|
359
|
+
* Thrown when rate limit is exceeded, or a plan quota is (see `isQuota`)
|
|
360
|
+
*/
|
|
361
|
+
declare class RateLimitError extends SpooledError {
|
|
362
|
+
/** Rate limit information */
|
|
363
|
+
readonly rateLimitInfo: RateLimitInfo;
|
|
364
|
+
constructor(message?: string, code?: string, rateLimitInfo?: RateLimitInfo, details?: Record<string, unknown>, requestId?: string);
|
|
205
365
|
/**
|
|
206
|
-
*
|
|
366
|
+
* True when this 429 is a plan quota or limit (daily job cap, active jobs,
|
|
367
|
+
* queue/worker/webhook caps) rather than per-second rate limiting.
|
|
368
|
+
*
|
|
369
|
+
* A quota does not clear for minutes or hours, so retrying it only blocks the
|
|
370
|
+
* caller for the whole backoff and, via the circuit breaker, takes every
|
|
371
|
+
* other call on the client down with it. It is never retried and never
|
|
372
|
+
* counted as a circuit breaker failure.
|
|
373
|
+
*
|
|
374
|
+
* Detection: the `QUOTA_EXCEEDED` code, or, for older plan-limit paths that
|
|
375
|
+
* answer with plain text wrapped as `RATE_LIMIT_EXCEEDED`, a "... limit
|
|
376
|
+
* reached" message that carries no `Retry-After`.
|
|
207
377
|
*/
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
378
|
+
get isQuota(): boolean;
|
|
379
|
+
isRetryable(): boolean;
|
|
380
|
+
/** Get the number of seconds to wait before retrying */
|
|
381
|
+
getRetryAfter(): number;
|
|
382
|
+
toJSON(): Record<string, unknown>;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Server error (5xx)
|
|
386
|
+
* Thrown when the server encounters an error
|
|
387
|
+
*/
|
|
388
|
+
declare class ServerError extends SpooledError {
|
|
389
|
+
constructor(message?: string, statusCode?: number, code?: string, details?: Record<string, unknown>, requestId?: string);
|
|
390
|
+
isRetryable(): boolean;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Network error
|
|
394
|
+
* Thrown when a network request fails (no response received)
|
|
395
|
+
*/
|
|
396
|
+
declare class NetworkError extends SpooledError {
|
|
397
|
+
constructor(message?: string, cause?: Error);
|
|
398
|
+
isRetryable(): boolean;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Timeout error
|
|
402
|
+
* Thrown when a request times out
|
|
403
|
+
*/
|
|
404
|
+
declare class TimeoutError extends SpooledError {
|
|
405
|
+
/** Timeout duration in milliseconds */
|
|
406
|
+
readonly timeoutMs: number;
|
|
407
|
+
constructor(message?: string, timeoutMs?: number);
|
|
408
|
+
isRetryable(): boolean;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Circuit breaker open error
|
|
412
|
+
* Thrown when the circuit breaker is open and rejecting requests
|
|
413
|
+
*/
|
|
414
|
+
declare class CircuitBreakerOpenError extends SpooledError {
|
|
415
|
+
constructor(message?: string);
|
|
416
|
+
isRetryable(): boolean;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Unsupported operation error
|
|
420
|
+
* Thrown by SDK methods whose route the Spooled API does not provide (or
|
|
421
|
+
* always rejects). It is raised before any network call, so code that still
|
|
422
|
+
* calls such a method fails loudly with an explanation instead of a 404.
|
|
423
|
+
*/
|
|
424
|
+
declare class UnsupportedOperationError extends SpooledError {
|
|
425
|
+
/** The SDK method that is not supported, e.g. `ingest.github` */
|
|
426
|
+
readonly operation: string;
|
|
427
|
+
constructor(operation: string, reason: string);
|
|
215
428
|
}
|
|
216
429
|
/**
|
|
217
|
-
*
|
|
430
|
+
* Parse rate limit headers from a Response
|
|
431
|
+
*/
|
|
432
|
+
declare function parseRateLimitHeaders(headers: Headers): RateLimitInfo;
|
|
433
|
+
/**
|
|
434
|
+
* Create an appropriate error from an HTTP response
|
|
435
|
+
*/
|
|
436
|
+
declare function createErrorFromResponse(response: Response): Promise<SpooledError>;
|
|
437
|
+
/**
|
|
438
|
+
* Check if an error is a SpooledError instance
|
|
439
|
+
*/
|
|
440
|
+
declare function isSpooledError(error: unknown): error is SpooledError;
|
|
441
|
+
/**
|
|
442
|
+
* Check if an error is retryable
|
|
218
443
|
*/
|
|
219
|
-
declare function
|
|
444
|
+
declare function isRetryableError(error: unknown): boolean;
|
|
220
445
|
|
|
221
446
|
/**
|
|
222
447
|
* HTTP Client Utility
|
|
@@ -262,6 +487,20 @@ interface HttpRequestOptions {
|
|
|
262
487
|
skipResponseConversion?: boolean;
|
|
263
488
|
/** Whether to skip retry logic */
|
|
264
489
|
skipRetry?: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* The request is safe to replay even though it is a POST/PATCH, so network
|
|
492
|
+
* errors, timeouts, 5xx and 408 are retried like they are for a GET.
|
|
493
|
+
*
|
|
494
|
+
* Use it only for calls the server makes idempotent: lease-fenced job and
|
|
495
|
+
* worker acks (complete/fail/heartbeat answer a replay with 409) and job
|
|
496
|
+
* creation with an idempotency key (the server returns the existing job).
|
|
497
|
+
*/
|
|
498
|
+
idempotent?: boolean;
|
|
499
|
+
/**
|
|
500
|
+
* Never try to refresh the access token when this request gets a 401.
|
|
501
|
+
* Set on the auth calls that the refresh itself makes.
|
|
502
|
+
*/
|
|
503
|
+
skipAuthRefresh?: boolean;
|
|
265
504
|
/** Optional abort signal */
|
|
266
505
|
signal?: AbortSignal;
|
|
267
506
|
}
|
|
@@ -287,13 +526,25 @@ declare class HttpClient {
|
|
|
287
526
|
private authToken;
|
|
288
527
|
/** Optional function to mint a fresh access token (set when auto-refresh is enabled) */
|
|
289
528
|
private refreshTokenFn;
|
|
290
|
-
/**
|
|
291
|
-
|
|
529
|
+
/**
|
|
530
|
+
* The refresh currently in flight, shared by every request that gets a 401
|
|
531
|
+
* meanwhile. A boolean guard here made the second concurrent 401 skip the
|
|
532
|
+
* refresh and fail even though the token was about to be replaced.
|
|
533
|
+
*/
|
|
534
|
+
private refreshInFlight;
|
|
535
|
+
/** Rate-limit headers of the most recent response that carried them */
|
|
536
|
+
private lastRateLimit;
|
|
292
537
|
constructor(config: ResolvedConfig, circuitBreaker: CircuitBreaker);
|
|
293
538
|
/**
|
|
294
539
|
* Set the authentication token
|
|
295
540
|
*/
|
|
296
541
|
setAuthToken(token: string): void;
|
|
542
|
+
/**
|
|
543
|
+
* The `X-RateLimit-*` (and `Retry-After`) values of the most recent
|
|
544
|
+
* response that carried them, successful or not. `undefined` until such a
|
|
545
|
+
* response arrives. With concurrent requests it is the last one to finish.
|
|
546
|
+
*/
|
|
547
|
+
getLastRateLimitInfo(): RateLimitInfo | undefined;
|
|
297
548
|
/**
|
|
298
549
|
* Set the token refresh function.
|
|
299
550
|
*
|
|
@@ -301,6 +552,13 @@ declare class HttpClient {
|
|
|
301
552
|
* refresh + retry of the original request with the new token.
|
|
302
553
|
*/
|
|
303
554
|
setRefreshTokenFn(fn: () => Promise<string>): void;
|
|
555
|
+
/**
|
|
556
|
+
* Refresh the access token once for all callers.
|
|
557
|
+
*
|
|
558
|
+
* Resolves true when a new token is installed, false when the refresh failed
|
|
559
|
+
* (the caller then surfaces its original 401).
|
|
560
|
+
*/
|
|
561
|
+
private refreshAuthToken;
|
|
304
562
|
/**
|
|
305
563
|
* Build full URL with query parameters
|
|
306
564
|
*/
|
|
@@ -317,6 +575,8 @@ declare class HttpClient {
|
|
|
317
575
|
* Execute a single HTTP request (no retry)
|
|
318
576
|
*/
|
|
319
577
|
private executeRequest;
|
|
578
|
+
/** Remember the rate-limit headers of a response that has them. */
|
|
579
|
+
private recordRateLimit;
|
|
320
580
|
/**
|
|
321
581
|
* Make an HTTP request with retry and circuit breaker
|
|
322
582
|
*/
|
|
@@ -329,12 +589,13 @@ declare class HttpClient {
|
|
|
329
589
|
/**
|
|
330
590
|
* Resolve the retry configuration for a request.
|
|
331
591
|
*
|
|
332
|
-
* Idempotent methods (GET/PUT/DELETE)
|
|
333
|
-
*
|
|
334
|
-
*
|
|
592
|
+
* Idempotent methods (GET/PUT/DELETE), any request carrying an idempotency
|
|
593
|
+
* key and any request marked `idempotent` retry normally. Non-idempotent
|
|
594
|
+
* methods (POST/PATCH) otherwise must NOT be retried on ambiguous failures
|
|
335
595
|
* (network/timeout/5xx) — doing so risks duplicate jobs, double claims,
|
|
336
|
-
* etc. They are still retried on 429, which is rejected before
|
|
337
|
-
* server processes the request and is therefore side-effect-free.
|
|
596
|
+
* etc. They are still retried on a rate-limit 429, which is rejected before
|
|
597
|
+
* the server processes the request and is therefore side-effect-free. A
|
|
598
|
+
* quota 429 is never retried: it does not clear for hours.
|
|
338
599
|
*/
|
|
339
600
|
private resolveRetryConfig;
|
|
340
601
|
/**
|
|
@@ -509,8 +770,32 @@ type PlanTier = "free" | "starter" | "pro" | "enterprise";
|
|
|
509
770
|
type ScheduleRunStatus = "pending" | "running" | "completed" | "failed";
|
|
510
771
|
/** Webhook delivery status */
|
|
511
772
|
type WebhookDeliveryStatus = "pending" | "success" | "failed";
|
|
512
|
-
/**
|
|
513
|
-
|
|
773
|
+
/**
|
|
774
|
+
* Webhook event types.
|
|
775
|
+
*
|
|
776
|
+
* `job.deadlettered`, `job.retried`, `workflow.completed` and
|
|
777
|
+
* `workflow.failed` need API 0.1.122 or later. The SDK does not check event
|
|
778
|
+
* names in responses: a name newer than this list is passed through as a
|
|
779
|
+
* string, so give a `switch` over it a `default` branch.
|
|
780
|
+
*/
|
|
781
|
+
type WebhookEventType = "job.created" | "job.started" | "job.completed" | "job.failed" | "job.cancelled" | "queue.paused" | "queue.resumed" | "worker.registered" | "worker.deregistered" | "schedule.triggered"
|
|
782
|
+
/** Sent next to every `job.failed` whose `data.status` is `deadletter`. */
|
|
783
|
+
| "job.deadlettered"
|
|
784
|
+
/** A manual retry (job, DLQ or workflow retry) put the job back to pending. */
|
|
785
|
+
| "job.retried"
|
|
786
|
+
/** A workflow finished; announced at most once, up to ~10 s late. */
|
|
787
|
+
| "workflow.completed"
|
|
788
|
+
/** A workflow failed; announced at most once, up to ~10 s late. */
|
|
789
|
+
| "workflow.failed";
|
|
790
|
+
/**
|
|
791
|
+
* Body format of an outgoing webhook (API 0.1.122+).
|
|
792
|
+
*
|
|
793
|
+
* `json` (the default) is the signed JSON envelope. `slack`, `discord` and
|
|
794
|
+
* `teams` send one short chat message built from the event, so a chat
|
|
795
|
+
* service's incoming-webhook URL can be used as it is (`teams` is the legacy
|
|
796
|
+
* Office 365 connector `MessageCard`; Teams Workflows URLs reject it).
|
|
797
|
+
*/
|
|
798
|
+
type WebhookFormat = "json" | "slack" | "discord" | "teams";
|
|
514
799
|
/** Dependency mode for workflows */
|
|
515
800
|
type DependencyMode = "all" | "any";
|
|
516
801
|
/** Pagination parameters */
|
|
@@ -540,6 +825,22 @@ interface PaginatedResponse<T> {
|
|
|
540
825
|
/** Whether there are more results */
|
|
541
826
|
hasMore: boolean;
|
|
542
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* One page of a list endpoint that reports `X-Has-More` (API 0.1.122+):
|
|
830
|
+
* `GET /jobs`, `GET /jobs/dlq` and `GET /jobs/{id}/history`.
|
|
831
|
+
*
|
|
832
|
+
* The response body stays a bare array; `hasMore` comes from the header.
|
|
833
|
+
*/
|
|
834
|
+
interface ListPage<T> {
|
|
835
|
+
/** Items of this page, in the server's order */
|
|
836
|
+
data: T[];
|
|
837
|
+
/**
|
|
838
|
+
* `true` when another page follows: ask again with
|
|
839
|
+
* `offset + data.length`. From the `X-Has-More` header; an older server
|
|
840
|
+
* without it gets a guess from the page size (a full page means "maybe").
|
|
841
|
+
*/
|
|
842
|
+
hasMore: boolean;
|
|
843
|
+
}
|
|
543
844
|
/**
|
|
544
845
|
* Helper to create a paginated response from an array
|
|
545
846
|
*/
|
|
@@ -624,18 +925,44 @@ interface CreateJobParams {
|
|
|
624
925
|
parentJobId?: string;
|
|
625
926
|
/** Webhook URL for completion notification */
|
|
626
927
|
completionWebhook?: string;
|
|
928
|
+
/** HMAC secret used to sign the `completionWebhook` request (never returned by the API) */
|
|
929
|
+
completionWebhookSecret?: string;
|
|
627
930
|
}
|
|
628
931
|
/** Result of creating a job */
|
|
629
932
|
interface CreateJobResult {
|
|
630
933
|
id: string;
|
|
631
934
|
created: boolean;
|
|
632
935
|
}
|
|
936
|
+
/**
|
|
937
|
+
* Server-side job search filters (API 0.1.122+), shared by `GET /jobs` and
|
|
938
|
+
* `GET /jobs/dlq`. All filters combine with AND. An invalid value is a 400
|
|
939
|
+
* `ValidationError`; an older server ignores them.
|
|
940
|
+
*/
|
|
941
|
+
interface JobSearchParams {
|
|
942
|
+
/**
|
|
943
|
+
* Search text, case-insensitive: matches a job whose id starts with it, or
|
|
944
|
+
* whose queue name or `payload.job_type` contains it (at most 255 bytes).
|
|
945
|
+
*/
|
|
946
|
+
q?: string;
|
|
947
|
+
/** Exact `payload.job_type` (at most 255 bytes) */
|
|
948
|
+
jobType?: string;
|
|
949
|
+
/**
|
|
950
|
+
* Only jobs created at or after this instant. A `Date` is sent as an
|
|
951
|
+
* ISO 8601 UTC string; a string must be RFC 3339.
|
|
952
|
+
*/
|
|
953
|
+
createdAfter?: Date | string;
|
|
954
|
+
/** Only jobs created before this instant (exclusive); see `createdAfter` */
|
|
955
|
+
createdBefore?: Date | string;
|
|
956
|
+
}
|
|
633
957
|
/** Parameters for listing jobs */
|
|
634
|
-
interface ListJobsParams extends ListParams {
|
|
958
|
+
interface ListJobsParams extends ListParams, JobSearchParams {
|
|
635
959
|
/** Filter by queue name */
|
|
636
960
|
queueName?: string;
|
|
637
|
-
/**
|
|
638
|
-
|
|
961
|
+
/**
|
|
962
|
+
* Filter by status: one status, or several (sent as the comma list
|
|
963
|
+
* `status=failed,deadletter`, which needs API 0.1.122+).
|
|
964
|
+
*/
|
|
965
|
+
status?: JobStatus | readonly JobStatus[];
|
|
639
966
|
/** Filter by a single tag (matches Postgres `tags ? tag` semantics) */
|
|
640
967
|
tag?: string;
|
|
641
968
|
}
|
|
@@ -669,10 +996,9 @@ interface ClaimedJob {
|
|
|
669
996
|
timeoutSeconds: number;
|
|
670
997
|
leaseExpiresAt?: string;
|
|
671
998
|
/**
|
|
672
|
-
* Lease fencing token for this claim.
|
|
673
|
-
* complete/fail/heartbeat
|
|
674
|
-
*
|
|
675
|
-
* LEASE_EXPIRED). Omitted = legacy behavior.
|
|
999
|
+
* Lease fencing token for this claim. Send it back on
|
|
1000
|
+
* complete/fail/heartbeat: the API requires it (a call without it is a 422
|
|
1001
|
+
* `ValidationError`, since 2026-07) and rejects a stale lease with 409.
|
|
676
1002
|
*/
|
|
677
1003
|
leaseId?: string | null;
|
|
678
1004
|
}
|
|
@@ -697,7 +1023,10 @@ interface CompleteJobParams {
|
|
|
697
1023
|
workerId: string;
|
|
698
1024
|
/** Optional result payload (any JSON) */
|
|
699
1025
|
result?: JsonValue;
|
|
700
|
-
/**
|
|
1026
|
+
/**
|
|
1027
|
+
* Lease fencing token from the claimed job (`ClaimedJob.leaseId`). The API
|
|
1028
|
+
* requires it: without it the call is a 422 `ValidationError`.
|
|
1029
|
+
*/
|
|
701
1030
|
leaseId?: string;
|
|
702
1031
|
}
|
|
703
1032
|
/** Parameters for failing a job */
|
|
@@ -706,7 +1035,10 @@ interface FailJobParams {
|
|
|
706
1035
|
workerId: string;
|
|
707
1036
|
/** Error message (1-2048 chars) */
|
|
708
1037
|
error: string;
|
|
709
|
-
/**
|
|
1038
|
+
/**
|
|
1039
|
+
* Lease fencing token from the claimed job (`ClaimedJob.leaseId`). The API
|
|
1040
|
+
* requires it: without it the call is a 422 `ValidationError`.
|
|
1041
|
+
*/
|
|
710
1042
|
leaseId?: string;
|
|
711
1043
|
}
|
|
712
1044
|
/** Parameters for job heartbeat */
|
|
@@ -715,7 +1047,10 @@ interface HeartbeatJobParams {
|
|
|
715
1047
|
workerId: string;
|
|
716
1048
|
/** Lease duration in seconds (5-3600) */
|
|
717
1049
|
leaseDurationSecs: number;
|
|
718
|
-
/**
|
|
1050
|
+
/**
|
|
1051
|
+
* Lease fencing token from the claimed job (`ClaimedJob.leaseId`). The API
|
|
1052
|
+
* requires it: without it the call is a 422 `ValidationError`.
|
|
1053
|
+
*/
|
|
719
1054
|
leaseId?: string;
|
|
720
1055
|
}
|
|
721
1056
|
/** Response for priority boost */
|
|
@@ -760,10 +1095,37 @@ interface BulkEnqueueResponse {
|
|
|
760
1095
|
failureCount: number;
|
|
761
1096
|
}
|
|
762
1097
|
/** Parameters for listing DLQ */
|
|
763
|
-
interface ListDlqParams extends ListParams {
|
|
1098
|
+
interface ListDlqParams extends ListParams, JobSearchParams {
|
|
764
1099
|
/** Filter by queue name */
|
|
765
1100
|
queueName?: string;
|
|
766
1101
|
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Event types of `GET /jobs/{id}/history`. The server records `processing`
|
|
1104
|
+
* (REST claim), `completed` (REST complete), `retry_scheduled` and
|
|
1105
|
+
* `deadlettered` (REST fail, scheduler sweeps); `created` is defined but not
|
|
1106
|
+
* written today, and jobs settled over gRPC have sparse history. Any other
|
|
1107
|
+
* string the server sends is passed through.
|
|
1108
|
+
*/
|
|
1109
|
+
type JobHistoryEventType = "created" | "processing" | "completed" | "retry_scheduled" | "deadlettered" | (string & {});
|
|
1110
|
+
/** One recorded lifecycle event of a job (`GET /jobs/{id}/history`) */
|
|
1111
|
+
interface JobHistoryEvent {
|
|
1112
|
+
id: string;
|
|
1113
|
+
jobId: string;
|
|
1114
|
+
eventType: JobHistoryEventType;
|
|
1115
|
+
/** The worker that caused the event, when known */
|
|
1116
|
+
workerId?: string | null;
|
|
1117
|
+
/**
|
|
1118
|
+
* Event details as stored (any JSON, keys left in snake_case as the server
|
|
1119
|
+
* wrote them).
|
|
1120
|
+
*/
|
|
1121
|
+
details: JsonValue;
|
|
1122
|
+
createdAt: string;
|
|
1123
|
+
}
|
|
1124
|
+
/** Parameters for `jobs.history()` (API 0.1.122+) */
|
|
1125
|
+
interface JobHistoryParams extends PaginationParams {
|
|
1126
|
+
/** `asc` (default, oldest first) or `desc` (newest first) */
|
|
1127
|
+
order?: "asc" | "desc";
|
|
1128
|
+
}
|
|
767
1129
|
/** Parameters for retrying DLQ jobs */
|
|
768
1130
|
interface RetryDlqParams {
|
|
769
1131
|
/** Specific job IDs to retry */
|
|
@@ -802,6 +1164,11 @@ interface PurgeDlqResponse {
|
|
|
802
1164
|
interface DlqOperations {
|
|
803
1165
|
/** List jobs in dead-letter queue */
|
|
804
1166
|
list(params?: ListDlqParams): Promise<JobSummary[]>;
|
|
1167
|
+
/**
|
|
1168
|
+
* List one page of the dead-letter queue with `hasMore` from the
|
|
1169
|
+
* `X-Has-More` header (API 0.1.122+).
|
|
1170
|
+
*/
|
|
1171
|
+
listPage(params?: ListDlqParams): Promise<ListPage<JobSummary>>;
|
|
805
1172
|
/** Retry jobs from DLQ */
|
|
806
1173
|
retry(params: RetryDlqParams): Promise<RetryDlqResponse>;
|
|
807
1174
|
/** Purge jobs from DLQ */
|
|
@@ -822,8 +1189,33 @@ declare class JobsResource {
|
|
|
822
1189
|
createAndGet(params: CreateJobParams): Promise<Job>;
|
|
823
1190
|
/**
|
|
824
1191
|
* List jobs with optional filtering
|
|
1192
|
+
*
|
|
1193
|
+
* `status` takes one status or several, and `q`, `jobType`, `createdAfter`
|
|
1194
|
+
* and `createdBefore` filter on the server (API 0.1.122+). Use
|
|
1195
|
+
* {@link JobsResource.listPage} to also learn whether another page follows.
|
|
825
1196
|
*/
|
|
826
1197
|
list(params?: ListJobsParams): Promise<JobSummary[]>;
|
|
1198
|
+
/**
|
|
1199
|
+
* List one page of jobs with `hasMore` from the `X-Has-More` header
|
|
1200
|
+
* (API 0.1.122+). Takes the same filters as {@link JobsResource.list}.
|
|
1201
|
+
*
|
|
1202
|
+
* @example
|
|
1203
|
+
* ```typescript
|
|
1204
|
+
* let offset = 0;
|
|
1205
|
+
* for (;;) {
|
|
1206
|
+
* const page = await client.jobs.listPage({
|
|
1207
|
+
* status: ["failed", "deadletter"],
|
|
1208
|
+
* createdAfter: new Date(Date.now() - 86_400_000),
|
|
1209
|
+
* limit: 100,
|
|
1210
|
+
* offset,
|
|
1211
|
+
* });
|
|
1212
|
+
* handle(page.data);
|
|
1213
|
+
* if (!page.hasMore) break;
|
|
1214
|
+
* offset += page.data.length;
|
|
1215
|
+
* }
|
|
1216
|
+
* ```
|
|
1217
|
+
*/
|
|
1218
|
+
listPage(params?: ListJobsParams): Promise<ListPage<JobSummary>>;
|
|
827
1219
|
/**
|
|
828
1220
|
* Get a job by ID
|
|
829
1221
|
*/
|
|
@@ -840,6 +1232,21 @@ declare class JobsResource {
|
|
|
840
1232
|
* Boost job priority
|
|
841
1233
|
*/
|
|
842
1234
|
boostPriority(id: string, priority: number): Promise<BoostPriorityResponse>;
|
|
1235
|
+
/**
|
|
1236
|
+
* Get the recorded lifecycle events of a job (`GET /jobs/{id}/history`,
|
|
1237
|
+
* API 0.1.122+), oldest first unless `order: "desc"`.
|
|
1238
|
+
*
|
|
1239
|
+
* The history is sparse: the server records REST claims (`processing`),
|
|
1240
|
+
* completions (`completed`) and failures (`retry_scheduled`,
|
|
1241
|
+
* `deadlettered`) and the scheduler's dead-letter sweeps, so a job settled
|
|
1242
|
+
* over gRPC may have few or no events. An unknown job is a `NotFoundError`.
|
|
1243
|
+
*/
|
|
1244
|
+
history(id: string, params?: JobHistoryParams): Promise<JobHistoryEvent[]>;
|
|
1245
|
+
/**
|
|
1246
|
+
* One page of {@link JobsResource.history} with `hasMore` from the
|
|
1247
|
+
* `X-Has-More` header. `limit` defaults to 100 (at most 500).
|
|
1248
|
+
*/
|
|
1249
|
+
historyPage(id: string, params?: JobHistoryParams): Promise<ListPage<JobHistoryEvent>>;
|
|
843
1250
|
/**
|
|
844
1251
|
* Get job statistics
|
|
845
1252
|
*/
|
|
@@ -858,12 +1265,20 @@ declare class JobsResource {
|
|
|
858
1265
|
claim(params: ClaimJobsParams): Promise<ClaimJobsResult>;
|
|
859
1266
|
/**
|
|
860
1267
|
* Complete a job (worker ack)
|
|
1268
|
+
*
|
|
1269
|
+
* Lease-fenced and idempotent on the server, so a network error, timeout or
|
|
1270
|
+
* 5xx is retried: a lost ack would otherwise re-run a finished job.
|
|
861
1271
|
*/
|
|
862
1272
|
complete(id: string, params: CompleteJobParams): Promise<{
|
|
863
1273
|
success: boolean;
|
|
864
1274
|
}>;
|
|
865
1275
|
/**
|
|
866
1276
|
* Fail a job (worker nack)
|
|
1277
|
+
*
|
|
1278
|
+
* `params.error` is made acceptable first: empty text becomes "Job failed"
|
|
1279
|
+
* and text over 2048 characters is truncated, because the API rejects both
|
|
1280
|
+
* with a 400 that would leave the job processing until its lease expires.
|
|
1281
|
+
* Retried like {@link JobsResource.complete}.
|
|
867
1282
|
*/
|
|
868
1283
|
fail(id: string, params: FailJobParams): Promise<{
|
|
869
1284
|
success: boolean;
|
|
@@ -871,11 +1286,16 @@ declare class JobsResource {
|
|
|
871
1286
|
}>;
|
|
872
1287
|
/**
|
|
873
1288
|
* Extend job lease (heartbeat)
|
|
1289
|
+
*
|
|
1290
|
+
* Retried like {@link JobsResource.complete}: with the default 30 s lease and
|
|
1291
|
+
* 15 s heartbeat, one lost heartbeat leaves no slack.
|
|
874
1292
|
*/
|
|
875
1293
|
heartbeat(id: string, params: HeartbeatJobParams): Promise<{
|
|
876
1294
|
success: boolean;
|
|
877
1295
|
}>;
|
|
878
1296
|
private listDlq;
|
|
1297
|
+
private listDlqPage;
|
|
1298
|
+
private listSummaries;
|
|
879
1299
|
private retryDlq;
|
|
880
1300
|
private purgeDlq;
|
|
881
1301
|
}
|
|
@@ -946,6 +1366,14 @@ interface ResumeQueueResponse {
|
|
|
946
1366
|
resumed: boolean;
|
|
947
1367
|
pausedDurationSecs: number;
|
|
948
1368
|
}
|
|
1369
|
+
/** Options for deleting a queue */
|
|
1370
|
+
interface DeleteQueueOptions {
|
|
1371
|
+
/**
|
|
1372
|
+
* Also delete every job (and dead-letter row) of the queue. Required to
|
|
1373
|
+
* delete a queue with pending/processing jobs or one without a stored config.
|
|
1374
|
+
*/
|
|
1375
|
+
deleteJobs?: boolean;
|
|
1376
|
+
}
|
|
949
1377
|
|
|
950
1378
|
/**
|
|
951
1379
|
* Queues Resource
|
|
@@ -982,8 +1410,14 @@ declare class QueuesResource {
|
|
|
982
1410
|
resume(name: string): Promise<ResumeQueueResponse>;
|
|
983
1411
|
/**
|
|
984
1412
|
* Delete a queue configuration
|
|
1413
|
+
*
|
|
1414
|
+
* Without `deleteJobs` the API only deletes an explicit queue config of an
|
|
1415
|
+
* idle queue, and answers 409 otherwise: a queue that exists only because
|
|
1416
|
+
* jobs were posted to it has no config to delete, and a queue with pending
|
|
1417
|
+
* or processing jobs is not idle. Pass `{ deleteJobs: true }` to delete the
|
|
1418
|
+
* queue's jobs (and DLQ rows) along with it.
|
|
985
1419
|
*/
|
|
986
|
-
delete(name: string): Promise<void>;
|
|
1420
|
+
delete(name: string, options?: DeleteQueueOptions): Promise<void>;
|
|
987
1421
|
}
|
|
988
1422
|
|
|
989
1423
|
/**
|
|
@@ -1012,6 +1446,17 @@ interface Worker {
|
|
|
1012
1446
|
registeredAt: string;
|
|
1013
1447
|
/** Last row update (detail response). */
|
|
1014
1448
|
updatedAt?: string;
|
|
1449
|
+
/**
|
|
1450
|
+
* Jobs this worker completed while it held the lease (API 0.1.122+; counts
|
|
1451
|
+
* start at 0 with that release).
|
|
1452
|
+
*/
|
|
1453
|
+
jobsProcessed?: number;
|
|
1454
|
+
/**
|
|
1455
|
+
* Failed attempts this worker reported while it held the lease: a fail
|
|
1456
|
+
* that was retried or dead-lettered (API 0.1.122+). Lease-expiry recovery
|
|
1457
|
+
* does not count.
|
|
1458
|
+
*/
|
|
1459
|
+
jobsFailed?: number;
|
|
1015
1460
|
}
|
|
1016
1461
|
/** Worker summary for list responses */
|
|
1017
1462
|
interface WorkerSummary {
|
|
@@ -1022,6 +1467,10 @@ interface WorkerSummary {
|
|
|
1022
1467
|
currentJobs: number;
|
|
1023
1468
|
maxConcurrency: number;
|
|
1024
1469
|
lastHeartbeat: string;
|
|
1470
|
+
/** See {@link Worker.jobsProcessed} (API 0.1.122+). */
|
|
1471
|
+
jobsProcessed?: number;
|
|
1472
|
+
/** See {@link Worker.jobsFailed} (API 0.1.122+). */
|
|
1473
|
+
jobsFailed?: number;
|
|
1025
1474
|
}
|
|
1026
1475
|
/** Parameters for registering a worker */
|
|
1027
1476
|
interface RegisterWorkerParams {
|
|
@@ -1090,6 +1539,8 @@ declare class WorkersResource {
|
|
|
1090
1539
|
register(params: RegisterWorkerParams): Promise<RegisterWorkerResponse>;
|
|
1091
1540
|
/**
|
|
1092
1541
|
* Send worker heartbeat
|
|
1542
|
+
*
|
|
1543
|
+
* Idempotent on the server, so network errors, timeouts and 5xx are retried.
|
|
1093
1544
|
*/
|
|
1094
1545
|
heartbeat(id: string, params: WorkerHeartbeatParams): Promise<void>;
|
|
1095
1546
|
/**
|
|
@@ -1359,8 +1810,12 @@ interface WorkflowJob {
|
|
|
1359
1810
|
id: string;
|
|
1360
1811
|
/** Workflow ID this job belongs to */
|
|
1361
1812
|
workflowId: string;
|
|
1362
|
-
/**
|
|
1363
|
-
|
|
1813
|
+
/**
|
|
1814
|
+
* Job key within the workflow. The API does not return it (a job stores only
|
|
1815
|
+
* its workflow step), so this is undefined today; take the key to job ID
|
|
1816
|
+
* mapping from the `jobIds` of `workflows.create()`.
|
|
1817
|
+
*/
|
|
1818
|
+
key?: string;
|
|
1364
1819
|
/** Queue name */
|
|
1365
1820
|
queueName: string;
|
|
1366
1821
|
/** Current job status */
|
|
@@ -1392,8 +1847,8 @@ interface WorkflowJob {
|
|
|
1392
1847
|
interface WorkflowJobStatus {
|
|
1393
1848
|
/** Job ID */
|
|
1394
1849
|
jobId: string;
|
|
1395
|
-
/** Job key within the workflow */
|
|
1396
|
-
key
|
|
1850
|
+
/** Job key within the workflow; undefined, see {@link WorkflowJob.key} */
|
|
1851
|
+
key?: string;
|
|
1397
1852
|
/** Current status */
|
|
1398
1853
|
status: string;
|
|
1399
1854
|
/** Progress percentage (0-100) */
|
|
@@ -1415,7 +1870,7 @@ interface WorkflowJobOperations {
|
|
|
1415
1870
|
* @example
|
|
1416
1871
|
* ```typescript
|
|
1417
1872
|
* const jobs = await client.workflows.jobs.list('wf_123');
|
|
1418
|
-
* console.log('Jobs:', jobs.map(j => j.
|
|
1873
|
+
* console.log('Jobs:', jobs.map(j => j.id));
|
|
1419
1874
|
* ```
|
|
1420
1875
|
*/
|
|
1421
1876
|
list(workflowId: string): Promise<WorkflowJob[]>;
|
|
@@ -1434,14 +1889,16 @@ interface WorkflowJobOperations {
|
|
|
1434
1889
|
/**
|
|
1435
1890
|
* Get the status of all jobs in a workflow.
|
|
1436
1891
|
*
|
|
1437
|
-
* Returns a summary of each job's status
|
|
1892
|
+
* Returns a summary of each job's status. The API does not store or return
|
|
1893
|
+
* the `key` a job was created with, so `key` is undefined; map keys to job
|
|
1894
|
+
* IDs from the `jobIds` array that `workflows.create()` returns.
|
|
1438
1895
|
*
|
|
1439
1896
|
* @param workflowId - The workflow ID
|
|
1440
1897
|
* @example
|
|
1441
1898
|
* ```typescript
|
|
1442
1899
|
* const statuses = await client.workflows.jobs.getStatus('wf_123');
|
|
1443
1900
|
* for (const s of statuses) {
|
|
1444
|
-
* console.log(`${s.
|
|
1901
|
+
* console.log(`${s.jobId}: ${s.status}`);
|
|
1445
1902
|
* }
|
|
1446
1903
|
* ```
|
|
1447
1904
|
*/
|
|
@@ -1538,6 +1995,12 @@ interface OutgoingWebhook {
|
|
|
1538
1995
|
* it is re-enabled with `update(id, { enabled: true })`.
|
|
1539
1996
|
*/
|
|
1540
1997
|
lastStatus?: "success" | "failed" | "auto_disabled";
|
|
1998
|
+
/**
|
|
1999
|
+
* Body format of the deliveries (API 0.1.122+; absent from older servers,
|
|
2000
|
+
* which only send `json`). A format newer than this SDK is passed through
|
|
2001
|
+
* as a string.
|
|
2002
|
+
*/
|
|
2003
|
+
format?: WebhookFormat | (string & {});
|
|
1541
2004
|
createdAt: string;
|
|
1542
2005
|
updatedAt: string;
|
|
1543
2006
|
}
|
|
@@ -1553,6 +2016,11 @@ interface CreateOutgoingWebhookParams {
|
|
|
1553
2016
|
secret?: string;
|
|
1554
2017
|
/** Whether enabled (default: true) */
|
|
1555
2018
|
enabled?: boolean;
|
|
2019
|
+
/**
|
|
2020
|
+
* Body format (default `json`; API 0.1.122+). `slack`, `discord` and
|
|
2021
|
+
* `teams` post a chat message to that service's incoming-webhook URL.
|
|
2022
|
+
*/
|
|
2023
|
+
format?: WebhookFormat;
|
|
1556
2024
|
}
|
|
1557
2025
|
/**
|
|
1558
2026
|
* Parameters for updating an outgoing webhook.
|
|
@@ -1583,6 +2051,8 @@ interface UpdateOutgoingWebhookParams {
|
|
|
1583
2051
|
* `QUOTA_EXCEEDED` even though no webhook is being created.
|
|
1584
2052
|
*/
|
|
1585
2053
|
enabled?: boolean;
|
|
2054
|
+
/** New body format; omit it to keep the current one (API 0.1.122+). */
|
|
2055
|
+
format?: WebhookFormat;
|
|
1586
2056
|
}
|
|
1587
2057
|
/** Response for webhook test */
|
|
1588
2058
|
interface TestWebhookResponse {
|
|
@@ -1951,14 +2421,12 @@ declare class OrganizationsResource {
|
|
|
1951
2421
|
/**
|
|
1952
2422
|
* Clear/delete the webhook token for the current organization.
|
|
1953
2423
|
*
|
|
1954
|
-
*
|
|
1955
|
-
*
|
|
1956
|
-
*
|
|
1957
|
-
*
|
|
1958
|
-
* @
|
|
1959
|
-
*
|
|
1960
|
-
* await client.organizations.clearWebhookToken();
|
|
1961
|
-
* ```
|
|
2424
|
+
* @deprecated The API refuses this operation on purpose (an org without a
|
|
2425
|
+
* webhook token would have an open public ingestion endpoint) and always
|
|
2426
|
+
* answers with an error. This method now throws
|
|
2427
|
+
* {@link UnsupportedOperationError} without a network call; rotate the token
|
|
2428
|
+
* with {@link OrganizationsResource.regenerateWebhookToken} instead. It will
|
|
2429
|
+
* be removed in the next major release.
|
|
1962
2430
|
*/
|
|
1963
2431
|
clearWebhookToken(): Promise<void>;
|
|
1964
2432
|
}
|
|
@@ -2271,8 +2739,9 @@ declare class AdminResource {
|
|
|
2271
2739
|
/**
|
|
2272
2740
|
* Webhook Ingestion Types
|
|
2273
2741
|
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2742
|
+
* The custom endpoint is called by external webhook providers and is
|
|
2743
|
+
* authenticated by the org webhook token (not an API key). The GitHub and
|
|
2744
|
+
* Stripe option types are kept only so existing code still compiles.
|
|
2276
2745
|
*/
|
|
2277
2746
|
|
|
2278
2747
|
interface IngestCustomWebhookParams {
|
|
@@ -2288,6 +2757,39 @@ interface IngestCustomWebhookResponse {
|
|
|
2288
2757
|
queueName?: string;
|
|
2289
2758
|
status?: string;
|
|
2290
2759
|
}
|
|
2760
|
+
/** `status` of an inbound webhook log entry */
|
|
2761
|
+
type InboundDeliveryStatus = "created" | "duplicate";
|
|
2762
|
+
/** Parameters for `ingest.listDeliveries()` (`GET /webhooks/deliveries`) */
|
|
2763
|
+
interface ListInboundDeliveriesParams extends PaginationParams {
|
|
2764
|
+
/** `created` (a new job) or `duplicate` (an idempotent replay) */
|
|
2765
|
+
status?: InboundDeliveryStatus;
|
|
2766
|
+
/**
|
|
2767
|
+
* Only entries received at or after this instant. A `Date` is sent as an
|
|
2768
|
+
* ISO 8601 UTC string; a string must be RFC 3339.
|
|
2769
|
+
*/
|
|
2770
|
+
since?: Date | string;
|
|
2771
|
+
/** Only entries whose job went to this queue (exact match) */
|
|
2772
|
+
queueName?: string;
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* One accepted request to `POST /webhooks/{org_id}/custom`, from the inbound
|
|
2776
|
+
* webhook log (API 0.1.122+). The log never holds the payload or a signature.
|
|
2777
|
+
*/
|
|
2778
|
+
interface InboundWebhookDelivery {
|
|
2779
|
+
id: string;
|
|
2780
|
+
/** `custom` today */
|
|
2781
|
+
provider: string;
|
|
2782
|
+
/** The request's event type, `custom` when it had none */
|
|
2783
|
+
eventType: string;
|
|
2784
|
+
/** Queue of the job the request resolved to */
|
|
2785
|
+
matchedQueue: string | null;
|
|
2786
|
+
/** Job the request created or matched (`null` for entries before 0.1.122) */
|
|
2787
|
+
jobId: string | null;
|
|
2788
|
+
/** `created` or `duplicate` (`null` for entries before 0.1.122) */
|
|
2789
|
+
status: InboundDeliveryStatus | (string & {}) | null;
|
|
2790
|
+
createdAt: string;
|
|
2791
|
+
}
|
|
2792
|
+
/** @deprecated The API has no GitHub webhook route; `ingest.github` throws. */
|
|
2291
2793
|
interface IngestGitHubWebhookOptions {
|
|
2292
2794
|
/** Value for X-GitHub-Event header (e.g. "pull_request") */
|
|
2293
2795
|
githubEvent: string;
|
|
@@ -2300,6 +2802,7 @@ interface IngestGitHubWebhookOptions {
|
|
|
2300
2802
|
/** If provided, the SDK will compute the signature for you */
|
|
2301
2803
|
secret?: string;
|
|
2302
2804
|
}
|
|
2805
|
+
/** @deprecated The API has no Stripe webhook route; `ingest.stripe` throws. */
|
|
2303
2806
|
interface IngestStripeWebhookOptions {
|
|
2304
2807
|
/** Optional org-scoped webhook token (X-Webhook-Token) */
|
|
2305
2808
|
webhookToken?: string;
|
|
@@ -2316,8 +2819,9 @@ interface IngestStripeWebhookOptions {
|
|
|
2316
2819
|
/**
|
|
2317
2820
|
* Webhook Ingestion Resource
|
|
2318
2821
|
*
|
|
2319
|
-
*
|
|
2320
|
-
*
|
|
2822
|
+
* The Spooled API ingests webhooks on one route:
|
|
2823
|
+
* `POST /api/v1/webhooks/{org_id}/custom`, authenticated by the org's webhook
|
|
2824
|
+
* token. The GitHub and Stripe routes were removed from the API.
|
|
2321
2825
|
*/
|
|
2322
2826
|
|
|
2323
2827
|
declare class WebhookIngestionResource {
|
|
@@ -2326,15 +2830,23 @@ declare class WebhookIngestionResource {
|
|
|
2326
2830
|
/**
|
|
2327
2831
|
* Ingest a GitHub webhook.
|
|
2328
2832
|
*
|
|
2329
|
-
*
|
|
2833
|
+
* @deprecated The API has no `/webhooks/{org_id}/github` route (it always
|
|
2834
|
+
* answered 404). This method now throws {@link UnsupportedOperationError}
|
|
2835
|
+
* without a network call; point the GitHub webhook at `ingest.custom` /
|
|
2836
|
+
* `POST /api/v1/webhooks/{org_id}/custom` instead. It will be removed in the
|
|
2837
|
+
* next major release.
|
|
2330
2838
|
*/
|
|
2331
|
-
github(
|
|
2839
|
+
github(_orgId: string, _body: string | Uint8Array | ArrayBuffer, _options: IngestGitHubWebhookOptions): Promise<void>;
|
|
2332
2840
|
/**
|
|
2333
2841
|
* Ingest a Stripe webhook.
|
|
2334
2842
|
*
|
|
2335
|
-
*
|
|
2843
|
+
* @deprecated The API has no `/webhooks/{org_id}/stripe` route (it always
|
|
2844
|
+
* answered 404). This method now throws {@link UnsupportedOperationError}
|
|
2845
|
+
* without a network call; point the Stripe webhook at `ingest.custom` /
|
|
2846
|
+
* `POST /api/v1/webhooks/{org_id}/custom` instead. It will be removed in the
|
|
2847
|
+
* next major release.
|
|
2336
2848
|
*/
|
|
2337
|
-
stripe(
|
|
2849
|
+
stripe(_orgId: string, _body: string | Uint8Array | ArrayBuffer, _options?: IngestStripeWebhookOptions): Promise<void>;
|
|
2338
2850
|
/**
|
|
2339
2851
|
* Ingest a custom webhook.
|
|
2340
2852
|
*
|
|
@@ -2345,6 +2857,17 @@ declare class WebhookIngestionResource {
|
|
|
2345
2857
|
webhookToken?: string;
|
|
2346
2858
|
forwardedProto?: string;
|
|
2347
2859
|
}): Promise<IngestCustomWebhookResponse>;
|
|
2860
|
+
/**
|
|
2861
|
+
* The inbound webhook log: accepted requests to
|
|
2862
|
+
* `POST /webhooks/{org_id}/custom`, newest first
|
|
2863
|
+
* (`GET /webhooks/deliveries`, API 0.1.122+).
|
|
2864
|
+
*
|
|
2865
|
+
* Needs an API key without a queue restriction (a queue-scoped key gets a
|
|
2866
|
+
* 403 `AuthorizationError`). Entries carry no payload and no signature;
|
|
2867
|
+
* requests that were rejected are not logged. `limit` defaults to 50 (at
|
|
2868
|
+
* most 100); an invalid filter is a 400 `ValidationError`.
|
|
2869
|
+
*/
|
|
2870
|
+
listDeliveries(params?: ListInboundDeliveriesParams): Promise<InboundWebhookDelivery[]>;
|
|
2348
2871
|
}
|
|
2349
2872
|
|
|
2350
2873
|
/**
|
|
@@ -2758,8 +3281,11 @@ interface GrpcCompleteRequest {
|
|
|
2758
3281
|
workerId: string;
|
|
2759
3282
|
/** Result as object (will be converted to google.protobuf.Struct) */
|
|
2760
3283
|
result?: Record<string, unknown>;
|
|
2761
|
-
/**
|
|
2762
|
-
|
|
3284
|
+
/**
|
|
3285
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
3286
|
+
* server rejects a settlement without it with INVALID_ARGUMENT.
|
|
3287
|
+
*/
|
|
3288
|
+
leaseId: string;
|
|
2763
3289
|
}
|
|
2764
3290
|
/** Complete response */
|
|
2765
3291
|
interface GrpcCompleteResponse {
|
|
@@ -2770,9 +3296,20 @@ interface GrpcFailRequest {
|
|
|
2770
3296
|
jobId: string;
|
|
2771
3297
|
workerId: string;
|
|
2772
3298
|
error: string;
|
|
3299
|
+
/**
|
|
3300
|
+
* Retry the job (until its `maxRetries` run out) instead of dead-lettering it
|
|
3301
|
+
* at once. Defaults to `true`, which the SDK sends explicitly, so servers
|
|
3302
|
+
* from before proto field 4 became `optional bool` (where an absent field
|
|
3303
|
+
* read as `false` and dead-lettered the job on its first failure) behave the
|
|
3304
|
+
* same. Pass `false` to dead-letter the job now, whatever `maxRetries` says:
|
|
3305
|
+
* the SDK puts `retry = false` on the wire with field presence.
|
|
3306
|
+
*/
|
|
2773
3307
|
retry?: boolean;
|
|
2774
|
-
/**
|
|
2775
|
-
|
|
3308
|
+
/**
|
|
3309
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
3310
|
+
* server rejects a settlement without it with INVALID_ARGUMENT.
|
|
3311
|
+
*/
|
|
3312
|
+
leaseId: string;
|
|
2776
3313
|
}
|
|
2777
3314
|
/** Fail response */
|
|
2778
3315
|
interface GrpcFailResponse {
|
|
@@ -2785,8 +3322,11 @@ interface GrpcRenewLeaseRequest {
|
|
|
2785
3322
|
jobId: string;
|
|
2786
3323
|
workerId: string;
|
|
2787
3324
|
extensionSecs: number;
|
|
2788
|
-
/**
|
|
2789
|
-
|
|
3325
|
+
/**
|
|
3326
|
+
* Lease fencing token from the dequeued job (proto `lease_id`). Required: the
|
|
3327
|
+
* server rejects a renewal without it with INVALID_ARGUMENT.
|
|
3328
|
+
*/
|
|
3329
|
+
leaseId: string;
|
|
2790
3330
|
}
|
|
2791
3331
|
/** Renew lease response */
|
|
2792
3332
|
interface GrpcRenewLeaseResponse {
|
|
@@ -2851,6 +3391,17 @@ interface GrpcRegisterWorkerRequest {
|
|
|
2851
3391
|
maxConcurrency?: number;
|
|
2852
3392
|
version?: string;
|
|
2853
3393
|
metadata?: Record<string, string>;
|
|
3394
|
+
/**
|
|
3395
|
+
* Stable worker id (proto `optional string worker_id = 7`): 1-128
|
|
3396
|
+
* characters, letters, digits, `-`, `_` and `.`.
|
|
3397
|
+
*
|
|
3398
|
+
* Send the same id after a restart and the server updates that worker
|
|
3399
|
+
* instead of adding one, so a restarting worker does not count twice against
|
|
3400
|
+
* the plan's worker limit. Omitted or empty: the server assigns a new id. An
|
|
3401
|
+
* id that another organization already uses fails with ALREADY_EXISTS
|
|
3402
|
+
* (`ConflictError`). Servers older than API 0.1.119 ignore the field.
|
|
3403
|
+
*/
|
|
3404
|
+
workerId?: string;
|
|
2854
3405
|
}
|
|
2855
3406
|
/** Register worker response */
|
|
2856
3407
|
interface GrpcRegisterWorkerResponse {
|
|
@@ -3319,6 +3870,13 @@ declare class SpooledClient {
|
|
|
3319
3870
|
/**
|
|
3320
3871
|
* Exchange the API key for a JWT via /auth/login and cache the result.
|
|
3321
3872
|
*
|
|
3873
|
+
* The JWT belongs to the realtime transport only. It must NOT replace the
|
|
3874
|
+
* REST bearer: an API-key client has no refresh token wired into its HTTP
|
|
3875
|
+
* layer, so after the JWT's 24 h lifetime every REST call (claim, complete,
|
|
3876
|
+
* heartbeat, create) would have failed with 401 for good. REST keeps using
|
|
3877
|
+
* the API key; realtime re-mints its own JWT near expiry (see
|
|
3878
|
+
* `getJwtToken`).
|
|
3879
|
+
*
|
|
3322
3880
|
* Concurrent callers share a single in-flight login so a burst of reconnects
|
|
3323
3881
|
* (e.g. WebSocket and SSE at once) issues just one request.
|
|
3324
3882
|
*/
|
|
@@ -3339,6 +3897,15 @@ declare class SpooledClient {
|
|
|
3339
3897
|
* Get current configuration (read-only)
|
|
3340
3898
|
*/
|
|
3341
3899
|
getConfig(): Readonly<ResolvedConfig>;
|
|
3900
|
+
/**
|
|
3901
|
+
* Rate-limit state from the most recent response that carried
|
|
3902
|
+
* `X-RateLimit-*` headers (API 0.1.122+): `limit`, `remaining`, `reset`
|
|
3903
|
+
* (from the Unix-seconds header), `scope` and, after a 429, `retryAfter`.
|
|
3904
|
+
* `undefined` until such a response arrives, and for servers or routes that
|
|
3905
|
+
* do not send the headers. A 429 also carries the same values on
|
|
3906
|
+
* `RateLimitError.rateLimitInfo`.
|
|
3907
|
+
*/
|
|
3908
|
+
getRateLimitInfo(): RateLimitInfo | undefined;
|
|
3342
3909
|
/**
|
|
3343
3910
|
* Get circuit breaker statistics
|
|
3344
3911
|
*/
|
|
@@ -3416,7 +3983,10 @@ interface SpooledWorkerOptions {
|
|
|
3416
3983
|
version?: string;
|
|
3417
3984
|
/** Additional worker metadata */
|
|
3418
3985
|
metadata?: JsonObject;
|
|
3419
|
-
/**
|
|
3986
|
+
/**
|
|
3987
|
+
* Graceful shutdown timeout in ms (default: 30000): how long `stop()` lets
|
|
3988
|
+
* running handlers finish before aborting and failing them.
|
|
3989
|
+
*/
|
|
3420
3990
|
shutdownTimeout?: number;
|
|
3421
3991
|
}
|
|
3422
3992
|
/** Worker state */
|
|
@@ -3433,7 +4003,12 @@ interface JobContext {
|
|
|
3433
4003
|
retryCount: number;
|
|
3434
4004
|
/** Maximum retries */
|
|
3435
4005
|
maxRetries: number;
|
|
3436
|
-
/**
|
|
4006
|
+
/**
|
|
4007
|
+
* Abort signal. Aborted when the job exceeds its `timeoutSeconds` or when a
|
|
4008
|
+
* stop outlives `shutdownTimeout`; NOT aborted merely because a stop was
|
|
4009
|
+
* requested (the handler gets the grace period to finish and be acked).
|
|
4010
|
+
* `signal.reason` carries the cause.
|
|
4011
|
+
*/
|
|
3437
4012
|
signal: AbortSignal;
|
|
3438
4013
|
/** Log local job progress (0-100); backend progress persistence is not yet available. */
|
|
3439
4014
|
progress: (percent: number, message?: string) => Promise<void>;
|
|
@@ -3493,7 +4068,16 @@ interface ActiveJob {
|
|
|
3493
4068
|
job: ClaimedJob;
|
|
3494
4069
|
startedAt: Date;
|
|
3495
4070
|
heartbeatTimer?: ReturnType<typeof setInterval>;
|
|
4071
|
+
/** Fires when the job exceeds its `timeoutSeconds` */
|
|
4072
|
+
timeoutTimer?: ReturnType<typeof setTimeout>;
|
|
3496
4073
|
abortController: AbortController;
|
|
4074
|
+
/**
|
|
4075
|
+
* The outcome of this execution is decided (acked, or about to be): nothing
|
|
4076
|
+
* else may ack it. Set when the handler settles or the shutdown fails it.
|
|
4077
|
+
*/
|
|
4078
|
+
settled?: boolean;
|
|
4079
|
+
/** The complete/fail request for this execution, once started. */
|
|
4080
|
+
ack?: Promise<void>;
|
|
3497
4081
|
}
|
|
3498
4082
|
|
|
3499
4083
|
/**
|
|
@@ -3542,6 +4126,10 @@ declare class SpooledWorker {
|
|
|
3542
4126
|
private pollTimer;
|
|
3543
4127
|
private workerHeartbeatTimer;
|
|
3544
4128
|
private shutdownPromise;
|
|
4129
|
+
/** The claim request currently on the wire, so a stop can wait for its jobs. */
|
|
4130
|
+
private pollInFlight;
|
|
4131
|
+
/** Wakes the shutdown drain when the last active job has been acked. */
|
|
4132
|
+
private drainWaiter;
|
|
3545
4133
|
private eventHandlers;
|
|
3546
4134
|
constructor(client: SpooledClient, options: SpooledWorkerOptions);
|
|
3547
4135
|
/**
|
|
@@ -3565,7 +4153,15 @@ declare class SpooledWorker {
|
|
|
3565
4153
|
*/
|
|
3566
4154
|
start(): Promise<void>;
|
|
3567
4155
|
/**
|
|
3568
|
-
* Stop the worker gracefully
|
|
4156
|
+
* Stop the worker gracefully.
|
|
4157
|
+
*
|
|
4158
|
+
* Drains: the worker stops claiming, then lets running handlers finish for
|
|
4159
|
+
* up to `shutdownTimeout`. A handler that returns completes its job and one
|
|
4160
|
+
* that throws fails it, even though a stop was requested meanwhile; its
|
|
4161
|
+
* `signal` is NOT aborted during the grace period. Only handlers still
|
|
4162
|
+
* running when the timeout ends are aborted and failed with "Worker shutdown
|
|
4163
|
+
* timeout". The worker deregisters last, because deregistering returns every
|
|
4164
|
+
* job the worker still holds to the queue.
|
|
3569
4165
|
*/
|
|
3570
4166
|
stop(): Promise<void>;
|
|
3571
4167
|
private doStop;
|
|
@@ -3582,13 +4178,24 @@ declare class SpooledWorker {
|
|
|
3582
4178
|
private poll;
|
|
3583
4179
|
private processJob;
|
|
3584
4180
|
private executeHandler;
|
|
4181
|
+
/**
|
|
4182
|
+
* Run the handler, racing it against the job's `timeoutSeconds`.
|
|
4183
|
+
* Never rejects: a throw (sync or async) is reported as an outcome.
|
|
4184
|
+
*/
|
|
4185
|
+
private runHandler;
|
|
4186
|
+
/** Abort a handler that outlived the shutdown grace period and fail its job. */
|
|
4187
|
+
private abandonJob;
|
|
3585
4188
|
private completeJob;
|
|
3586
4189
|
private failJob;
|
|
4190
|
+
private clearTimeoutTimer;
|
|
3587
4191
|
private cleanupJob;
|
|
3588
4192
|
private sendJobHeartbeat;
|
|
3589
4193
|
private sendWorkerHeartbeat;
|
|
3590
|
-
|
|
3591
|
-
|
|
4194
|
+
/**
|
|
4195
|
+
* Resolve once no job is active, or after `timeoutMs`. The timer is always
|
|
4196
|
+
* cleared, so a clean stop leaves nothing that keeps the process alive.
|
|
4197
|
+
*/
|
|
4198
|
+
private waitForDrain;
|
|
3592
4199
|
}
|
|
3593
4200
|
|
|
3594
|
-
export { type
|
|
4201
|
+
export { type CreateJobParams as $, API_VERSION as A, type BatchJobStatus as B, type ConnectionState as C, type BillingStatus as D, type BoostPriorityResponse as E, type BulkEnqueueParams as F, type BulkEnqueueResponse as G, type BulkJobItem as H, type CheckEmailResponse as I, type CheckSlugResponse as J, CircuitBreaker as K, type CircuitBreakerConfig as L, CircuitBreakerOpenError as M, type CircuitBreakerOptions as N, CircuitState as O, type CircuitStateChange as P, type ClaimJobsParams as Q, type RealtimeConnectionOptions as R, type SubscriptionFilter as S, type ClaimJobsResult as T, type ClaimedJob as U, type CompleteJobParams as V, ConflictError as W, type CreateApiKeyParams as X, type CreateApiKeyResponse as Y, type CreateBillingPortalParams as Z, type CreateBillingPortalResponse as _, type RealtimeEventType as a, GrpcWorkerOperations as a$, type CreateJobResult as a0, type CreateOrganizationParams as a1, type CreateOrganizationResponse as a2, type CreateOutgoingWebhookParams as a3, type CreateScheduleParams as a4, type CreateScheduleResponse as a5, type CreateWorkflowParams as a6, type CreateWorkflowResponse as a7, type CurrentUserResponse as a8, DEFAULT_CONFIG as a9, type GrpcFailRequest as aA, type GrpcFailResponse as aB, type GrpcGetJobRequest as aC, type GrpcGetJobResponse as aD, type GrpcGetQueueStatsRequest as aE, type GrpcGetQueueStatsResponse as aF, type GrpcGetQueueStatsResponse_Legacy as aG, type GrpcHeartbeatParams as aH, type GrpcHeartbeatRequest as aI, type GrpcHeartbeatResponse as aJ, type GrpcHeartbeatResponse_Legacy as aK, type GrpcJob as aL, GrpcJobStatus as aM, GrpcJobStatusNumber as aN, type GrpcProcessRequest as aO, type GrpcProcessResponse as aP, GrpcQueueOperations as aQ, type GrpcRegisterWorkerParams as aR, type GrpcRegisterWorkerRequest as aS, type GrpcRegisterWorkerResponse as aT, type GrpcRegisterWorkerResponse_Legacy as aU, type GrpcRenewLeaseParams as aV, type GrpcRenewLeaseRequest as aW, type GrpcRenewLeaseResponse as aX, type GrpcRenewLeaseResponse_Legacy as aY, type GrpcStreamJobsRequest as aZ, type GrpcTimestamp as a_, type DashboardData as aa, DashboardResource as ab, type DashboardWorkerSummary as ac, type DebugFn as ad, type DeleteQueueOptions as ae, type DependencyInfo as af, type DependencyMode as ag, type FailJobParams as ah, type GrpcClientOptions as ai, type GrpcCompleteJobParams as aj, type GrpcCompleteJobResponse as ak, type GrpcCompleteRequest as al, type GrpcCompleteResponse as am, type GrpcDequeueJobParams as an, type GrpcDequeueJobResponse as ao, type GrpcDequeueRequest as ap, type GrpcDequeueResponse as aq, type GrpcDeregisterRequest as ar, type GrpcDeregisterResponse as as, type GrpcEnqueueJobParams as at, type GrpcEnqueueJobResponse as au, type GrpcEnqueueRequest as av, type GrpcEnqueueResponse as aw, type GrpcErrorResponse as ax, type GrpcFailJobParams as ay, type GrpcFailJobResponse as az, type RealtimeEvent as b, type ProcessJobsStream as b$, HealthResource as b0, type HealthResponse as b1, type HeartbeatEvent as b2, type HeartbeatJobParams as b3, HttpClient as b4, type InboundDeliveryStatus as b5, type InboundWebhookDelivery as b6, type IngestCustomWebhookParams as b7, type IngestCustomWebhookResponse as b8, type IngestGitHubWebhookOptions as b9, type JsonValue as bA, type ListDlqParams as bB, type ListInboundDeliveriesParams as bC, type ListJobsParams as bD, type ListPage as bE, type ListParams as bF, type ListSchedulesParams as bG, type ListWorkflowsParams as bH, type LoginParams as bI, type LoginResponse as bJ, MetricsResource as bK, NetworkError as bL, NotFoundError as bM, type Organization as bN, type OrganizationMember as bO, type OrganizationSummary as bP, type OrganizationUsage as bQ, OrganizationsResource as bR, type OutgoingWebhook as bS, type OutgoingWebhookDelivery as bT, type PaginatedResponse as bU, type PaginationParams as bV, type PauseQueueResponse as bW, PayloadTooLargeError as bX, type PlanCount as bY, type PlanLimits as bZ, type PlanTier as b_, type IngestStripeWebhookOptions as ba, type InitialApiKey as bb, type Job as bc, type JobCompletedEvent as bd, type JobContext as be, type JobCreatedEvent as bf, type JobFailedEvent as bg, type JobHandler as bh, type JobHistoryEvent as bi, type JobHistoryEventType as bj, type JobHistoryParams as bk, type JobProgressEvent as bl, type JobResult as bm, type JobSearchParams as bn, type JobStartedEvent as bo, type JobStats as bp, type JobStatus as bq, type JobStatusChangedEvent as br, type JobStream as bs, type JobSummary as bt, type JobSummaryStats as bu, type JobWithDependencies as bv, JobsResource as bw, type JsonArray as bx, type JsonObject as by, type JsonPrimitive as bz, type RetryConfig as c, type WorkerEvent as c$, type PurgeDlqParams as c0, type PurgeDlqResponse as c1, type QueueConfig as c2, type QueueConfigSummary as c3, type QueuePausedEvent as c4, type QueueResumedEvent as c5, type QueueStats as c6, type QueueSummary as c7, QueuesResource as c8, RateLimitError as c9, type SpooledWorkerOptions as cA, type StartEmailLoginResponse as cB, type StreamOptions as cC, type SystemInfo as cD, type TestWebhookResponse as cE, TimeoutError as cF, type TokenClaims as cG, type TriggerScheduleResponse as cH, UnsupportedOperationError as cI, type UpdateApiKeyParams as cJ, type UpdateOrganizationParams as cK, type UpdateOutgoingWebhookParams as cL, type UpdateQueueConfigParams as cM, type UpdateScheduleParams as cN, type UsageItem as cO, type UsageWarning as cP, type ValidateTokenParams as cQ, type ValidateTokenResponse as cR, ValidationError as cS, type WebhookDeliveryStatus as cT, type WebhookEventType as cU, type WebhookFormat as cV, WebhookIngestionResource as cW, type WebhookTokenResponse as cX, WebhooksResource as cY, type Worker as cZ, type WorkerDeregisteredEvent as c_, type RateLimitInfo as ca, type RealtimeEventData as cb, type RecentActivity as cc, type RefreshTokenParams as cd, type RefreshTokenResponse as ce, type RegisterWorkerParams as cf, type RegisterWorkerResponse as cg, type ResolvedConfig as ch, type ResourceUsage as ci, type ResumeQueueResponse as cj, type RetryDlqParams as ck, type RetryDlqResponse as cl, SDK_VERSION as cm, type Schedule as cn, type ScheduleRun as co, type ScheduleRunStatus as cp, type ScheduleTriggeredEvent as cq, SchedulesResource as cr, ServerError as cs, SpooledClient as ct, type SpooledClientConfig as cu, SpooledError as cv, SpooledGrpcClient as cw, SpooledRealtime as cx, type SpooledRealtimeOptions as cy, SpooledWorker as cz, type AddDependenciesParams as d, type WorkerEventData as d0, type WorkerHeartbeatParams as d1, type WorkerRegisteredEvent as d2, type WorkerState as d3, type WorkerStatus as d4, type WorkerSummary as d5, WorkersResource as d6, type Workflow as d7, type WorkflowJob as d8, type WorkflowJobDefinition as d9, type WorkflowJobStatus as da, type WorkflowResponse as db, type WorkflowStatus as dc, WorkflowsResource as dd, asyncIterableFromStream as de, createCircuitBreaker as df, createClient as dg, createErrorFromResponse as dh, createHttpClient as di, createJobStream as dj, createPaginatedResponse as dk, createProcessJobsStream as dl, dateToTimestamp as dm, isCircuitBreakerFailure as dn, isRetryableError as dp, isSpooledError as dq, parseRateLimitHeaders as dr, resolveConfig as ds, timestampToDate as dt, validateConfig as du, type ActiveJob as dv, type AddDependenciesResponse as e, type AdminApiKeyResponse as f, type AdminCreateApiKeyParams as g, type AdminCreateOrganizationParams as h, type AdminCreateOrganizationResponse as i, type AdminDeleteOrganizationParams as j, type AdminListOrganizationsParams as k, type AdminOrganizationDetail as l, type AdminOrganizationList as m, type AdminOrganizationSummary as n, type AdminPlanLimits as o, type AdminPlatformStats as p, AdminResource as q, type AdminUpdateOrganizationParams as r, type AdminUsageStats as s, type ApiErrorBody as t, type ApiKeySummary as u, ApiKeysResource as v, AuthResource as w, AuthenticationError as x, AuthorizationError as y, BillingResource as z };
|