@aouda/client 0.1.10 → 0.1.12

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.
@@ -1,4 +1,4 @@
1
- import { A as AoudaClient } from '../client-Dgenr-cE.cjs';
1
+ import { A as AoudaClient } from '../client-Q83x0Mz9.cjs';
2
2
 
3
3
  /**
4
4
  * CLI for @aouda/client.
@@ -1,4 +1,4 @@
1
- import { A as AoudaClient } from '../client-Dgenr-cE.js';
1
+ import { A as AoudaClient } from '../client-Q83x0Mz9.js';
2
2
 
3
3
  /**
4
4
  * CLI for @aouda/client.
package/dist/cli/index.js CHANGED
@@ -392,7 +392,7 @@ import { fileURLToPath } from "url";
392
392
  // package.json
393
393
  var package_default = {
394
394
  name: "@aouda/client",
395
- version: "0.1.10",
395
+ version: "0.1.12",
396
396
  description: "Official TypeScript/JavaScript client library for Aouda",
397
397
  type: "module",
398
398
  main: "./dist/index.cjs",
@@ -630,6 +630,7 @@ var AuthHandler = class {
630
630
  this._tokenExpiry = null;
631
631
  this._authenticated = false;
632
632
  this._refreshPromise = null;
633
+ this._onAccessTokenRefreshed = null;
633
634
  this._serverUrl = serverUrl.replace(/\/+$/, "");
634
635
  this._timeout = timeout;
635
636
  this._authBasePath = config.basePath;
@@ -879,10 +880,16 @@ var AuthHandler = class {
879
880
  const thresholdSeconds = this._refreshThresholdMs / 1e3;
880
881
  return this._tokenExpiry <= nowSeconds + thresholdSeconds;
881
882
  }
883
+ setOnAccessTokenRefreshed(handler) {
884
+ this._onAccessTokenRefreshed = handler;
885
+ }
882
886
  async _doRefresh() {
883
887
  try {
884
888
  const result = await this.callRefreshEndpoint();
885
889
  this.handleSignInResult(result);
890
+ if (result.accessToken) {
891
+ this._onAccessTokenRefreshed?.(result.accessToken);
892
+ }
886
893
  return true;
887
894
  } catch {
888
895
  return false;
@@ -2378,20 +2385,22 @@ var AsyncEventQueue = class {
2378
2385
  }
2379
2386
  };
2380
2387
  var TableSubscription = class {
2381
- constructor(transport, tableName, options = {}, baseFilter) {
2388
+ constructor(transport, identity, options = {}, onWarnings) {
2382
2389
  this._queue = new AsyncEventQueue();
2383
2390
  this._active = true;
2384
2391
  this._started = false;
2385
2392
  this._startPromise = null;
2386
2393
  this._lastVersion = 0;
2387
2394
  this._pendingSnapshotRows = [];
2395
+ this._forceFreshSubscribe = false;
2388
2396
  this.id = createStreamingId("sub");
2389
2397
  this._transport = transport;
2390
- this._tableName = tableName;
2391
- this._baseFilter = baseFilter;
2398
+ this._identity = identity;
2392
2399
  this._onSnapshot = options.onSnapshot;
2393
2400
  this._onChange = options.onChange;
2394
2401
  this._onError = options.onError;
2402
+ this._onWarnings = onWarnings;
2403
+ this._conflate = options.conflate;
2395
2404
  this._reconnectHandlerKey = `${this.id}::reconnect`;
2396
2405
  }
2397
2406
  get lastVersion() {
@@ -2442,7 +2451,8 @@ var TableSubscription = class {
2442
2451
  }
2443
2452
  try {
2444
2453
  this._pendingSnapshotRows = [];
2445
- const resumeFrom = this._lastVersion > 0 ? this._lastVersion : void 0;
2454
+ const resumeFrom = this._forceFreshSubscribe || this._lastVersion <= 0 ? void 0 : this._lastVersion;
2455
+ this._forceFreshSubscribe = false;
2446
2456
  await this._sendSubscribe(resumeFrom);
2447
2457
  } catch (error) {
2448
2458
  const wrapped = error instanceof Error ? error : new AoudaConnectionError("Subscription reconnect failed");
@@ -2452,16 +2462,25 @@ var TableSubscription = class {
2452
2462
  async _sendSubscribe(resumeFrom) {
2453
2463
  const message = {
2454
2464
  type: "subscribe",
2455
- id: this.id,
2456
- target: this._tableName
2465
+ id: this.id
2457
2466
  };
2458
- const filter = this._baseFilter;
2459
- if (filter !== void 0) {
2460
- message.filter = filter;
2467
+ if (this._identity.kind === "named") {
2468
+ message.hash = this._identity.hash;
2469
+ if (this._identity.args !== void 0) {
2470
+ message.args = this._identity.args;
2471
+ }
2472
+ } else {
2473
+ message.target = this._identity.target;
2474
+ if (this._identity.filter !== void 0) {
2475
+ message.filter = this._identity.filter;
2476
+ }
2461
2477
  }
2462
2478
  if (resumeFrom !== void 0) {
2463
2479
  message.resume_from = resumeFrom;
2464
2480
  }
2481
+ if (this._conflate !== void 0) {
2482
+ message.conflate = this._conflate;
2483
+ }
2465
2484
  await this._transport.send(message);
2466
2485
  }
2467
2486
  _handleMessage(message) {
@@ -2493,6 +2512,9 @@ var TableSubscription = class {
2493
2512
  }
2494
2513
  _handleSnapshotComplete(message) {
2495
2514
  this._lastVersion = message.version;
2515
+ if (message.warnings != null && message.warnings.length > 0) {
2516
+ this._onWarnings?.(message.warnings);
2517
+ }
2496
2518
  const rows = this._pendingSnapshotRows;
2497
2519
  this._pendingSnapshotRows = [];
2498
2520
  this._onSnapshot?.(rows, message.version);
@@ -2522,10 +2544,19 @@ var TableSubscription = class {
2522
2544
  key: message.key,
2523
2545
  version: message.version
2524
2546
  };
2547
+ if (message.values_skipped !== void 0) {
2548
+ event.values_skipped = message.values_skipped;
2549
+ }
2525
2550
  this._onChange?.(event);
2526
2551
  this._queue.push(event);
2527
2552
  }
2528
2553
  _handleServerError(message) {
2554
+ if (message.code === "SLOW_CONSUMER") {
2555
+ this._pendingSnapshotRows = [];
2556
+ this._lastVersion = 0;
2557
+ this._forceFreshSubscribe = true;
2558
+ return;
2559
+ }
2529
2560
  this._pendingSnapshotRows = [];
2530
2561
  const error = new AoudaConnectionError(
2531
2562
  `Subscription error (${message.code}): ${message.message}`
@@ -3233,16 +3264,16 @@ var TableQuery = class _TableQuery {
3233
3264
  const whereClause = this.buildWhereClause();
3234
3265
  const queryFilter = buildSubscriptionFilter(whereClause);
3235
3266
  const mergedFilter = mergeFilterObjects(queryFilter, options.filter);
3236
- const subscription = new TableSubscription(
3237
- wsTransport,
3238
- this.tableName,
3239
- {
3240
- onSnapshot: options.onSnapshot,
3241
- onChange: options.onChange,
3242
- onError: options.onError
3243
- },
3244
- mergedFilter
3245
- );
3267
+ const subscription = new TableSubscription(wsTransport, {
3268
+ kind: "table",
3269
+ target: this.tableName,
3270
+ filter: mergedFilter
3271
+ }, {
3272
+ onSnapshot: options.onSnapshot,
3273
+ onChange: options.onChange,
3274
+ onError: options.onError,
3275
+ conflate: options.conflate
3276
+ });
3246
3277
  subscription.start();
3247
3278
  return subscription;
3248
3279
  }
@@ -3828,10 +3859,84 @@ function serializeUpdateValue(col, val) {
3828
3859
  else: toNode(cond.else)
3829
3860
  };
3830
3861
  }
3862
+ if ("$upper" in val) {
3863
+ return { type: "call", fn: "upper", args: [unaryCallArg(col, val.$upper)] };
3864
+ }
3865
+ if ("$lower" in val) {
3866
+ return { type: "call", fn: "lower", args: [unaryCallArg(col, val.$lower)] };
3867
+ }
3868
+ if ("$trim" in val) {
3869
+ return { type: "call", fn: "trim", args: [unaryCallArg(col, val.$trim)] };
3870
+ }
3871
+ if ("$concat" in val) {
3872
+ const parts = val.$concat;
3873
+ return {
3874
+ type: "call",
3875
+ fn: "concat",
3876
+ args: parts.map((p) => valueToExprNode(p))
3877
+ };
3878
+ }
3879
+ if ("$substring" in val) {
3880
+ const spec = val.$substring;
3881
+ if (Array.isArray(spec)) {
3882
+ return {
3883
+ type: "call",
3884
+ fn: "substring",
3885
+ args: [{ type: "colRef", col }, ...spec.map((p) => valueToExprNode(p))]
3886
+ };
3887
+ }
3888
+ return {
3889
+ type: "call",
3890
+ fn: "substring",
3891
+ args: [{ type: "colRef", col }, { type: "literal", value: spec }]
3892
+ };
3893
+ }
3894
+ if ("$round" in val) {
3895
+ return {
3896
+ type: "call",
3897
+ fn: "round",
3898
+ args: [
3899
+ { type: "colRef", col },
3900
+ { type: "literal", value: val.$round }
3901
+ ]
3902
+ };
3903
+ }
3904
+ if ("$roundTo" in val) {
3905
+ return {
3906
+ type: "call",
3907
+ fn: "roundTo",
3908
+ args: [
3909
+ { type: "colRef", col },
3910
+ { type: "literal", value: val.$roundTo }
3911
+ ]
3912
+ };
3913
+ }
3914
+ if ("$cast" in val) {
3915
+ return {
3916
+ type: "call",
3917
+ fn: "cast",
3918
+ args: [
3919
+ { type: "colRef", col },
3920
+ { type: "literal", value: val.$cast }
3921
+ ]
3922
+ };
3923
+ }
3831
3924
  throw new Error(
3832
3925
  `Unknown expression operator in update() for column '${col}': ${JSON.stringify(val)}`
3833
3926
  );
3834
3927
  }
3928
+ function unaryCallArg(col, operand) {
3929
+ if (operand === true || operand === 1) {
3930
+ return { type: "colRef", col };
3931
+ }
3932
+ return valueToExprNode(operand);
3933
+ }
3934
+ function valueToExprNode(v) {
3935
+ if (typeof v === "string" && v.startsWith("$")) {
3936
+ return { type: "colRef", col: v.slice(1) };
3937
+ }
3938
+ return { type: "literal", value: v };
3939
+ }
3835
3940
 
3836
3941
  // src/tables.ts
3837
3942
  function validateNonEmptyString(value, name) {
@@ -4961,10 +5066,11 @@ function emptyStats() {
4961
5066
  };
4962
5067
  }
4963
5068
  var NamedQueriesApi = class {
4964
- constructor(transport, database, onWarning) {
5069
+ constructor(transport, database, onWarning, getStreamingTransport) {
4965
5070
  this.transport = transport;
4966
5071
  this.database = database;
4967
5072
  this.onWarning = onWarning;
5073
+ this.getStreamingTransport = getStreamingTransport;
4968
5074
  }
4969
5075
  async execute(hash, args, options) {
4970
5076
  if (typeof hash !== "string" || hash.trim().length === 0) {
@@ -5032,6 +5138,26 @@ var NamedQueriesApi = class {
5032
5138
  return { isError: false, result };
5033
5139
  });
5034
5140
  }
5141
+ subscribe(hash, args, options = {}) {
5142
+ if (typeof hash !== "string" || hash.trim().length === 0) {
5143
+ throw new Error("Named query hash must be a non-empty string");
5144
+ }
5145
+ const subscription = new TableSubscription(
5146
+ this.getStreamingTransport(),
5147
+ { kind: "named", hash, args },
5148
+ {
5149
+ onSnapshot: options.onSnapshot,
5150
+ onChange: options.onChange,
5151
+ onError: options.onError,
5152
+ conflate: options.conflate
5153
+ },
5154
+ (warnings) => {
5155
+ raiseDeprecationWarnings(this.onWarning, warnings);
5156
+ }
5157
+ );
5158
+ subscription.start();
5159
+ return subscription;
5160
+ }
5035
5161
  };
5036
5162
  var NamedMutationsApi = class {
5037
5163
  constructor(transport, database, onWarning) {
@@ -5099,6 +5225,7 @@ var WebSocketTransport = class {
5099
5225
  // Resolved/rejected when the auth handshake completes.
5100
5226
  this._authResolve = null;
5101
5227
  this._authReject = null;
5228
+ this._handshakeComplete = false;
5102
5229
  this._serverUrl = serverUrl;
5103
5230
  this._database = database;
5104
5231
  this._authHandler = options.authHandler;
@@ -5108,6 +5235,11 @@ var WebSocketTransport = class {
5108
5235
  this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
5109
5236
  this._enableCompression = options.enableCompression ?? true;
5110
5237
  this._wireMode = options.wireMode ?? "json";
5238
+ this._authHandler?.setOnAccessTokenRefreshed((token) => {
5239
+ if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
5240
+ void this.send({ type: "re_auth", token });
5241
+ }
5242
+ });
5111
5243
  }
5112
5244
  // ─── Public API ────────────────────────────────────────────────────────────
5113
5245
  /** Latest version number from the most recent server `heartbeat` message. */
@@ -5280,6 +5412,7 @@ var WebSocketTransport = class {
5280
5412
  const resolve4 = this._authResolve;
5281
5413
  this._authResolve = null;
5282
5414
  this._authReject = null;
5415
+ this._handshakeComplete = true;
5283
5416
  if (resolve4) resolve4();
5284
5417
  break;
5285
5418
  }
@@ -5306,10 +5439,15 @@ var WebSocketTransport = class {
5306
5439
  break;
5307
5440
  }
5308
5441
  const id = "id" in msg ? msg.id : void 0;
5309
- if (id !== void 0 && id !== null) {
5442
+ if (id !== void 0 && id !== null && id !== "") {
5310
5443
  this._handlers.get(id)?.(msg);
5311
5444
  } else {
5312
5445
  this._handlers.get("__global__")?.(msg);
5446
+ for (const [key, handler] of this._handlers) {
5447
+ if (key !== "__global__") {
5448
+ handler(msg);
5449
+ }
5450
+ }
5313
5451
  }
5314
5452
  }
5315
5453
  // ─── Internal: reconnect ──────────────────────────────────────────────────
@@ -5843,7 +5981,8 @@ var AoudaClient = class {
5843
5981
  this._namedQueries = new NamedQueriesApi(
5844
5982
  this.transport,
5845
5983
  this.database,
5846
- onNamedArtifactWarning
5984
+ onNamedArtifactWarning,
5985
+ () => this._getOrCreateWebSocketTransport()
5847
5986
  );
5848
5987
  this._namedMutations = new NamedMutationsApi(
5849
5988
  this.transport,