@spooled/sdk 1.0.31 → 1.0.33
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 +10 -6
- package/dist/{index-CfLL1w6Y.d.cts → index-QIsnz4Bc.d.cts} +23 -3
- package/dist/{index-CfLL1w6Y.d.ts → index-QIsnz4Bc.d.ts} +23 -3
- package/dist/index.cjs +90 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -8
- package/dist/index.d.ts +18 -8
- package/dist/index.js +90 -72
- package/dist/index.js.map +1 -1
- package/dist/worker/index.d.cts +1 -1
- package/dist/worker/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,7 +157,7 @@ Run jobs on a cron schedule:
|
|
|
157
157
|
```typescript
|
|
158
158
|
const schedule = await client.schedules.create({
|
|
159
159
|
name: 'Daily Report',
|
|
160
|
-
cronExpression: '0
|
|
160
|
+
cronExpression: '0 9 * * *', // 9 AM daily; 5-field (min hour dom mon dow) or 6-field (leading seconds) both work
|
|
161
161
|
timezone: 'America/New_York',
|
|
162
162
|
queueName: 'reports',
|
|
163
163
|
payloadTemplate: { type: 'daily' },
|
|
@@ -320,22 +320,25 @@ All operations automatically enforce tier-based limits:
|
|
|
320
320
|
- ✅ Queue creation
|
|
321
321
|
- ✅ Webhook creation
|
|
322
322
|
|
|
323
|
-
When
|
|
323
|
+
When a plan quota or limit is exceeded, you'll receive an `HTTP 429` response with
|
|
324
|
+
`code: "QUOTA_EXCEEDED"` and a body describing the `resource`, `current`, `limit`, and `plan`:
|
|
324
325
|
|
|
325
326
|
```typescript
|
|
326
|
-
import {
|
|
327
|
+
import { RateLimitError } from '@spooled/sdk';
|
|
327
328
|
|
|
328
329
|
try {
|
|
329
330
|
await client.jobs.create({ /* ... */ });
|
|
330
331
|
} catch (error) {
|
|
331
|
-
if (error instanceof
|
|
332
|
-
// Plan
|
|
332
|
+
if (error instanceof RateLimitError && error.code === 'QUOTA_EXCEEDED') {
|
|
333
|
+
// Plan quota reached (HTTP 429); details carry resource/current/limit/plan
|
|
333
334
|
console.log(`Plan limit: ${error.message}`);
|
|
334
335
|
console.log('Details:', error.details);
|
|
335
336
|
}
|
|
336
337
|
}
|
|
337
338
|
```
|
|
338
339
|
|
|
340
|
+
(Per-second rate limiting also returns `429`, as a `RateLimitError` with the default `RATE_LIMIT_EXCEEDED` code.)
|
|
341
|
+
|
|
339
342
|
## Error Handling
|
|
340
343
|
|
|
341
344
|
All errors extend `SpooledError` with specific subclasses:
|
|
@@ -355,8 +358,9 @@ try {
|
|
|
355
358
|
if (error instanceof NotFoundError) {
|
|
356
359
|
console.log('Job not found');
|
|
357
360
|
} else if (error instanceof AuthorizationError) {
|
|
358
|
-
console.log(`Forbidden
|
|
361
|
+
console.log(`Forbidden: ${error.message}`);
|
|
359
362
|
} else if (error instanceof RateLimitError) {
|
|
363
|
+
// 429: either a plan quota (code "QUOTA_EXCEEDED") or per-second rate limiting
|
|
360
364
|
console.log(`Retry after ${error.getRetryAfter()} seconds`);
|
|
361
365
|
} else if (isSpooledError(error)) {
|
|
362
366
|
console.log(`API error: ${error.code} - ${error.message}`);
|
|
@@ -107,11 +107,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
107
|
successThreshold: number;
|
|
108
108
|
timeout: number;
|
|
109
109
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.0.
|
|
110
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.0.33";
|
|
111
111
|
readonly autoRefreshToken: true;
|
|
112
112
|
};
|
|
113
113
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.0.
|
|
114
|
+
declare const SDK_VERSION = "1.0.33";
|
|
115
115
|
/** API version prefix */
|
|
116
116
|
declare const API_VERSION = "v1";
|
|
117
117
|
/**
|
|
@@ -2315,6 +2315,26 @@ interface JobStatusChangedEvent extends RealtimeEventBase {
|
|
|
2315
2315
|
newStatus: JobStatus;
|
|
2316
2316
|
};
|
|
2317
2317
|
}
|
|
2318
|
+
/** Queue stats update event (backend `QueueStats`) */
|
|
2319
|
+
interface QueueStatsEvent extends RealtimeEventBase {
|
|
2320
|
+
type: 'queue.stats';
|
|
2321
|
+
data: {
|
|
2322
|
+
queueName: string;
|
|
2323
|
+
pending: number;
|
|
2324
|
+
processing: number;
|
|
2325
|
+
completed: number;
|
|
2326
|
+
failed: number;
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
/** Worker heartbeat event (backend `WorkerHeartbeat`) */
|
|
2330
|
+
interface WorkerHeartbeatEvent extends RealtimeEventBase {
|
|
2331
|
+
type: 'worker.heartbeat';
|
|
2332
|
+
data: {
|
|
2333
|
+
workerId: string;
|
|
2334
|
+
status: string;
|
|
2335
|
+
currentJobId?: string;
|
|
2336
|
+
};
|
|
2337
|
+
}
|
|
2318
2338
|
/** Queue paused event */
|
|
2319
2339
|
interface QueuePausedEvent extends RealtimeEventBase {
|
|
2320
2340
|
type: 'queue.paused';
|
|
@@ -2363,7 +2383,7 @@ interface HeartbeatEvent extends RealtimeEventBase {
|
|
|
2363
2383
|
};
|
|
2364
2384
|
}
|
|
2365
2385
|
/** All realtime event types */
|
|
2366
|
-
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2386
|
+
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueueStatsEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | WorkerHeartbeatEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2367
2387
|
/** Event type names */
|
|
2368
2388
|
type RealtimeEventType = RealtimeEvent['type'];
|
|
2369
2389
|
/** Extract event data type from event type name */
|
|
@@ -107,11 +107,11 @@ declare const DEFAULT_CONFIG: {
|
|
|
107
107
|
successThreshold: number;
|
|
108
108
|
timeout: number;
|
|
109
109
|
};
|
|
110
|
-
readonly userAgent: "@spooled/sdk-nodejs/1.0.
|
|
110
|
+
readonly userAgent: "@spooled/sdk-nodejs/1.0.33";
|
|
111
111
|
readonly autoRefreshToken: true;
|
|
112
112
|
};
|
|
113
113
|
/** SDK version */
|
|
114
|
-
declare const SDK_VERSION = "1.0.
|
|
114
|
+
declare const SDK_VERSION = "1.0.33";
|
|
115
115
|
/** API version prefix */
|
|
116
116
|
declare const API_VERSION = "v1";
|
|
117
117
|
/**
|
|
@@ -2315,6 +2315,26 @@ interface JobStatusChangedEvent extends RealtimeEventBase {
|
|
|
2315
2315
|
newStatus: JobStatus;
|
|
2316
2316
|
};
|
|
2317
2317
|
}
|
|
2318
|
+
/** Queue stats update event (backend `QueueStats`) */
|
|
2319
|
+
interface QueueStatsEvent extends RealtimeEventBase {
|
|
2320
|
+
type: 'queue.stats';
|
|
2321
|
+
data: {
|
|
2322
|
+
queueName: string;
|
|
2323
|
+
pending: number;
|
|
2324
|
+
processing: number;
|
|
2325
|
+
completed: number;
|
|
2326
|
+
failed: number;
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
/** Worker heartbeat event (backend `WorkerHeartbeat`) */
|
|
2330
|
+
interface WorkerHeartbeatEvent extends RealtimeEventBase {
|
|
2331
|
+
type: 'worker.heartbeat';
|
|
2332
|
+
data: {
|
|
2333
|
+
workerId: string;
|
|
2334
|
+
status: string;
|
|
2335
|
+
currentJobId?: string;
|
|
2336
|
+
};
|
|
2337
|
+
}
|
|
2318
2338
|
/** Queue paused event */
|
|
2319
2339
|
interface QueuePausedEvent extends RealtimeEventBase {
|
|
2320
2340
|
type: 'queue.paused';
|
|
@@ -2363,7 +2383,7 @@ interface HeartbeatEvent extends RealtimeEventBase {
|
|
|
2363
2383
|
};
|
|
2364
2384
|
}
|
|
2365
2385
|
/** All realtime event types */
|
|
2366
|
-
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2386
|
+
type RealtimeEvent = JobCreatedEvent | JobStartedEvent | JobCompletedEvent | JobFailedEvent | JobProgressEvent | JobStatusChangedEvent | QueueStatsEvent | QueuePausedEvent | QueueResumedEvent | WorkerRegisteredEvent | WorkerDeregisteredEvent | WorkerHeartbeatEvent | ScheduleTriggeredEvent | HeartbeatEvent;
|
|
2367
2387
|
/** Event type names */
|
|
2368
2388
|
type RealtimeEventType = RealtimeEvent['type'];
|
|
2369
2389
|
/** Extract event data type from event type name */
|
package/dist/index.cjs
CHANGED
|
@@ -49,12 +49,19 @@ var DEFAULT_CONFIG = {
|
|
|
49
49
|
successThreshold: 3,
|
|
50
50
|
timeout: 3e4
|
|
51
51
|
},
|
|
52
|
-
userAgent: "@spooled/sdk-nodejs/1.0.
|
|
52
|
+
userAgent: "@spooled/sdk-nodejs/1.0.33",
|
|
53
53
|
autoRefreshToken: true
|
|
54
54
|
};
|
|
55
|
-
var SDK_VERSION = "1.0.
|
|
55
|
+
var SDK_VERSION = "1.0.33";
|
|
56
56
|
var API_VERSION = "v1";
|
|
57
57
|
var API_BASE_PATH = `/api/${API_VERSION}`;
|
|
58
|
+
function normalizeCredential(value) {
|
|
59
|
+
if (value === void 0) {
|
|
60
|
+
return void 0;
|
|
61
|
+
}
|
|
62
|
+
const trimmed = value.trim();
|
|
63
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
64
|
+
}
|
|
58
65
|
function resolveConfig(options) {
|
|
59
66
|
let debugFn = null;
|
|
60
67
|
if (options.debug === true) {
|
|
@@ -84,10 +91,10 @@ function resolveConfig(options) {
|
|
|
84
91
|
const derivedWsUrl = baseUrl.replace(/^http/, "ws");
|
|
85
92
|
const wsUrl = options.wsUrl ?? derivedWsUrl;
|
|
86
93
|
return {
|
|
87
|
-
apiKey: options.apiKey,
|
|
88
|
-
accessToken: options.accessToken,
|
|
89
|
-
refreshToken: options.refreshToken,
|
|
90
|
-
adminKey: options.adminKey,
|
|
94
|
+
apiKey: normalizeCredential(options.apiKey),
|
|
95
|
+
accessToken: normalizeCredential(options.accessToken),
|
|
96
|
+
refreshToken: normalizeCredential(options.refreshToken),
|
|
97
|
+
adminKey: normalizeCredential(options.adminKey),
|
|
91
98
|
baseUrl,
|
|
92
99
|
wsUrl,
|
|
93
100
|
grpcAddress: options.grpcAddress ?? DEFAULT_CONFIG.grpcAddress,
|
|
@@ -320,22 +327,33 @@ function parseRateLimitHeaders(headers) {
|
|
|
320
327
|
}
|
|
321
328
|
return info;
|
|
322
329
|
}
|
|
330
|
+
var MAX_RAW_ERROR_BODY_CHARS = 500;
|
|
323
331
|
async function parseErrorBody(response) {
|
|
324
332
|
const contentType = response.headers.get("Content-Type") || "";
|
|
325
|
-
|
|
333
|
+
let raw;
|
|
334
|
+
try {
|
|
335
|
+
raw = await response.text();
|
|
336
|
+
} catch {
|
|
326
337
|
return null;
|
|
327
338
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
339
|
+
if (contentType.includes("application/json")) {
|
|
340
|
+
try {
|
|
341
|
+
const body = JSON.parse(raw);
|
|
342
|
+
if (typeof body === "object" && body !== null) {
|
|
343
|
+
const message = (body.message ?? body.error) || response.statusText;
|
|
344
|
+
return {
|
|
345
|
+
code: body.code || "UNKNOWN_ERROR",
|
|
346
|
+
message,
|
|
347
|
+
details: body.details
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
} catch {
|
|
337
351
|
}
|
|
338
|
-
}
|
|
352
|
+
}
|
|
353
|
+
const trimmed = raw.trim();
|
|
354
|
+
if (trimmed) {
|
|
355
|
+
const message = trimmed.length > MAX_RAW_ERROR_BODY_CHARS ? `${trimmed.slice(0, MAX_RAW_ERROR_BODY_CHARS)}\u2026` : trimmed;
|
|
356
|
+
return { code: "UNKNOWN_ERROR", message };
|
|
339
357
|
}
|
|
340
358
|
return null;
|
|
341
359
|
}
|
|
@@ -1841,6 +1859,24 @@ var WebhookIngestionResource = class {
|
|
|
1841
1859
|
}
|
|
1842
1860
|
};
|
|
1843
1861
|
|
|
1862
|
+
// src/realtime/event-map.ts
|
|
1863
|
+
var BACKEND_EVENT_TYPE_MAP = {
|
|
1864
|
+
JobStatusChange: "job.status_changed",
|
|
1865
|
+
JobCreated: "job.created",
|
|
1866
|
+
JobCompleted: "job.completed",
|
|
1867
|
+
JobFailed: "job.failed",
|
|
1868
|
+
QueueStats: "queue.stats",
|
|
1869
|
+
WorkerHeartbeat: "worker.heartbeat",
|
|
1870
|
+
WorkerRegistered: "worker.registered",
|
|
1871
|
+
WorkerDeregistered: "worker.deregistered",
|
|
1872
|
+
SystemHealth: "system.health",
|
|
1873
|
+
Ping: "ping",
|
|
1874
|
+
Error: "error"
|
|
1875
|
+
};
|
|
1876
|
+
function mapEventType(type) {
|
|
1877
|
+
return BACKEND_EVENT_TYPE_MAP[type] ?? type;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1844
1880
|
// src/realtime/websocket.ts
|
|
1845
1881
|
var WebSocketRealtimeClient = class {
|
|
1846
1882
|
options;
|
|
@@ -1856,7 +1892,6 @@ var WebSocketRealtimeClient = class {
|
|
|
1856
1892
|
*/
|
|
1857
1893
|
authFailure = false;
|
|
1858
1894
|
subscriptions = /* @__PURE__ */ new Map();
|
|
1859
|
-
pendingCommands = /* @__PURE__ */ new Map();
|
|
1860
1895
|
// Event handlers
|
|
1861
1896
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
1862
1897
|
allEventsHandlers = /* @__PURE__ */ new Set();
|
|
@@ -1961,10 +1996,13 @@ var WebSocketRealtimeClient = class {
|
|
|
1961
1996
|
}
|
|
1962
1997
|
this.setState("disconnected");
|
|
1963
1998
|
this.subscriptions.clear();
|
|
1964
|
-
this.clearPendingCommands();
|
|
1965
1999
|
}
|
|
1966
2000
|
/**
|
|
1967
|
-
* Subscribe to events matching a filter
|
|
2001
|
+
* Subscribe to events matching a filter.
|
|
2002
|
+
*
|
|
2003
|
+
* The server applies filtering itself and sends no acknowledgement, so this
|
|
2004
|
+
* resolves as soon as the command has been written to the socket. The filter
|
|
2005
|
+
* is tracked locally so it is replayed automatically on reconnect.
|
|
1968
2006
|
*/
|
|
1969
2007
|
async subscribe(filter) {
|
|
1970
2008
|
const filterId = this.filterToId(filter);
|
|
@@ -1973,11 +2011,13 @@ var WebSocketRealtimeClient = class {
|
|
|
1973
2011
|
}
|
|
1974
2012
|
this.subscriptions.set(filterId, filter);
|
|
1975
2013
|
if (this.state === "connected") {
|
|
1976
|
-
|
|
2014
|
+
this.sendCommand("Subscribe", filter);
|
|
1977
2015
|
}
|
|
1978
2016
|
}
|
|
1979
2017
|
/**
|
|
1980
|
-
* Unsubscribe from events matching a filter
|
|
2018
|
+
* Unsubscribe from events matching a filter.
|
|
2019
|
+
*
|
|
2020
|
+
* Fire-and-forget, like {@link subscribe} — the server sends no ack.
|
|
1981
2021
|
*/
|
|
1982
2022
|
async unsubscribe(filter) {
|
|
1983
2023
|
const filterId = this.filterToId(filter);
|
|
@@ -1986,7 +2026,7 @@ var WebSocketRealtimeClient = class {
|
|
|
1986
2026
|
}
|
|
1987
2027
|
this.subscriptions.delete(filterId);
|
|
1988
2028
|
if (this.state === "connected") {
|
|
1989
|
-
|
|
2029
|
+
this.sendCommand("Unsubscribe", filter);
|
|
1990
2030
|
}
|
|
1991
2031
|
}
|
|
1992
2032
|
/**
|
|
@@ -2039,13 +2079,11 @@ var WebSocketRealtimeClient = class {
|
|
|
2039
2079
|
handleMessage(data) {
|
|
2040
2080
|
try {
|
|
2041
2081
|
const message = convertResponse(JSON.parse(data));
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
return;
|
|
2045
|
-
}
|
|
2082
|
+
const eventType = mapEventType(String(message.type));
|
|
2083
|
+
message.type = eventType;
|
|
2046
2084
|
const event = message;
|
|
2047
|
-
this.options.debug(`Received event: ${
|
|
2048
|
-
const handlers = this.eventHandlers.get(
|
|
2085
|
+
this.options.debug(`Received event: ${eventType}`, event);
|
|
2086
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
2049
2087
|
if (handlers) {
|
|
2050
2088
|
const eventData = event.data;
|
|
2051
2089
|
handlers.forEach((handler) => {
|
|
@@ -2067,25 +2105,8 @@ var WebSocketRealtimeClient = class {
|
|
|
2067
2105
|
this.options.debug("Failed to parse message", { data, error });
|
|
2068
2106
|
}
|
|
2069
2107
|
}
|
|
2070
|
-
handleCommandResponse(response) {
|
|
2071
|
-
if (!response.requestId) {
|
|
2072
|
-
return;
|
|
2073
|
-
}
|
|
2074
|
-
const pending = this.pendingCommands.get(response.requestId);
|
|
2075
|
-
if (!pending) {
|
|
2076
|
-
return;
|
|
2077
|
-
}
|
|
2078
|
-
clearTimeout(pending.timeout);
|
|
2079
|
-
this.pendingCommands.delete(response.requestId);
|
|
2080
|
-
if (response.type === "error") {
|
|
2081
|
-
pending.reject(new Error(response.error || "Unknown error"));
|
|
2082
|
-
} else {
|
|
2083
|
-
pending.resolve();
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
2108
|
handleDisconnect() {
|
|
2087
2109
|
this.ws = null;
|
|
2088
|
-
this.clearPendingCommands();
|
|
2089
2110
|
if (this.options.autoReconnect && this.reconnectAttempts < this.options.maxReconnectAttempts) {
|
|
2090
2111
|
this.scheduleReconnect();
|
|
2091
2112
|
} else {
|
|
@@ -2109,43 +2130,37 @@ var WebSocketRealtimeClient = class {
|
|
|
2109
2130
|
}
|
|
2110
2131
|
}, delay);
|
|
2111
2132
|
}
|
|
2112
|
-
|
|
2133
|
+
resubscribeAll() {
|
|
2113
2134
|
for (const filter of this.subscriptions.values()) {
|
|
2114
2135
|
try {
|
|
2115
|
-
|
|
2136
|
+
this.sendCommand("Subscribe", filter);
|
|
2116
2137
|
} catch (error) {
|
|
2117
2138
|
this.options.debug("Failed to resubscribe", { filter, error });
|
|
2118
2139
|
}
|
|
2119
2140
|
}
|
|
2120
2141
|
}
|
|
2121
|
-
|
|
2142
|
+
/**
|
|
2143
|
+
* Send a subscribe/unsubscribe command to the server.
|
|
2144
|
+
*
|
|
2145
|
+
* The backend `ClientCommand` shape is `{ cmd, queue, job_id }` and it sends
|
|
2146
|
+
* no acknowledgement, so this is fire-and-forget — it writes to the socket
|
|
2147
|
+
* and returns. The `SubscriptionFilter`'s `workerId`/`scheduleId` have no
|
|
2148
|
+
* server-side equivalent and are ignored.
|
|
2149
|
+
*/
|
|
2150
|
+
sendCommand(cmd, filter) {
|
|
2122
2151
|
if (!this.ws || this.state !== "connected") {
|
|
2123
2152
|
throw new Error("WebSocket not connected");
|
|
2124
2153
|
}
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}, 1e4);
|
|
2132
|
-
this.pendingCommands.set(requestId, { resolve, reject, timeout });
|
|
2133
|
-
this.ws.send(JSON.stringify(fullCommand));
|
|
2134
|
-
});
|
|
2135
|
-
}
|
|
2136
|
-
clearPendingCommands() {
|
|
2137
|
-
for (const pending of this.pendingCommands.values()) {
|
|
2138
|
-
clearTimeout(pending.timeout);
|
|
2139
|
-
pending.reject(new Error("Connection closed"));
|
|
2140
|
-
}
|
|
2141
|
-
this.pendingCommands.clear();
|
|
2154
|
+
const command = {
|
|
2155
|
+
cmd,
|
|
2156
|
+
queue: filter.queueName,
|
|
2157
|
+
job_id: filter.jobId
|
|
2158
|
+
};
|
|
2159
|
+
this.ws.send(JSON.stringify(command));
|
|
2142
2160
|
}
|
|
2143
2161
|
filterToId(filter) {
|
|
2144
2162
|
return JSON.stringify(filter);
|
|
2145
2163
|
}
|
|
2146
|
-
generateRequestId() {
|
|
2147
|
-
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
2148
|
-
}
|
|
2149
2164
|
};
|
|
2150
2165
|
function redactToken(url) {
|
|
2151
2166
|
return url.replace(/([?&](?:token|api_key)=)[^&]*/gi, "$1***");
|
|
@@ -2344,9 +2359,12 @@ var SseRealtimeClient = class {
|
|
|
2344
2359
|
}
|
|
2345
2360
|
handleMessage(data) {
|
|
2346
2361
|
try {
|
|
2347
|
-
const
|
|
2348
|
-
|
|
2349
|
-
|
|
2362
|
+
const parsed = convertResponse(JSON.parse(data));
|
|
2363
|
+
const eventType = mapEventType(String(parsed.type));
|
|
2364
|
+
parsed.type = eventType;
|
|
2365
|
+
const event = parsed;
|
|
2366
|
+
this.options.debug(`Received SSE event: ${eventType}`, event);
|
|
2367
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
2350
2368
|
if (handlers) {
|
|
2351
2369
|
const eventData = event.data;
|
|
2352
2370
|
handlers.forEach((handler) => {
|