@ekodb/ekodb-client 0.19.0 → 0.20.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 +0 -1
- package/dist/client.d.ts +108 -5
- package/dist/client.js +401 -64
- package/dist/client.test.js +117 -0
- package/dist/functions.test.d.ts +1 -2
- package/dist/functions.test.js +1 -2
- package/dist/query-builder.d.ts +0 -4
- package/dist/query-builder.js +2 -14
- package/dist/query-builder.test.js +0 -5
- package/dist/utils.js +7 -1
- package/dist/utils.test.js +4 -0
- package/dist/websocket.test.js +180 -0
- package/package.json +1 -1
- package/src/client.test.ts +150 -1
- package/src/client.ts +478 -66
- package/src/functions.test.ts +1 -2
- package/src/query-builder.test.ts +0 -7
- package/src/query-builder.ts +2 -14
- package/src/utils.test.ts +5 -0
- package/src/utils.ts +9 -1
- package/src/websocket.test.ts +273 -0
package/README.md
CHANGED
|
@@ -269,7 +269,6 @@ const joinResults = await client.find("users", multiQuery);
|
|
|
269
269
|
- `.contains(field, value)` - String contains
|
|
270
270
|
- `.startsWith(field, value)` - String starts with
|
|
271
271
|
- `.endsWith(field, value)` - String ends with
|
|
272
|
-
- `.regex(field, pattern)` - Regex match
|
|
273
272
|
- `.sortAsc(field)` / `.sortDesc(field)` - Sorting
|
|
274
273
|
- `.limit(n)` / `.skip(n)` - Pagination
|
|
275
274
|
- `.join(joinConfig)` - Add join configuration
|
package/dist/client.d.ts
CHANGED
|
@@ -374,6 +374,20 @@ export declare class EkoDBClient {
|
|
|
374
374
|
* Sleep for a specified number of seconds
|
|
375
375
|
*/
|
|
376
376
|
private sleep;
|
|
377
|
+
/**
|
|
378
|
+
* Parse a `Retry-After` header into a non-negative delay in seconds.
|
|
379
|
+
*
|
|
380
|
+
* Per RFC 9110 the value is either delay-seconds (an integer) or an
|
|
381
|
+
* HTTP-date. Anything that doesn't resolve to a finite, non-negative number
|
|
382
|
+
* (missing header, garbage, a past date) falls back to `defaultSecs`.
|
|
383
|
+
*/
|
|
384
|
+
private parseRetryAfter;
|
|
385
|
+
/**
|
|
386
|
+
* Backoff delay (in seconds) for a 0-indexed retry attempt: a capped
|
|
387
|
+
* exponential schedule (0.2s → 5s) with full jitter, so concurrent clients
|
|
388
|
+
* don't retry in lockstep. Returns a value in [d/2, d].
|
|
389
|
+
*/
|
|
390
|
+
private backoffSeconds;
|
|
377
391
|
/**
|
|
378
392
|
* Helper to determine if a path should use JSON
|
|
379
393
|
* Only CRUD operations (insert/update/delete/batch) use MessagePack
|
|
@@ -1090,9 +1104,17 @@ export declare class EkoDBClient {
|
|
|
1090
1104
|
filterValue?: string;
|
|
1091
1105
|
}): EventStream<MutationNotification>;
|
|
1092
1106
|
/**
|
|
1093
|
-
* Create a WebSocket client
|
|
1107
|
+
* Create a WebSocket client.
|
|
1108
|
+
*
|
|
1109
|
+
* The token is supplied as a provider bound to this client's
|
|
1110
|
+
* {@link getToken}, so every (re)connect re-evaluates (and proactively
|
|
1111
|
+
* refreshes) the auth token instead of snapshotting it once. This means a
|
|
1112
|
+
* reconnect after a token rotation uses the current token.
|
|
1113
|
+
*
|
|
1114
|
+
* @param wsURL - The WebSocket URL (e.g. `wss://host`); `/api/ws` is appended if absent.
|
|
1115
|
+
* @param options - Optional reconnect/timeout tunables.
|
|
1094
1116
|
*/
|
|
1095
|
-
websocket(wsURL: string): WebSocketClient;
|
|
1117
|
+
websocket(wsURL: string, options?: WebSocketClientOptions): WebSocketClient;
|
|
1096
1118
|
/**
|
|
1097
1119
|
* Generate embeddings for a single text
|
|
1098
1120
|
*
|
|
@@ -1236,6 +1258,35 @@ export interface SubscribeOptions {
|
|
|
1236
1258
|
filterField?: string;
|
|
1237
1259
|
filterValue?: string;
|
|
1238
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* A token provider: either a static token string, or a (possibly async)
|
|
1263
|
+
* function that returns a fresh token. When a function is supplied it is
|
|
1264
|
+
* re-invoked on every (re)connect, so a rotated/refreshed token is always
|
|
1265
|
+
* used for the new socket instead of a stale snapshot captured once.
|
|
1266
|
+
*/
|
|
1267
|
+
export type TokenProvider = string | (() => string | null | Promise<string | null>);
|
|
1268
|
+
/** Tunables for the WebSocket client's reconnect + request-timeout behavior. */
|
|
1269
|
+
export interface WebSocketClientOptions {
|
|
1270
|
+
/**
|
|
1271
|
+
* Auto-reconnect after an unexpected socket close/error (not an explicit
|
|
1272
|
+
* `close()`/unsubscribe). Defaults to true.
|
|
1273
|
+
*/
|
|
1274
|
+
autoReconnect?: boolean;
|
|
1275
|
+
/** Initial backoff delay in ms before the first reconnect attempt. Default 200. */
|
|
1276
|
+
reconnectInitialDelayMs?: number;
|
|
1277
|
+
/** Maximum backoff delay in ms (the cap for exponential growth). Default 5000. */
|
|
1278
|
+
reconnectMaxDelayMs?: number;
|
|
1279
|
+
/**
|
|
1280
|
+
* Maximum number of consecutive reconnect attempts before giving up.
|
|
1281
|
+
* 0 or undefined means unlimited. Default unlimited.
|
|
1282
|
+
*/
|
|
1283
|
+
reconnectMaxAttempts?: number;
|
|
1284
|
+
/**
|
|
1285
|
+
* Per-request timeout in ms for request/response WS calls. If no response
|
|
1286
|
+
* arrives in this window the pending promise rejects. Default 30000.
|
|
1287
|
+
*/
|
|
1288
|
+
requestTimeoutMs?: number;
|
|
1289
|
+
}
|
|
1239
1290
|
/** EventEmitter-like interface for subscriptions and chat streams. */
|
|
1240
1291
|
export declare class EventStream<_T = unknown> {
|
|
1241
1292
|
private listeners;
|
|
@@ -1280,24 +1331,67 @@ export declare class SchemaCache {
|
|
|
1280
1331
|
export declare function extractRecordId(record: Record, extraCandidates?: string[]): string | undefined;
|
|
1281
1332
|
export declare class WebSocketClient {
|
|
1282
1333
|
private wsURL;
|
|
1283
|
-
private
|
|
1334
|
+
private tokenProvider;
|
|
1284
1335
|
private ws;
|
|
1285
1336
|
private dispatcherRunning;
|
|
1286
1337
|
private schemaCache;
|
|
1338
|
+
private autoReconnect;
|
|
1339
|
+
private reconnectInitialDelayMs;
|
|
1340
|
+
private reconnectMaxDelayMs;
|
|
1341
|
+
private reconnectMaxAttempts;
|
|
1342
|
+
private requestTimeoutMs;
|
|
1343
|
+
/** Set while close() is in progress so the close handler doesn't reconnect. */
|
|
1344
|
+
private closed;
|
|
1345
|
+
private reconnectAttempts;
|
|
1346
|
+
private reconnecting;
|
|
1347
|
+
private connectPromise;
|
|
1287
1348
|
private pendingRequests;
|
|
1288
1349
|
private subscriptions;
|
|
1350
|
+
/** Bookkeeping so subscriptions can be replayed on reconnect. */
|
|
1351
|
+
private subscriptionParams;
|
|
1289
1352
|
private chatStreams;
|
|
1290
1353
|
private registerToolsAck;
|
|
1291
|
-
|
|
1354
|
+
/**
|
|
1355
|
+
* @param wsURL - WebSocket URL; `/api/ws` is appended if absent.
|
|
1356
|
+
* @param token - A static token string OR a {@link TokenProvider} function
|
|
1357
|
+
* re-evaluated on every (re)connect (so a refreshed token is used after a drop).
|
|
1358
|
+
* @param options - Optional reconnect/timeout tunables.
|
|
1359
|
+
*/
|
|
1360
|
+
constructor(wsURL: string, token: TokenProvider, options?: WebSocketClientOptions);
|
|
1292
1361
|
private messageCounter;
|
|
1293
1362
|
private genMessageId;
|
|
1294
1363
|
/**
|
|
1295
|
-
*
|
|
1364
|
+
* Compute the capped exponential backoff (with jitter) for a reconnect
|
|
1365
|
+
* attempt. attempt 0 -> ~initial, growing x2 each time up to the max cap.
|
|
1366
|
+
* Jitter is +/-25% to avoid thundering-herd reconnect storms.
|
|
1367
|
+
* @internal exposed for testing
|
|
1368
|
+
*/
|
|
1369
|
+
computeBackoff(attempt: number): number;
|
|
1370
|
+
/**
|
|
1371
|
+
* Connect and start the dispatcher. Re-evaluates the token provider so the
|
|
1372
|
+
* current/refreshed token is used for this socket.
|
|
1296
1373
|
*/
|
|
1297
1374
|
private ensureConnected;
|
|
1375
|
+
private openSocket;
|
|
1298
1376
|
private spawnDispatcher;
|
|
1377
|
+
/**
|
|
1378
|
+
* Reject in-flight requests and tear down the dead socket. If the close was
|
|
1379
|
+
* unexpected (not an explicit `close()`) and auto-reconnect is enabled,
|
|
1380
|
+
* schedule a reconnect that re-sends the active subscriptions.
|
|
1381
|
+
*/
|
|
1382
|
+
private handleDisconnect;
|
|
1383
|
+
/**
|
|
1384
|
+
* Reconnect with capped exponential backoff + jitter, then re-send the
|
|
1385
|
+
* subscribe messages for every active subscription so the SAME EventStream
|
|
1386
|
+
* keeps delivering mutations after a transient drop.
|
|
1387
|
+
*/
|
|
1388
|
+
private scheduleReconnect;
|
|
1389
|
+
/** Re-send Subscribe frames for every tracked subscription after a reconnect. */
|
|
1390
|
+
private resubscribeAll;
|
|
1299
1391
|
private routeMessage;
|
|
1300
1392
|
private sendRequest;
|
|
1393
|
+
/** Resolve/reject a pending request, clearing its timeout timer. */
|
|
1394
|
+
private settlePending;
|
|
1301
1395
|
/**
|
|
1302
1396
|
* Find all records in a collection via WebSocket.
|
|
1303
1397
|
*/
|
|
@@ -1307,6 +1401,11 @@ export declare class WebSocketClient {
|
|
|
1307
1401
|
* Returns an EventStream that emits "mutation" events.
|
|
1308
1402
|
*/
|
|
1309
1403
|
subscribe(collection: string, options?: SubscribeOptions): Promise<EventStream<MutationNotification>>;
|
|
1404
|
+
/**
|
|
1405
|
+
* Unsubscribe from a collection's mutation notifications. This is an
|
|
1406
|
+
* intentional teardown, so the subscription is NOT replayed on reconnect.
|
|
1407
|
+
*/
|
|
1408
|
+
unsubscribe(collection: string): void;
|
|
1310
1409
|
/**
|
|
1311
1410
|
* Send a chat message and receive a streaming response.
|
|
1312
1411
|
* Returns an EventStream that emits "event" with ChatStreamEvent objects.
|
|
@@ -1369,6 +1468,10 @@ export declare class WebSocketClient {
|
|
|
1369
1468
|
deleteCollection(name: string): Promise<void>;
|
|
1370
1469
|
/**
|
|
1371
1470
|
* Close the WebSocket connection.
|
|
1471
|
+
*
|
|
1472
|
+
* This is an INTENTIONAL close: it disables auto-reconnect, rejects any
|
|
1473
|
+
* in-flight requests, and tears down all subscriptions/chat streams so
|
|
1474
|
+
* nothing is replayed afterward.
|
|
1372
1475
|
*/
|
|
1373
1476
|
close(): void;
|
|
1374
1477
|
}
|