@aouda/client 0.1.9 → 0.1.10

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.
@@ -421,7 +421,7 @@ var import_node_url = require("url");
421
421
  // package.json
422
422
  var package_default = {
423
423
  name: "@aouda/client",
424
- version: "0.1.9",
424
+ version: "0.1.10",
425
425
  description: "Official TypeScript/JavaScript client library for Aouda",
426
426
  type: "module",
427
427
  main: "./dist/index.cjs",
@@ -1512,7 +1512,15 @@ var ERROR_CODE_MAP = {
1512
1512
  AUTH_TOKEN_INVALID: AoudaAuthenticationError,
1513
1513
  AUTH_TOKEN_REVOKED: AoudaAuthenticationError,
1514
1514
  AUTH_API_KEY_INVALID: AoudaAuthenticationError,
1515
- AUTH_REQUIRED: AoudaAuthenticationError
1515
+ AUTH_REQUIRED: AoudaAuthenticationError,
1516
+ NAMED_QUERY_NOT_FOUND: AoudaNotFoundError,
1517
+ NAMED_MUTATION_NOT_FOUND: AoudaNotFoundError,
1518
+ NAMED_QUERY_BATCH_EMPTY: AoudaValidationError,
1519
+ NAMED_QUERY_BATCH_TOO_LARGE: AoudaValidationError,
1520
+ NAMED_QUERY_BATCH_MUTATION: AoudaValidationError,
1521
+ NAMED_QUERY_BIND_FAILED: AoudaValidationError,
1522
+ NAMED_QUERY_PARAM_REQUIRED: AoudaValidationError,
1523
+ NAMED_MUTATION_BIND_FAILED: AoudaValidationError
1516
1524
  };
1517
1525
  function createComposedAbortController(...signals) {
1518
1526
  const controller = new AbortController();
@@ -2405,6 +2413,7 @@ var TableSubscription = class {
2405
2413
  this._started = false;
2406
2414
  this._startPromise = null;
2407
2415
  this._lastVersion = 0;
2416
+ this._pendingSnapshotRows = [];
2408
2417
  this.id = createStreamingId("sub");
2409
2418
  this._transport = transport;
2410
2419
  this._tableName = tableName;
@@ -2461,6 +2470,7 @@ var TableSubscription = class {
2461
2470
  return;
2462
2471
  }
2463
2472
  try {
2473
+ this._pendingSnapshotRows = [];
2464
2474
  const resumeFrom = this._lastVersion > 0 ? this._lastVersion : void 0;
2465
2475
  await this._sendSubscribe(resumeFrom);
2466
2476
  } catch (error) {
@@ -2489,7 +2499,13 @@ var TableSubscription = class {
2489
2499
  }
2490
2500
  switch (message.type) {
2491
2501
  case "snapshot":
2492
- this._handleSnapshot(message);
2502
+ this._handleSnapshotPage(message);
2503
+ return;
2504
+ case "snapshot_complete":
2505
+ this._handleSnapshotComplete(message);
2506
+ return;
2507
+ case "gap":
2508
+ void this._handleGap(message);
2493
2509
  return;
2494
2510
  case "change":
2495
2511
  this._handleChange(message);
@@ -2501,9 +2517,13 @@ var TableSubscription = class {
2501
2517
  return;
2502
2518
  }
2503
2519
  }
2504
- _handleSnapshot(message) {
2520
+ _handleSnapshotPage(message) {
2521
+ this._pendingSnapshotRows.push(...message.rows);
2522
+ }
2523
+ _handleSnapshotComplete(message) {
2505
2524
  this._lastVersion = message.version;
2506
- const rows = message.rows;
2525
+ const rows = this._pendingSnapshotRows;
2526
+ this._pendingSnapshotRows = [];
2507
2527
  this._onSnapshot?.(rows, message.version);
2508
2528
  this._queue.push({
2509
2529
  type: "snapshot",
@@ -2511,6 +2531,16 @@ var TableSubscription = class {
2511
2531
  version: message.version
2512
2532
  });
2513
2533
  }
2534
+ async _handleGap(message) {
2535
+ this._pendingSnapshotRows = [];
2536
+ this._lastVersion = message.last_seq;
2537
+ try {
2538
+ await this._sendSubscribe(message.last_seq);
2539
+ } catch (error) {
2540
+ const wrapped = error instanceof Error ? error : new AoudaConnectionError("Subscription gap resume failed");
2541
+ this._notifyError(wrapped);
2542
+ }
2543
+ }
2514
2544
  _handleChange(message) {
2515
2545
  this._lastVersion = message.version;
2516
2546
  const event = {
@@ -2525,6 +2555,7 @@ var TableSubscription = class {
2525
2555
  this._queue.push(event);
2526
2556
  }
2527
2557
  _handleServerError(message) {
2558
+ this._pendingSnapshotRows = [];
2528
2559
  const error = new AoudaConnectionError(
2529
2560
  `Subscription error (${message.code}): ${message.message}`
2530
2561
  );
@@ -4932,6 +4963,147 @@ var MaterializedQueriesApi = class {
4932
4963
  }
4933
4964
  };
4934
4965
 
4966
+ // src/named-queries.ts
4967
+ var MAX_NAMED_QUERY_BATCH_SIZE = 32;
4968
+ function raiseDeprecationWarnings(sink, warnings) {
4969
+ if (warnings == null) return;
4970
+ for (const warning of warnings) {
4971
+ if (warning.code !== "NAMED_QUERY_DEPRECATED" && warning.code !== "NAMED_MUTATION_DEPRECATED") {
4972
+ continue;
4973
+ }
4974
+ const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
4975
+ const hash = warning.hash != null && warning.hash.length > 0 ? ` hash=${warning.hash}` : "";
4976
+ sink({
4977
+ code: warning.code,
4978
+ hash: warning.hash,
4979
+ sunsetAt: warning.sunsetAt,
4980
+ message: `${warning.code}:${hash}${sunset}`.trim()
4981
+ });
4982
+ }
4983
+ }
4984
+ function emptyStats() {
4985
+ return {
4986
+ rowsScanned: 0,
4987
+ rowsReturned: 0,
4988
+ segmentsAccessed: 0,
4989
+ executionMs: 0
4990
+ };
4991
+ }
4992
+ var NamedQueriesApi = class {
4993
+ constructor(transport, database, onWarning) {
4994
+ this.transport = transport;
4995
+ this.database = database;
4996
+ this.onWarning = onWarning;
4997
+ }
4998
+ async execute(hash, args, options) {
4999
+ if (typeof hash !== "string" || hash.trim().length === 0) {
5000
+ throw new Error("Named query hash must be a non-empty string");
5001
+ }
5002
+ const prefix = databasePath2(this.database);
5003
+ const path4 = `${prefix}/named-queries/${encodeURIComponent(hash)}/query?format=columnar`;
5004
+ const response = await this.transport.post(
5005
+ path4,
5006
+ { args: args ?? {} },
5007
+ { signal: options?.signal }
5008
+ );
5009
+ const rows = columnarToRows(response);
5010
+ raiseDeprecationWarnings(this.onWarning, response.warnings);
5011
+ return {
5012
+ rows,
5013
+ stats: response.stats,
5014
+ warnings: response.warnings
5015
+ };
5016
+ }
5017
+ async batch(items, options) {
5018
+ if (items.length === 0) {
5019
+ throw new AoudaValidationError(
5020
+ "Named query batch requires a non-empty queries array.",
5021
+ "NAMED_QUERY_BATCH_EMPTY",
5022
+ 400
5023
+ );
5024
+ }
5025
+ if (items.length > MAX_NAMED_QUERY_BATCH_SIZE) {
5026
+ throw new AoudaValidationError(
5027
+ `Named query batch exceeds ${MAX_NAMED_QUERY_BATCH_SIZE} elements.`,
5028
+ "NAMED_QUERY_BATCH_TOO_LARGE",
5029
+ 400
5030
+ );
5031
+ }
5032
+ const prefix = databasePath2(this.database);
5033
+ const path4 = `${prefix}/named-queries/batch?format=columnar`;
5034
+ const envelope = await this.transport.post(
5035
+ path4,
5036
+ { queries: items },
5037
+ { signal: options?.signal }
5038
+ );
5039
+ return (envelope.results ?? []).map((slot) => {
5040
+ if (slot.code != null && slot.code.length > 0) {
5041
+ return {
5042
+ isError: true,
5043
+ code: slot.code,
5044
+ error: slot.error
5045
+ };
5046
+ }
5047
+ const columnar = {
5048
+ columns: slot.columns ?? [],
5049
+ types: slot.types ?? [],
5050
+ data: slot.data ?? [],
5051
+ rowCount: slot.rowCount ?? 0,
5052
+ stats: slot.stats ?? emptyStats(),
5053
+ warnings: slot.warnings
5054
+ };
5055
+ const result = {
5056
+ rows: columnarToRows(columnar),
5057
+ stats: columnar.stats,
5058
+ warnings: slot.warnings
5059
+ };
5060
+ raiseDeprecationWarnings(this.onWarning, slot.warnings);
5061
+ return { isError: false, result };
5062
+ });
5063
+ }
5064
+ };
5065
+ var NamedMutationsApi = class {
5066
+ constructor(transport, database, onWarning) {
5067
+ this.transport = transport;
5068
+ this.database = database;
5069
+ this.onWarning = onWarning;
5070
+ }
5071
+ async execute(hash, args) {
5072
+ if (typeof hash !== "string" || hash.trim().length === 0) {
5073
+ throw new Error("Named mutation hash must be a non-empty string");
5074
+ }
5075
+ const prefix = databasePath2(this.database);
5076
+ const path4 = `${prefix}/named-mutations/${encodeURIComponent(hash)}/execute`;
5077
+ const wire = await this.transport.post(path4, {
5078
+ args: args ?? {}
5079
+ });
5080
+ let op = "unknown";
5081
+ let rowsAffected = 0;
5082
+ if (wire.rowsInserted != null) {
5083
+ op = "insert";
5084
+ rowsAffected = wire.rowsInserted;
5085
+ } else if (wire.rowsUpdated != null) {
5086
+ op = "update";
5087
+ rowsAffected = wire.rowsUpdated;
5088
+ } else if (wire.rowsDeleted != null) {
5089
+ op = "delete";
5090
+ rowsAffected = wire.rowsDeleted;
5091
+ }
5092
+ raiseDeprecationWarnings(this.onWarning, wire.warnings);
5093
+ const returning = wire.rows == null ? void 0 : {
5094
+ rows: columnarToRows(wire.rows),
5095
+ stats: wire.rows.stats,
5096
+ warnings: wire.rows.warnings
5097
+ };
5098
+ return {
5099
+ op,
5100
+ rowsAffected,
5101
+ returning,
5102
+ warnings: wire.warnings
5103
+ };
5104
+ }
5105
+ };
5106
+
4935
5107
  // src/streaming/websocket-transport.ts
4936
5108
  var import_msgpack = require("@msgpack/msgpack");
4937
5109
  var DEFAULT_PING_INTERVAL_MS = 2e4;
@@ -5694,6 +5866,19 @@ var AoudaClient = class {
5694
5866
  this.transport,
5695
5867
  this.database
5696
5868
  );
5869
+ const onNamedArtifactWarning = options.onNamedArtifactWarning ?? ((warning) => {
5870
+ console.warn(warning.message);
5871
+ });
5872
+ this._namedQueries = new NamedQueriesApi(
5873
+ this.transport,
5874
+ this.database,
5875
+ onNamedArtifactWarning
5876
+ );
5877
+ this._namedMutations = new NamedMutationsApi(
5878
+ this.transport,
5879
+ this.database,
5880
+ onNamedArtifactWarning
5881
+ );
5697
5882
  }
5698
5883
  /**
5699
5884
  * Connects to the Aouda server.
@@ -5836,6 +6021,18 @@ var AoudaClient = class {
5836
6021
  get materializedQueries() {
5837
6022
  return this._materializedQueries;
5838
6023
  }
6024
+ /**
6025
+ * Hash-only named-query execute and batch. Names are codegen aliases (D-5).
6026
+ */
6027
+ get namedQueries() {
6028
+ return this._namedQueries;
6029
+ }
6030
+ /**
6031
+ * Hash-only named-mutation execute. No batch.
6032
+ */
6033
+ get namedMutations() {
6034
+ return this._namedMutations;
6035
+ }
5839
6036
  /**
5840
6037
  * Access auth operations (signUp, signIn, signOut, refresh, me, changePassword).
5841
6038
  * @returns The auth API.
@@ -5984,7 +6181,7 @@ Usage:
5984
6181
  npx @aouda/client schema <command> [options]
5985
6182
 
5986
6183
  Commands:
5987
- generate Fetch schema from Aouda server and output TypeScript types
6184
+ generate Fetch schema from Aouda server and output TypeScript types (tables + named query/mutation hashes)
5988
6185
  schema Schema management (diff, apply, export, validate, history, seed)
5989
6186
  diff Show migration plan (desired vs current)
5990
6187
  apply Apply schema (use --allow-destructive for drops; --dry-run to preview)