@aouda/client 0.1.10 → 0.1.11

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.
@@ -2259,6 +2259,7 @@ declare class AuthHandler {
2259
2259
  private readonly _serverUrl;
2260
2260
  private readonly _timeout;
2261
2261
  private readonly _refreshThresholdMs;
2262
+ private _onAccessTokenRefreshed;
2262
2263
  private readonly _apiKeyMode;
2263
2264
  private readonly _isServiceKeyMode;
2264
2265
  private readonly _userToken;
@@ -2329,6 +2330,7 @@ declare class AuthHandler {
2329
2330
  callMeEndpoint(): Promise<UserProfile>;
2330
2331
  callChangePasswordEndpoint(currentPassword: string, newPassword: string): Promise<void>;
2331
2332
  private shouldProactivelyRefresh;
2333
+ setOnAccessTokenRefreshed(handler: ((token: string) => void) | null): void;
2332
2334
  private _doRefresh;
2333
2335
  private _fetchJson;
2334
2336
  private _tryReadErrorBody;
@@ -2426,12 +2428,23 @@ interface AuthMessage {
2426
2428
  database: string;
2427
2429
  wire_mode?: StreamingWireMode;
2428
2430
  }
2431
+ interface ConflateOptions {
2432
+ key?: string[];
2433
+ interval_ms: number;
2434
+ }
2429
2435
  interface SubscribeMessage {
2430
2436
  type: "subscribe";
2431
2437
  id: string;
2432
2438
  target: string;
2433
2439
  filter?: Record<string, unknown>;
2434
2440
  resume_from?: number;
2441
+ hash?: string;
2442
+ args?: Record<string, unknown>;
2443
+ conflate?: ConflateOptions;
2444
+ }
2445
+ interface ReAuthMessage {
2446
+ type: "re_auth";
2447
+ token: string;
2435
2448
  }
2436
2449
  interface UnsubscribeMessage {
2437
2450
  type: "unsubscribe";
@@ -2456,7 +2469,7 @@ interface StreamCloseMessage {
2456
2469
  interface PingMessage {
2457
2470
  type: "ping";
2458
2471
  }
2459
- type ClientMessage = AuthMessage | SubscribeMessage | UnsubscribeMessage | StreamOpenMessage | StreamRowsMessage | StreamCloseMessage | PingMessage;
2472
+ type ClientMessage = AuthMessage | ReAuthMessage | SubscribeMessage | UnsubscribeMessage | StreamOpenMessage | StreamRowsMessage | StreamCloseMessage | PingMessage;
2460
2473
  interface AuthOkMessage {
2461
2474
  type: "auth_ok";
2462
2475
  user_id?: string;
@@ -2489,11 +2502,12 @@ interface GapMessage {
2489
2502
  interface ChangeMessage {
2490
2503
  type: "change";
2491
2504
  id: string;
2492
- op: "insert" | "update" | "delete";
2505
+ op: "insert" | "update" | "delete" | "upsert";
2493
2506
  row?: unknown;
2494
2507
  prev?: unknown;
2495
2508
  key?: unknown;
2496
2509
  version: number;
2510
+ values_skipped?: number;
2497
2511
  }
2498
2512
  interface StreamAckMessage {
2499
2513
  type: "stream_ack";
@@ -2542,11 +2556,12 @@ interface SubscriptionSnapshotEvent<T = Record<string, unknown>> {
2542
2556
  }
2543
2557
  interface SubscriptionChangeEvent<T = Record<string, unknown>> {
2544
2558
  type: "change";
2545
- op: "insert" | "update" | "delete";
2559
+ op: "insert" | "update" | "delete" | "upsert";
2546
2560
  row?: T;
2547
2561
  prev?: T;
2548
2562
  key?: unknown;
2549
2563
  version: number;
2564
+ values_skipped?: number;
2550
2565
  }
2551
2566
  type SubscriptionEvent<T = Record<string, unknown>> = SubscriptionSnapshotEvent<T> | SubscriptionChangeEvent<T>;
2552
2567
  interface SubscribeOptions<T = Record<string, unknown>> {
@@ -2554,6 +2569,7 @@ interface SubscribeOptions<T = Record<string, unknown>> {
2554
2569
  onChange?: (event: SubscriptionChangeEvent<T>) => void;
2555
2570
  onError?: (error: Error) => void;
2556
2571
  filter?: Record<string, unknown>;
2572
+ conflate?: ConflateOptions;
2557
2573
  }
2558
2574
  interface Subscription<T = Record<string, unknown>> extends AsyncIterable<SubscriptionEvent<T>> {
2559
2575
  readonly id: string;
@@ -2259,6 +2259,7 @@ declare class AuthHandler {
2259
2259
  private readonly _serverUrl;
2260
2260
  private readonly _timeout;
2261
2261
  private readonly _refreshThresholdMs;
2262
+ private _onAccessTokenRefreshed;
2262
2263
  private readonly _apiKeyMode;
2263
2264
  private readonly _isServiceKeyMode;
2264
2265
  private readonly _userToken;
@@ -2329,6 +2330,7 @@ declare class AuthHandler {
2329
2330
  callMeEndpoint(): Promise<UserProfile>;
2330
2331
  callChangePasswordEndpoint(currentPassword: string, newPassword: string): Promise<void>;
2331
2332
  private shouldProactivelyRefresh;
2333
+ setOnAccessTokenRefreshed(handler: ((token: string) => void) | null): void;
2332
2334
  private _doRefresh;
2333
2335
  private _fetchJson;
2334
2336
  private _tryReadErrorBody;
@@ -2426,12 +2428,23 @@ interface AuthMessage {
2426
2428
  database: string;
2427
2429
  wire_mode?: StreamingWireMode;
2428
2430
  }
2431
+ interface ConflateOptions {
2432
+ key?: string[];
2433
+ interval_ms: number;
2434
+ }
2429
2435
  interface SubscribeMessage {
2430
2436
  type: "subscribe";
2431
2437
  id: string;
2432
2438
  target: string;
2433
2439
  filter?: Record<string, unknown>;
2434
2440
  resume_from?: number;
2441
+ hash?: string;
2442
+ args?: Record<string, unknown>;
2443
+ conflate?: ConflateOptions;
2444
+ }
2445
+ interface ReAuthMessage {
2446
+ type: "re_auth";
2447
+ token: string;
2435
2448
  }
2436
2449
  interface UnsubscribeMessage {
2437
2450
  type: "unsubscribe";
@@ -2456,7 +2469,7 @@ interface StreamCloseMessage {
2456
2469
  interface PingMessage {
2457
2470
  type: "ping";
2458
2471
  }
2459
- type ClientMessage = AuthMessage | SubscribeMessage | UnsubscribeMessage | StreamOpenMessage | StreamRowsMessage | StreamCloseMessage | PingMessage;
2472
+ type ClientMessage = AuthMessage | ReAuthMessage | SubscribeMessage | UnsubscribeMessage | StreamOpenMessage | StreamRowsMessage | StreamCloseMessage | PingMessage;
2460
2473
  interface AuthOkMessage {
2461
2474
  type: "auth_ok";
2462
2475
  user_id?: string;
@@ -2489,11 +2502,12 @@ interface GapMessage {
2489
2502
  interface ChangeMessage {
2490
2503
  type: "change";
2491
2504
  id: string;
2492
- op: "insert" | "update" | "delete";
2505
+ op: "insert" | "update" | "delete" | "upsert";
2493
2506
  row?: unknown;
2494
2507
  prev?: unknown;
2495
2508
  key?: unknown;
2496
2509
  version: number;
2510
+ values_skipped?: number;
2497
2511
  }
2498
2512
  interface StreamAckMessage {
2499
2513
  type: "stream_ack";
@@ -2542,11 +2556,12 @@ interface SubscriptionSnapshotEvent<T = Record<string, unknown>> {
2542
2556
  }
2543
2557
  interface SubscriptionChangeEvent<T = Record<string, unknown>> {
2544
2558
  type: "change";
2545
- op: "insert" | "update" | "delete";
2559
+ op: "insert" | "update" | "delete" | "upsert";
2546
2560
  row?: T;
2547
2561
  prev?: T;
2548
2562
  key?: unknown;
2549
2563
  version: number;
2564
+ values_skipped?: number;
2550
2565
  }
2551
2566
  type SubscriptionEvent<T = Record<string, unknown>> = SubscriptionSnapshotEvent<T> | SubscriptionChangeEvent<T>;
2552
2567
  interface SubscribeOptions<T = Record<string, unknown>> {
@@ -2554,6 +2569,7 @@ interface SubscribeOptions<T = Record<string, unknown>> {
2554
2569
  onChange?: (event: SubscriptionChangeEvent<T>) => void;
2555
2570
  onError?: (error: Error) => void;
2556
2571
  filter?: Record<string, unknown>;
2572
+ conflate?: ConflateOptions;
2557
2573
  }
2558
2574
  interface Subscription<T = Record<string, unknown>> extends AsyncIterable<SubscriptionEvent<T>> {
2559
2575
  readonly id: string;
package/dist/index.cjs CHANGED
@@ -86,7 +86,7 @@ module.exports = __toCommonJS(index_exports);
86
86
  // package.json
87
87
  var package_default = {
88
88
  name: "@aouda/client",
89
- version: "0.1.10",
89
+ version: "0.1.11",
90
90
  description: "Official TypeScript/JavaScript client library for Aouda",
91
91
  type: "module",
92
92
  main: "./dist/index.cjs",
@@ -357,6 +357,7 @@ var AuthHandler = class {
357
357
  this._tokenExpiry = null;
358
358
  this._authenticated = false;
359
359
  this._refreshPromise = null;
360
+ this._onAccessTokenRefreshed = null;
360
361
  this._serverUrl = serverUrl.replace(/\/+$/, "");
361
362
  this._timeout = timeout;
362
363
  this._authBasePath = config.basePath;
@@ -606,10 +607,16 @@ var AuthHandler = class {
606
607
  const thresholdSeconds = this._refreshThresholdMs / 1e3;
607
608
  return this._tokenExpiry <= nowSeconds + thresholdSeconds;
608
609
  }
610
+ setOnAccessTokenRefreshed(handler) {
611
+ this._onAccessTokenRefreshed = handler;
612
+ }
609
613
  async _doRefresh() {
610
614
  try {
611
615
  const result = await this.callRefreshEndpoint();
612
616
  this.handleSignInResult(result);
617
+ if (result.accessToken) {
618
+ this._onAccessTokenRefreshed?.(result.accessToken);
619
+ }
613
620
  return true;
614
621
  } catch {
615
622
  return false;
@@ -2112,6 +2119,7 @@ var TableSubscription = class {
2112
2119
  this._startPromise = null;
2113
2120
  this._lastVersion = 0;
2114
2121
  this._pendingSnapshotRows = [];
2122
+ this._forceFreshSubscribe = false;
2115
2123
  this.id = createStreamingId("sub");
2116
2124
  this._transport = transport;
2117
2125
  this._tableName = tableName;
@@ -2119,6 +2127,7 @@ var TableSubscription = class {
2119
2127
  this._onSnapshot = options.onSnapshot;
2120
2128
  this._onChange = options.onChange;
2121
2129
  this._onError = options.onError;
2130
+ this._conflate = options.conflate;
2122
2131
  this._reconnectHandlerKey = `${this.id}::reconnect`;
2123
2132
  }
2124
2133
  get lastVersion() {
@@ -2169,7 +2178,8 @@ var TableSubscription = class {
2169
2178
  }
2170
2179
  try {
2171
2180
  this._pendingSnapshotRows = [];
2172
- const resumeFrom = this._lastVersion > 0 ? this._lastVersion : void 0;
2181
+ const resumeFrom = this._forceFreshSubscribe || this._lastVersion <= 0 ? void 0 : this._lastVersion;
2182
+ this._forceFreshSubscribe = false;
2173
2183
  await this._sendSubscribe(resumeFrom);
2174
2184
  } catch (error) {
2175
2185
  const wrapped = error instanceof Error ? error : new AoudaConnectionError("Subscription reconnect failed");
@@ -2189,6 +2199,9 @@ var TableSubscription = class {
2189
2199
  if (resumeFrom !== void 0) {
2190
2200
  message.resume_from = resumeFrom;
2191
2201
  }
2202
+ if (this._conflate !== void 0) {
2203
+ message.conflate = this._conflate;
2204
+ }
2192
2205
  await this._transport.send(message);
2193
2206
  }
2194
2207
  _handleMessage(message) {
@@ -2249,10 +2262,19 @@ var TableSubscription = class {
2249
2262
  key: message.key,
2250
2263
  version: message.version
2251
2264
  };
2265
+ if (message.values_skipped !== void 0) {
2266
+ event.values_skipped = message.values_skipped;
2267
+ }
2252
2268
  this._onChange?.(event);
2253
2269
  this._queue.push(event);
2254
2270
  }
2255
2271
  _handleServerError(message) {
2272
+ if (message.code === "SLOW_CONSUMER") {
2273
+ this._pendingSnapshotRows = [];
2274
+ this._lastVersion = 0;
2275
+ this._forceFreshSubscribe = true;
2276
+ return;
2277
+ }
2256
2278
  this._pendingSnapshotRows = [];
2257
2279
  const error = new AoudaConnectionError(
2258
2280
  `Subscription error (${message.code}): ${message.message}`
@@ -2966,7 +2988,8 @@ var TableQuery = class _TableQuery {
2966
2988
  {
2967
2989
  onSnapshot: options.onSnapshot,
2968
2990
  onChange: options.onChange,
2969
- onError: options.onError
2991
+ onError: options.onError,
2992
+ conflate: options.conflate
2970
2993
  },
2971
2994
  mergedFilter
2972
2995
  );
@@ -4857,6 +4880,7 @@ var WebSocketTransport = class {
4857
4880
  // Resolved/rejected when the auth handshake completes.
4858
4881
  this._authResolve = null;
4859
4882
  this._authReject = null;
4883
+ this._handshakeComplete = false;
4860
4884
  this._serverUrl = serverUrl;
4861
4885
  this._database = database;
4862
4886
  this._authHandler = options.authHandler;
@@ -4866,6 +4890,11 @@ var WebSocketTransport = class {
4866
4890
  this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
4867
4891
  this._enableCompression = options.enableCompression ?? true;
4868
4892
  this._wireMode = options.wireMode ?? "json";
4893
+ this._authHandler?.setOnAccessTokenRefreshed((token) => {
4894
+ if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
4895
+ void this.send({ type: "re_auth", token });
4896
+ }
4897
+ });
4869
4898
  }
4870
4899
  // ─── Public API ────────────────────────────────────────────────────────────
4871
4900
  /** Latest version number from the most recent server `heartbeat` message. */
@@ -5038,6 +5067,7 @@ var WebSocketTransport = class {
5038
5067
  const resolve = this._authResolve;
5039
5068
  this._authResolve = null;
5040
5069
  this._authReject = null;
5070
+ this._handshakeComplete = true;
5041
5071
  if (resolve) resolve();
5042
5072
  break;
5043
5073
  }
@@ -5064,10 +5094,15 @@ var WebSocketTransport = class {
5064
5094
  break;
5065
5095
  }
5066
5096
  const id = "id" in msg ? msg.id : void 0;
5067
- if (id !== void 0 && id !== null) {
5097
+ if (id !== void 0 && id !== null && id !== "") {
5068
5098
  this._handlers.get(id)?.(msg);
5069
5099
  } else {
5070
5100
  this._handlers.get("__global__")?.(msg);
5101
+ for (const [key, handler] of this._handlers) {
5102
+ if (key !== "__global__") {
5103
+ handler(msg);
5104
+ }
5105
+ }
5071
5106
  }
5072
5107
  }
5073
5108
  // ─── Internal: reconnect ──────────────────────────────────────────────────