@aouda/client 0.1.14 → 0.1.16
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 +1 -1
- package/dist/cli/index.cjs +377 -75
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +377 -75
- package/dist/cli/index.js.map +1 -1
- package/dist/{client-BCMP-Fge.d.cts → client-CsE8Vd6m.d.cts} +168 -24
- package/dist/{client-BCMP-Fge.d.ts → client-CsE8Vd6m.d.ts} +168 -24
- package/dist/index.cjs +382 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -10
- package/dist/index.d.ts +14 -10
- package/dist/index.js +379 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
MaterializedQueriesApi: () => MaterializedQueriesApi,
|
|
61
61
|
MaterializedQueryState: () => MaterializedQueryState,
|
|
62
62
|
MaterializedQueryType: () => MaterializedQueryType,
|
|
63
|
+
MemoryConsistencyTokenStore: () => MemoryConsistencyTokenStore,
|
|
63
64
|
MetricsAdminApi: () => MetricsAdminApi,
|
|
64
65
|
NamedMutationsApi: () => NamedMutationsApi,
|
|
65
66
|
NamedQueriesApi: () => NamedQueriesApi,
|
|
@@ -75,10 +76,12 @@ __export(index_exports, {
|
|
|
75
76
|
applyLocalNetworkAccess: () => applyLocalNetworkAccess,
|
|
76
77
|
coerceColumnarValue: () => coerceColumnarValue,
|
|
77
78
|
columnarToRows: () => columnarToRows,
|
|
79
|
+
compareOrdinal: () => compareOrdinal,
|
|
78
80
|
createAoudaClient: () => createAoudaClient,
|
|
79
81
|
createAoudaClusterMcpToolSet: () => createAoudaClusterMcpToolSet,
|
|
80
82
|
installLocalNetworkFetch: () => installLocalNetworkFetch,
|
|
81
83
|
localNetworkFetch: () => localNetworkFetch,
|
|
84
|
+
maxToken: () => maxToken,
|
|
82
85
|
resolveTargetAddressSpace: () => resolveTargetAddressSpace,
|
|
83
86
|
version: () => version
|
|
84
87
|
});
|
|
@@ -87,7 +90,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
87
90
|
// package.json
|
|
88
91
|
var package_default = {
|
|
89
92
|
name: "@aouda/client",
|
|
90
|
-
version: "0.1.
|
|
93
|
+
version: "0.1.16",
|
|
91
94
|
description: "Official TypeScript/JavaScript client library for Aouda",
|
|
92
95
|
type: "module",
|
|
93
96
|
main: "./dist/index.cjs",
|
|
@@ -197,9 +200,10 @@ var AoudaError = class extends Error {
|
|
|
197
200
|
}
|
|
198
201
|
};
|
|
199
202
|
var AoudaConnectionError = class extends AoudaError {
|
|
200
|
-
constructor(message, cause) {
|
|
203
|
+
constructor(message, cause, rowErrors) {
|
|
201
204
|
super(message);
|
|
202
205
|
this.cause = cause;
|
|
206
|
+
this.rowErrors = rowErrors;
|
|
203
207
|
this.name = "AoudaConnectionError";
|
|
204
208
|
}
|
|
205
209
|
};
|
|
@@ -219,43 +223,45 @@ var AoudaResponseError = class extends AoudaError {
|
|
|
219
223
|
}
|
|
220
224
|
};
|
|
221
225
|
var AoudaApiError = class extends AoudaError {
|
|
222
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
226
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
223
227
|
super(message);
|
|
224
228
|
this.code = code;
|
|
225
229
|
this.statusCode = statusCode;
|
|
226
230
|
this.details = details;
|
|
227
231
|
this.requestId = requestId;
|
|
228
232
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
233
|
+
this.token = token;
|
|
234
|
+
this.rowErrors = rowErrors;
|
|
229
235
|
this.name = "AoudaApiError";
|
|
230
236
|
}
|
|
231
237
|
};
|
|
232
238
|
var AoudaNotFoundError = class extends AoudaApiError {
|
|
233
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
234
|
-
super(message, code, statusCode, details, requestId);
|
|
239
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
240
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
235
241
|
this.name = "AoudaNotFoundError";
|
|
236
242
|
}
|
|
237
243
|
};
|
|
238
244
|
var AoudaConflictError = class extends AoudaApiError {
|
|
239
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
240
|
-
super(message, code, statusCode, details, requestId);
|
|
245
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
246
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
241
247
|
this.name = "AoudaConflictError";
|
|
242
248
|
}
|
|
243
249
|
};
|
|
244
250
|
var AoudaValidationError = class extends AoudaApiError {
|
|
245
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
246
|
-
super(message, code, statusCode, details, requestId);
|
|
251
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
252
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
247
253
|
this.name = "AoudaValidationError";
|
|
248
254
|
}
|
|
249
255
|
};
|
|
250
256
|
var AoudaServerError = class extends AoudaApiError {
|
|
251
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
252
|
-
super(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
257
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
258
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
253
259
|
this.name = "AoudaServerError";
|
|
254
260
|
}
|
|
255
261
|
};
|
|
256
262
|
var AoudaAuthenticationError = class extends AoudaApiError {
|
|
257
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
258
|
-
super(message, code, statusCode, details, requestId);
|
|
263
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
264
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
259
265
|
this.name = "AoudaAuthenticationError";
|
|
260
266
|
}
|
|
261
267
|
};
|
|
@@ -1067,7 +1073,7 @@ function buildHandle(jobId, commitResp, wasResumed, transport, database, signal)
|
|
|
1067
1073
|
rowsDurablyCommitted: commitResp.rowsLoaded,
|
|
1068
1074
|
segmentsCreated: commitResp.segmentsCreated,
|
|
1069
1075
|
committedAtUtc: commitResp.committedAtUtc,
|
|
1070
|
-
|
|
1076
|
+
token: commitResp.token,
|
|
1071
1077
|
writeConcernSatisfied: commitResp.writeConcernAchieved ?? "acknowledged",
|
|
1072
1078
|
writeConcernTimedOut: commitResp.writeConcernTimedOut,
|
|
1073
1079
|
wasResumed,
|
|
@@ -1193,6 +1199,7 @@ var PROTOCOL_VERSION_HEADER = "X-Aouda-Protocol-Version";
|
|
|
1193
1199
|
var PROTOCOL_VERSION = "1";
|
|
1194
1200
|
var CONTENT_TYPE_JSON2 = "application/json";
|
|
1195
1201
|
var REQUEST_ID_HEADER2 = "X-Request-Id";
|
|
1202
|
+
var TOKEN_HEADER = "X-Aouda-Token";
|
|
1196
1203
|
var ERROR_CODE_MAP = {
|
|
1197
1204
|
TABLE_NOT_FOUND: AoudaNotFoundError,
|
|
1198
1205
|
COLUMN_NOT_FOUND: AoudaNotFoundError,
|
|
@@ -1207,6 +1214,10 @@ var ERROR_CODE_MAP = {
|
|
|
1207
1214
|
INVALID_OPERATOR: AoudaValidationError,
|
|
1208
1215
|
INVALID_COLUMN: AoudaValidationError,
|
|
1209
1216
|
INVALID_VALUE: AoudaValidationError,
|
|
1217
|
+
CONSTRAINT_CHECK_VIOLATION: AoudaValidationError,
|
|
1218
|
+
TRANSFORM_DERIVED_READONLY: AoudaValidationError,
|
|
1219
|
+
TRANSFORM_ROUTE_UNMATCHED: AoudaValidationError,
|
|
1220
|
+
TRANSFORM_ROUTE_AMBIGUOUS: AoudaValidationError,
|
|
1210
1221
|
UNSUPPORTED_VERSION: AoudaValidationError,
|
|
1211
1222
|
MALFORMED_REQUEST: AoudaValidationError,
|
|
1212
1223
|
INTERNAL_ERROR: AoudaServerError,
|
|
@@ -1232,7 +1243,12 @@ var ERROR_CODE_MAP = {
|
|
|
1232
1243
|
AUTH_IDENTITY_INVALID: AoudaValidationError,
|
|
1233
1244
|
AUTH_IDENTITY_NOT_FOUND: AoudaValidationError,
|
|
1234
1245
|
BULK_LOAD_TRANSFORM_INTENT_REQUIRED: AoudaValidationError,
|
|
1235
|
-
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError
|
|
1246
|
+
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError,
|
|
1247
|
+
TOKEN_MALFORMED: AoudaValidationError,
|
|
1248
|
+
TOKEN_FOREIGN_DATABASE: AoudaValidationError,
|
|
1249
|
+
TOKEN_EPOCH_SUPERSEDED: AoudaConflictError,
|
|
1250
|
+
TOKEN_UNSATISFIED: AoudaConflictError,
|
|
1251
|
+
TOKEN_FETCH_PRIMARY: AoudaApiError
|
|
1236
1252
|
};
|
|
1237
1253
|
function createComposedAbortController(...signals) {
|
|
1238
1254
|
const controller = new AbortController();
|
|
@@ -1262,6 +1278,9 @@ function parseRetryAfterSeconds(header) {
|
|
|
1262
1278
|
if (!Number.isFinite(n) || n < 0) return void 0;
|
|
1263
1279
|
return n;
|
|
1264
1280
|
}
|
|
1281
|
+
function nonEmptyRowErrors(rowErrors) {
|
|
1282
|
+
return Array.isArray(rowErrors) && rowErrors.length > 0 ? rowErrors : void 0;
|
|
1283
|
+
}
|
|
1265
1284
|
function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
1266
1285
|
const message = body.error ?? `${statusCode} ${statusText}`;
|
|
1267
1286
|
const code = body.code ?? "UNKNOWN";
|
|
@@ -1269,7 +1288,16 @@ function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
|
1269
1288
|
const requestId = body.requestId;
|
|
1270
1289
|
const retryAfterSeconds = parseRetryAfterSeconds(retryAfterHeader ?? null);
|
|
1271
1290
|
const Ctor = ERROR_CODE_MAP[code] ?? AoudaApiError;
|
|
1272
|
-
return new Ctor(
|
|
1291
|
+
return new Ctor(
|
|
1292
|
+
message,
|
|
1293
|
+
code,
|
|
1294
|
+
statusCode,
|
|
1295
|
+
details,
|
|
1296
|
+
requestId,
|
|
1297
|
+
retryAfterSeconds,
|
|
1298
|
+
body.token,
|
|
1299
|
+
nonEmptyRowErrors(body.rowErrors)
|
|
1300
|
+
);
|
|
1273
1301
|
}
|
|
1274
1302
|
var HttpTransport = class {
|
|
1275
1303
|
constructor(options) {
|
|
@@ -1281,6 +1309,29 @@ var HttpTransport = class {
|
|
|
1281
1309
|
...options.defaultHeaders
|
|
1282
1310
|
};
|
|
1283
1311
|
this.abortController = new AbortController();
|
|
1312
|
+
this.database = options.database;
|
|
1313
|
+
this.store = options.consistencyTokenStore;
|
|
1314
|
+
}
|
|
1315
|
+
presentTokenHeaders(path, headers) {
|
|
1316
|
+
if (this.store == null || this.database == null || isAuthPath(path)) {
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
const token = this.store.get(this.database);
|
|
1320
|
+
if (token != null && token.length > 0) {
|
|
1321
|
+
headers[TOKEN_HEADER] = token;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
observeResponse(_path, response, bodyText, errorCode) {
|
|
1325
|
+
if (this.store == null || this.database == null) {
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (errorCode === "TOKEN_MALFORMED" || errorCode === "TOKEN_FOREIGN_DATABASE") {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const header = response.headers.get(TOKEN_HEADER);
|
|
1332
|
+
const bodyToken = readBodyToken(bodyText);
|
|
1333
|
+
const token = header != null && header.trim().length > 0 ? header : bodyToken;
|
|
1334
|
+
this.store.observe(this.database, token);
|
|
1284
1335
|
}
|
|
1285
1336
|
/**
|
|
1286
1337
|
* Abort all in-flight and future requests (e.g. on client disconnect).
|
|
@@ -1318,6 +1369,7 @@ var HttpTransport = class {
|
|
|
1318
1369
|
...this.defaultHeaders,
|
|
1319
1370
|
...config.headers
|
|
1320
1371
|
};
|
|
1372
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1321
1373
|
if (config.body !== void 0 && config.body !== null) {
|
|
1322
1374
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1323
1375
|
}
|
|
@@ -1337,6 +1389,7 @@ var HttpTransport = class {
|
|
|
1337
1389
|
const text = await response.text();
|
|
1338
1390
|
if (config.allowStatuses?.includes(response.status) && text) {
|
|
1339
1391
|
try {
|
|
1392
|
+
this.observeResponse(config.path, response, text);
|
|
1340
1393
|
return JSON.parse(text);
|
|
1341
1394
|
} catch {
|
|
1342
1395
|
}
|
|
@@ -1350,15 +1403,20 @@ var HttpTransport = class {
|
|
|
1350
1403
|
}
|
|
1351
1404
|
if (response.status === 401) {
|
|
1352
1405
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1406
|
+
this.observeResponse(config.path, response, text, code);
|
|
1353
1407
|
throw new AoudaAuthenticationError(
|
|
1354
1408
|
errorBody?.error ?? "Unauthorized",
|
|
1355
1409
|
code,
|
|
1356
1410
|
401,
|
|
1357
1411
|
errorBody?.details,
|
|
1358
|
-
errorBody?.requestId
|
|
1412
|
+
errorBody?.requestId,
|
|
1413
|
+
void 0,
|
|
1414
|
+
errorBody?.token,
|
|
1415
|
+
nonEmptyRowErrors(errorBody?.rowErrors)
|
|
1359
1416
|
);
|
|
1360
1417
|
}
|
|
1361
1418
|
if (errorBody?.code != null) {
|
|
1419
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1362
1420
|
throw createApiError(
|
|
1363
1421
|
response.status,
|
|
1364
1422
|
response.statusText,
|
|
@@ -1366,6 +1424,7 @@ var HttpTransport = class {
|
|
|
1366
1424
|
response.headers.get("Retry-After")
|
|
1367
1425
|
);
|
|
1368
1426
|
}
|
|
1427
|
+
this.observeResponse(config.path, response, text);
|
|
1369
1428
|
throw new AoudaResponseError(
|
|
1370
1429
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1371
1430
|
response.status,
|
|
@@ -1373,6 +1432,7 @@ var HttpTransport = class {
|
|
|
1373
1432
|
);
|
|
1374
1433
|
}
|
|
1375
1434
|
const responseText = await response.text();
|
|
1435
|
+
this.observeResponse(config.path, response, responseText);
|
|
1376
1436
|
if (config.rawText) {
|
|
1377
1437
|
return responseText;
|
|
1378
1438
|
}
|
|
@@ -1433,6 +1493,7 @@ var HttpTransport = class {
|
|
|
1433
1493
|
...this.defaultHeaders,
|
|
1434
1494
|
...config.headers
|
|
1435
1495
|
};
|
|
1496
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1436
1497
|
if (config.rawBodyStr === void 0 && config.body !== void 0 && config.body !== null) {
|
|
1437
1498
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1438
1499
|
}
|
|
@@ -1449,6 +1510,7 @@ var HttpTransport = class {
|
|
|
1449
1510
|
try {
|
|
1450
1511
|
const response = await localNetworkFetch(url, init);
|
|
1451
1512
|
if (response.ok || config.allowStatuses?.includes(response.status)) {
|
|
1513
|
+
this.observeResponse(config.path, response, void 0);
|
|
1452
1514
|
return response;
|
|
1453
1515
|
}
|
|
1454
1516
|
const text = await response.text();
|
|
@@ -1461,15 +1523,20 @@ var HttpTransport = class {
|
|
|
1461
1523
|
}
|
|
1462
1524
|
if (response.status === 401) {
|
|
1463
1525
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1526
|
+
this.observeResponse(config.path, response, text, code);
|
|
1464
1527
|
throw new AoudaAuthenticationError(
|
|
1465
1528
|
errorBody?.error ?? "Unauthorized",
|
|
1466
1529
|
code,
|
|
1467
1530
|
401,
|
|
1468
1531
|
errorBody?.details,
|
|
1469
|
-
errorBody?.requestId
|
|
1532
|
+
errorBody?.requestId,
|
|
1533
|
+
void 0,
|
|
1534
|
+
errorBody?.token,
|
|
1535
|
+
nonEmptyRowErrors(errorBody?.rowErrors)
|
|
1470
1536
|
);
|
|
1471
1537
|
}
|
|
1472
1538
|
if (errorBody?.code != null) {
|
|
1539
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1473
1540
|
throw createApiError(
|
|
1474
1541
|
response.status,
|
|
1475
1542
|
response.statusText,
|
|
@@ -1477,6 +1544,7 @@ var HttpTransport = class {
|
|
|
1477
1544
|
response.headers.get("Retry-After")
|
|
1478
1545
|
);
|
|
1479
1546
|
}
|
|
1547
|
+
this.observeResponse(config.path, response, text);
|
|
1480
1548
|
throw new AoudaResponseError(
|
|
1481
1549
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1482
1550
|
response.status,
|
|
@@ -1631,6 +1699,47 @@ var HttpTransport = class {
|
|
|
1631
1699
|
});
|
|
1632
1700
|
}
|
|
1633
1701
|
};
|
|
1702
|
+
function isAuthPath(path) {
|
|
1703
|
+
let p = path;
|
|
1704
|
+
const q = p.indexOf("?");
|
|
1705
|
+
if (q >= 0) {
|
|
1706
|
+
p = p.slice(0, q);
|
|
1707
|
+
}
|
|
1708
|
+
if (/^https?:\/\//i.test(p)) {
|
|
1709
|
+
try {
|
|
1710
|
+
p = new URL(p).pathname;
|
|
1711
|
+
} catch {
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
const lower = p.toLowerCase();
|
|
1715
|
+
if (lower === "/api/auth" || lower.startsWith("/api/auth/")) {
|
|
1716
|
+
return true;
|
|
1717
|
+
}
|
|
1718
|
+
const prefix = "/api/databases/";
|
|
1719
|
+
if (!lower.startsWith(prefix)) {
|
|
1720
|
+
return false;
|
|
1721
|
+
}
|
|
1722
|
+
const rest = lower.slice(prefix.length);
|
|
1723
|
+
const slash = rest.indexOf("/");
|
|
1724
|
+
if (slash < 0) {
|
|
1725
|
+
return false;
|
|
1726
|
+
}
|
|
1727
|
+
const afterDb = rest.slice(slash + 1);
|
|
1728
|
+
return afterDb === "auth" || afterDb.startsWith("auth/");
|
|
1729
|
+
}
|
|
1730
|
+
function readBodyToken(bodyText) {
|
|
1731
|
+
if (bodyText == null || bodyText.trim().length === 0) {
|
|
1732
|
+
return void 0;
|
|
1733
|
+
}
|
|
1734
|
+
try {
|
|
1735
|
+
const parsed = JSON.parse(bodyText);
|
|
1736
|
+
if (parsed !== null && typeof parsed === "object" && "token" in parsed && typeof parsed.token === "string") {
|
|
1737
|
+
return parsed.token;
|
|
1738
|
+
}
|
|
1739
|
+
} catch {
|
|
1740
|
+
}
|
|
1741
|
+
return void 0;
|
|
1742
|
+
}
|
|
1634
1743
|
|
|
1635
1744
|
// src/resilience/retry.ts
|
|
1636
1745
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -2063,6 +2172,48 @@ function databasePath2(db) {
|
|
|
2063
2172
|
return `/api/databases/${encodeURIComponent(db)}`;
|
|
2064
2173
|
}
|
|
2065
2174
|
|
|
2175
|
+
// src/consistency-token-store.ts
|
|
2176
|
+
var MemoryConsistencyTokenStore = class {
|
|
2177
|
+
constructor() {
|
|
2178
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
2179
|
+
}
|
|
2180
|
+
get(database) {
|
|
2181
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2182
|
+
throw new Error("database must be a non-empty string");
|
|
2183
|
+
}
|
|
2184
|
+
return this.tokens.get(normalizeKey(database));
|
|
2185
|
+
}
|
|
2186
|
+
observe(database, token) {
|
|
2187
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2188
|
+
throw new Error("database must be a non-empty string");
|
|
2189
|
+
}
|
|
2190
|
+
if (token == null || token.trim().length === 0) {
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
const key = normalizeKey(database);
|
|
2194
|
+
const stored = this.tokens.get(key);
|
|
2195
|
+
if (stored === void 0 || compareOrdinal(token, stored) > 0) {
|
|
2196
|
+
this.tokens.set(key, token);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
};
|
|
2200
|
+
function compareOrdinal(left, right) {
|
|
2201
|
+
if (left === right) return 0;
|
|
2202
|
+
return left < right ? -1 : 1;
|
|
2203
|
+
}
|
|
2204
|
+
function maxToken(left, right) {
|
|
2205
|
+
if (left == null || left.length === 0) {
|
|
2206
|
+
return right == null || right.length === 0 ? void 0 : right;
|
|
2207
|
+
}
|
|
2208
|
+
if (right == null || right.length === 0) {
|
|
2209
|
+
return left;
|
|
2210
|
+
}
|
|
2211
|
+
return compareOrdinal(left, right) >= 0 ? left : right;
|
|
2212
|
+
}
|
|
2213
|
+
function normalizeKey(database) {
|
|
2214
|
+
return database.toLowerCase();
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2066
2217
|
// src/streaming/subscription.ts
|
|
2067
2218
|
var AsyncEventQueue = class {
|
|
2068
2219
|
constructor() {
|
|
@@ -2119,7 +2270,7 @@ var AsyncEventQueue = class {
|
|
|
2119
2270
|
}
|
|
2120
2271
|
};
|
|
2121
2272
|
var TableSubscription = class {
|
|
2122
|
-
constructor(transport, identity, options = {}, onWarnings) {
|
|
2273
|
+
constructor(transport, identity, options = {}, onWarnings, store, database) {
|
|
2123
2274
|
this._queue = new AsyncEventQueue();
|
|
2124
2275
|
this._active = true;
|
|
2125
2276
|
this._started = false;
|
|
@@ -2135,6 +2286,11 @@ var TableSubscription = class {
|
|
|
2135
2286
|
this._onError = options.onError;
|
|
2136
2287
|
this._onWarnings = onWarnings;
|
|
2137
2288
|
this._conflate = options.conflate;
|
|
2289
|
+
this._atLeast = options.atLeast;
|
|
2290
|
+
this._waitMs = options.waitMs;
|
|
2291
|
+
this._onExceeded = options.onExceeded;
|
|
2292
|
+
this._store = store;
|
|
2293
|
+
this._database = database;
|
|
2138
2294
|
this._reconnectHandlerKey = `${this.id}::reconnect`;
|
|
2139
2295
|
}
|
|
2140
2296
|
get lastVersion() {
|
|
@@ -2199,7 +2355,7 @@ var TableSubscription = class {
|
|
|
2199
2355
|
id: this.id
|
|
2200
2356
|
};
|
|
2201
2357
|
if (this._identity.kind === "named") {
|
|
2202
|
-
message.
|
|
2358
|
+
message.name = this._identity.name;
|
|
2203
2359
|
if (this._identity.args !== void 0) {
|
|
2204
2360
|
message.args = this._identity.args;
|
|
2205
2361
|
}
|
|
@@ -2218,8 +2374,30 @@ var TableSubscription = class {
|
|
|
2218
2374
|
if (this._conflate !== void 0) {
|
|
2219
2375
|
message.conflate = this._conflate;
|
|
2220
2376
|
}
|
|
2377
|
+
const pin = this._resolvePin();
|
|
2378
|
+
if (pin !== void 0) {
|
|
2379
|
+
message.at_least = pin;
|
|
2380
|
+
}
|
|
2381
|
+
if (this._waitMs !== void 0) {
|
|
2382
|
+
message.wait_ms = this._waitMs;
|
|
2383
|
+
}
|
|
2384
|
+
if (this._onExceeded !== void 0) {
|
|
2385
|
+
message.on_exceeded = this._onExceeded;
|
|
2386
|
+
}
|
|
2221
2387
|
await this._transport.send(message);
|
|
2222
2388
|
}
|
|
2389
|
+
_resolvePin() {
|
|
2390
|
+
if (this._atLeast !== void 0 && this._store != null && this._database != null) {
|
|
2391
|
+
this._store.observe(this._database, this._atLeast);
|
|
2392
|
+
}
|
|
2393
|
+
const stored = this._store != null && this._database != null ? this._store.get(this._database) : void 0;
|
|
2394
|
+
return maxToken(this._atLeast, stored);
|
|
2395
|
+
}
|
|
2396
|
+
_observeToken(token) {
|
|
2397
|
+
if (token !== void 0 && this._store != null && this._database != null) {
|
|
2398
|
+
this._store.observe(this._database, token);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2223
2401
|
_handleMessage(message) {
|
|
2224
2402
|
if (!this._active) {
|
|
2225
2403
|
return;
|
|
@@ -2246,6 +2424,7 @@ var TableSubscription = class {
|
|
|
2246
2424
|
}
|
|
2247
2425
|
_handleSnapshotPage(message) {
|
|
2248
2426
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2427
|
+
this._observeToken(message.token);
|
|
2249
2428
|
}
|
|
2250
2429
|
_handleSnapshotComplete(message) {
|
|
2251
2430
|
this._lastVersion = message.version;
|
|
@@ -2263,6 +2442,10 @@ var TableSubscription = class {
|
|
|
2263
2442
|
if (message.total_matches !== void 0) {
|
|
2264
2443
|
snapshot.totalMatches = message.total_matches;
|
|
2265
2444
|
}
|
|
2445
|
+
if (message.token !== void 0) {
|
|
2446
|
+
snapshot.token = message.token;
|
|
2447
|
+
this._observeToken(message.token);
|
|
2448
|
+
}
|
|
2266
2449
|
this._queue.push(snapshot);
|
|
2267
2450
|
}
|
|
2268
2451
|
async _handleGap(message) {
|
|
@@ -2288,6 +2471,10 @@ var TableSubscription = class {
|
|
|
2288
2471
|
if (message.values_skipped !== void 0) {
|
|
2289
2472
|
event.values_skipped = message.values_skipped;
|
|
2290
2473
|
}
|
|
2474
|
+
if (message.token !== void 0) {
|
|
2475
|
+
event.token = message.token;
|
|
2476
|
+
this._observeToken(message.token);
|
|
2477
|
+
}
|
|
2291
2478
|
this._onChange?.(event);
|
|
2292
2479
|
this._queue.push(event);
|
|
2293
2480
|
}
|
|
@@ -2435,8 +2622,11 @@ var TableWriteStream = class {
|
|
|
2435
2622
|
resolve?.();
|
|
2436
2623
|
}
|
|
2437
2624
|
_handleServerError(message) {
|
|
2625
|
+
const rowErrors = Array.isArray(message.errors) && message.errors.length > 0 ? message.errors : void 0;
|
|
2438
2626
|
const error = new AoudaConnectionError(
|
|
2439
|
-
`Write stream error (${message.code}): ${message.message}
|
|
2627
|
+
`Write stream error (${message.code}): ${message.message}`,
|
|
2628
|
+
void 0,
|
|
2629
|
+
rowErrors
|
|
2440
2630
|
);
|
|
2441
2631
|
const openReject = this._openReject;
|
|
2442
2632
|
this._openResolve = null;
|
|
@@ -2632,11 +2822,12 @@ var TableQuery = class _TableQuery {
|
|
|
2632
2822
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2633
2823
|
* @internal Use `client.table()` to create queries.
|
|
2634
2824
|
*/
|
|
2635
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
2825
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2636
2826
|
this.transport = transport;
|
|
2637
2827
|
this.tableName = tableName;
|
|
2638
2828
|
this.database = database;
|
|
2639
2829
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
2830
|
+
this.store = store;
|
|
2640
2831
|
this.state = state ?? {
|
|
2641
2832
|
predicates: [],
|
|
2642
2833
|
groupClauses: [],
|
|
@@ -2652,6 +2843,16 @@ var TableQuery = class _TableQuery {
|
|
|
2652
2843
|
isDistinct: false
|
|
2653
2844
|
};
|
|
2654
2845
|
}
|
|
2846
|
+
withState(state) {
|
|
2847
|
+
return new _TableQuery(
|
|
2848
|
+
this.transport,
|
|
2849
|
+
this.tableName,
|
|
2850
|
+
this.database,
|
|
2851
|
+
state,
|
|
2852
|
+
this.getWebSocketTransport,
|
|
2853
|
+
this.store
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2655
2856
|
where(column, operator, value) {
|
|
2656
2857
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2657
2858
|
return new _TableQuery(
|
|
@@ -2662,7 +2863,8 @@ var TableQuery = class _TableQuery {
|
|
|
2662
2863
|
...this.state,
|
|
2663
2864
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2664
2865
|
},
|
|
2665
|
-
this.getWebSocketTransport
|
|
2866
|
+
this.getWebSocketTransport,
|
|
2867
|
+
this.store
|
|
2666
2868
|
);
|
|
2667
2869
|
}
|
|
2668
2870
|
/**
|
|
@@ -2681,7 +2883,7 @@ var TableQuery = class _TableQuery {
|
|
|
2681
2883
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2682
2884
|
...this.state,
|
|
2683
2885
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2684
|
-
}, this.getWebSocketTransport);
|
|
2886
|
+
}, this.getWebSocketTransport, this.store);
|
|
2685
2887
|
}
|
|
2686
2888
|
/**
|
|
2687
2889
|
* Sets the primary sort column for the query.
|
|
@@ -2706,7 +2908,7 @@ var TableQuery = class _TableQuery {
|
|
|
2706
2908
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2707
2909
|
...this.state,
|
|
2708
2910
|
orderByClauses: [orderByClause]
|
|
2709
|
-
}, this.getWebSocketTransport);
|
|
2911
|
+
}, this.getWebSocketTransport, this.store);
|
|
2710
2912
|
}
|
|
2711
2913
|
/**
|
|
2712
2914
|
* Sets the primary sort column to descending order.
|
|
@@ -2752,7 +2954,7 @@ var TableQuery = class _TableQuery {
|
|
|
2752
2954
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2753
2955
|
...this.state,
|
|
2754
2956
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
2755
|
-
}, this.getWebSocketTransport);
|
|
2957
|
+
}, this.getWebSocketTransport, this.store);
|
|
2756
2958
|
}
|
|
2757
2959
|
/**
|
|
2758
2960
|
* Sets the maximum number of rows to return.
|
|
@@ -2769,7 +2971,7 @@ var TableQuery = class _TableQuery {
|
|
|
2769
2971
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2770
2972
|
...this.state,
|
|
2771
2973
|
limitValue: count
|
|
2772
|
-
}, this.getWebSocketTransport);
|
|
2974
|
+
}, this.getWebSocketTransport, this.store);
|
|
2773
2975
|
}
|
|
2774
2976
|
/**
|
|
2775
2977
|
* Sets the number of rows to skip.
|
|
@@ -2786,7 +2988,7 @@ var TableQuery = class _TableQuery {
|
|
|
2786
2988
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2787
2989
|
...this.state,
|
|
2788
2990
|
offsetValue: count
|
|
2789
|
-
}, this.getWebSocketTransport);
|
|
2991
|
+
}, this.getWebSocketTransport, this.store);
|
|
2790
2992
|
}
|
|
2791
2993
|
/**
|
|
2792
2994
|
* Requests cross-partition access for this query.
|
|
@@ -2801,10 +3003,21 @@ var TableQuery = class _TableQuery {
|
|
|
2801
3003
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2802
3004
|
...this.state,
|
|
2803
3005
|
crossPartitionAccess: true
|
|
2804
|
-
}, this.getWebSocketTransport);
|
|
3006
|
+
}, this.getWebSocketTransport, this.store);
|
|
2805
3007
|
}
|
|
2806
3008
|
/**
|
|
2807
|
-
*
|
|
3009
|
+
* Pin this query at at least this C-1 token. Observes the token into the
|
|
3010
|
+
* client store (I3, sticky) and presents it on execute via `X-Aouda-Token`.
|
|
3011
|
+
*/
|
|
3012
|
+
atLeast(token) {
|
|
3013
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
3014
|
+
throw new Error("atLeast() requires a non-empty token");
|
|
3015
|
+
}
|
|
3016
|
+
this.store?.observe(this.database, token);
|
|
3017
|
+
return this.withState({ ...this.state, atLeast: token });
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* Selects specific columns to return.
|
|
2808
3021
|
* If not called, all columns are returned.
|
|
2809
3022
|
*
|
|
2810
3023
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -2826,7 +3039,7 @@ var TableQuery = class _TableQuery {
|
|
|
2826
3039
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2827
3040
|
...this.state,
|
|
2828
3041
|
selectColumns: columns.length > 0 ? columns : null
|
|
2829
|
-
}, this.getWebSocketTransport);
|
|
3042
|
+
}, this.getWebSocketTransport, this.store);
|
|
2830
3043
|
}
|
|
2831
3044
|
/**
|
|
2832
3045
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -2856,7 +3069,7 @@ var TableQuery = class _TableQuery {
|
|
|
2856
3069
|
...this.state,
|
|
2857
3070
|
selectColumns: columns,
|
|
2858
3071
|
isDistinct: true
|
|
2859
|
-
}, this.getWebSocketTransport);
|
|
3072
|
+
}, this.getWebSocketTransport, this.store);
|
|
2860
3073
|
}
|
|
2861
3074
|
/**
|
|
2862
3075
|
* Adds server-side computed columns to the query result.
|
|
@@ -2865,6 +3078,12 @@ var TableQuery = class _TableQuery {
|
|
|
2865
3078
|
* evaluated per row on the server. Computed columns are appended after any physical-column
|
|
2866
3079
|
* `select()` projection.
|
|
2867
3080
|
*
|
|
3081
|
+
* Result types are inferred by the server where the expression permits
|
|
3082
|
+
* (e.g. Int32 → `number`). Uninferable expressions use wire `"Unknown"` /
|
|
3083
|
+
* codegen `unknown`. Computed columns are always nullable. Named-query
|
|
3084
|
+
* `*Row` properties pick this up when regenerated against a post-S08 server.
|
|
3085
|
+
* See aouda-docs/guides/browser-tier-read-limits.md#selectexpr-result-types
|
|
3086
|
+
*
|
|
2868
3087
|
* @param projections - One or more `{ alias, expr }` pairs.
|
|
2869
3088
|
* @returns A new TableQuery with computed columns set.
|
|
2870
3089
|
*
|
|
@@ -2885,7 +3104,7 @@ var TableQuery = class _TableQuery {
|
|
|
2885
3104
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2886
3105
|
...this.state,
|
|
2887
3106
|
selectExprs: projections
|
|
2888
|
-
}, this.getWebSocketTransport);
|
|
3107
|
+
}, this.getWebSocketTransport, this.store);
|
|
2889
3108
|
}
|
|
2890
3109
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
2891
3110
|
return this.addJoinClause(
|
|
@@ -2943,7 +3162,8 @@ var TableQuery = class _TableQuery {
|
|
|
2943
3162
|
}
|
|
2944
3163
|
]
|
|
2945
3164
|
},
|
|
2946
|
-
this.getWebSocketTransport
|
|
3165
|
+
this.getWebSocketTransport,
|
|
3166
|
+
this.store
|
|
2947
3167
|
);
|
|
2948
3168
|
}
|
|
2949
3169
|
/**
|
|
@@ -2979,7 +3199,8 @@ var TableQuery = class _TableQuery {
|
|
|
2979
3199
|
...this.state,
|
|
2980
3200
|
groupByColumns: [...columns]
|
|
2981
3201
|
},
|
|
2982
|
-
this.getWebSocketTransport
|
|
3202
|
+
this.getWebSocketTransport,
|
|
3203
|
+
this.store
|
|
2983
3204
|
);
|
|
2984
3205
|
}
|
|
2985
3206
|
/**
|
|
@@ -3013,8 +3234,11 @@ var TableQuery = class _TableQuery {
|
|
|
3013
3234
|
onSnapshot: options.onSnapshot,
|
|
3014
3235
|
onChange: options.onChange,
|
|
3015
3236
|
onError: options.onError,
|
|
3016
|
-
conflate: options.conflate
|
|
3017
|
-
|
|
3237
|
+
conflate: options.conflate,
|
|
3238
|
+
atLeast: options.atLeast ?? this.state.atLeast,
|
|
3239
|
+
waitMs: options.waitMs,
|
|
3240
|
+
onExceeded: options.onExceeded
|
|
3241
|
+
}, void 0, this.store, this.database);
|
|
3018
3242
|
subscription.start();
|
|
3019
3243
|
return subscription;
|
|
3020
3244
|
}
|
|
@@ -3129,7 +3353,8 @@ var TableQuery = class _TableQuery {
|
|
|
3129
3353
|
...this.state,
|
|
3130
3354
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3131
3355
|
},
|
|
3132
|
-
this.getWebSocketTransport
|
|
3356
|
+
this.getWebSocketTransport,
|
|
3357
|
+
this.store
|
|
3133
3358
|
);
|
|
3134
3359
|
}
|
|
3135
3360
|
addAggregate(op, column) {
|
|
@@ -3150,7 +3375,8 @@ var TableQuery = class _TableQuery {
|
|
|
3150
3375
|
}
|
|
3151
3376
|
]
|
|
3152
3377
|
},
|
|
3153
|
-
this.getWebSocketTransport
|
|
3378
|
+
this.getWebSocketTransport,
|
|
3379
|
+
this.store
|
|
3154
3380
|
);
|
|
3155
3381
|
}
|
|
3156
3382
|
requireWebSocketTransport() {
|
|
@@ -3180,17 +3406,23 @@ var TableQuery = class _TableQuery {
|
|
|
3180
3406
|
* ```
|
|
3181
3407
|
*/
|
|
3182
3408
|
async execute() {
|
|
3409
|
+
if (this.state.atLeast) {
|
|
3410
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3411
|
+
}
|
|
3183
3412
|
const request = this.buildRequest();
|
|
3184
3413
|
const path = `${databasePath2(this.database)}/query`;
|
|
3185
3414
|
const response = await this.transport.post(path, request);
|
|
3186
3415
|
const rows = columnarToRows(response);
|
|
3187
3416
|
const stats = response.stats;
|
|
3188
|
-
return { rows, stats };
|
|
3417
|
+
return { rows, stats, token: response.token };
|
|
3189
3418
|
}
|
|
3190
3419
|
/**
|
|
3191
3420
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3192
3421
|
*/
|
|
3193
3422
|
async toColumnar() {
|
|
3423
|
+
if (this.state.atLeast) {
|
|
3424
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3425
|
+
}
|
|
3194
3426
|
const request = this.buildRequest();
|
|
3195
3427
|
const path = `${databasePath2(this.database)}/query`;
|
|
3196
3428
|
return this.transport.post(path, request);
|
|
@@ -3220,8 +3452,12 @@ var TableQuery = class _TableQuery {
|
|
|
3220
3452
|
limitValue: 0,
|
|
3221
3453
|
selectColumns: []
|
|
3222
3454
|
},
|
|
3223
|
-
this.getWebSocketTransport
|
|
3455
|
+
this.getWebSocketTransport,
|
|
3456
|
+
this.store
|
|
3224
3457
|
);
|
|
3458
|
+
if (this.state.atLeast) {
|
|
3459
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3460
|
+
}
|
|
3225
3461
|
const request = countQuery.buildRequest();
|
|
3226
3462
|
const path = `${databasePath2(this.database)}/query`;
|
|
3227
3463
|
const response = await this.transport.post(path, request);
|
|
@@ -3268,7 +3504,8 @@ var TableQuery = class _TableQuery {
|
|
|
3268
3504
|
const response = await this.transport.post(path, body);
|
|
3269
3505
|
const result = {
|
|
3270
3506
|
rowsInserted: response.rowsInserted,
|
|
3271
|
-
executionMs: response.executionMs
|
|
3507
|
+
executionMs: response.executionMs,
|
|
3508
|
+
token: response.token
|
|
3272
3509
|
};
|
|
3273
3510
|
if (response.generatedValues !== void 0) {
|
|
3274
3511
|
result.generatedValues = response.generatedValues;
|
|
@@ -3318,7 +3555,8 @@ var TableQuery = class _TableQuery {
|
|
|
3318
3555
|
const response = await this.transport.post(path, body);
|
|
3319
3556
|
const result = {
|
|
3320
3557
|
rowsInserted: response.rowsInserted,
|
|
3321
|
-
executionMs: response.executionMs
|
|
3558
|
+
executionMs: response.executionMs,
|
|
3559
|
+
token: response.token
|
|
3322
3560
|
};
|
|
3323
3561
|
if (response.generatedValues !== void 0) {
|
|
3324
3562
|
result.generatedValues = response.generatedValues;
|
|
@@ -3370,6 +3608,7 @@ var TableQuery = class _TableQuery {
|
|
|
3370
3608
|
return {
|
|
3371
3609
|
rowsAffected: response.rowsUpdated,
|
|
3372
3610
|
executionMs: response.executionMs,
|
|
3611
|
+
token: response.token,
|
|
3373
3612
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3374
3613
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3375
3614
|
};
|
|
@@ -3420,6 +3659,7 @@ var TableQuery = class _TableQuery {
|
|
|
3420
3659
|
rowsAffected: response.rowsDeleted,
|
|
3421
3660
|
executionMs: response.executionMs,
|
|
3422
3661
|
hasMore: response.hasMore,
|
|
3662
|
+
token: response.token,
|
|
3423
3663
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3424
3664
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3425
3665
|
};
|
|
@@ -3439,7 +3679,8 @@ var TableQuery = class _TableQuery {
|
|
|
3439
3679
|
return {
|
|
3440
3680
|
rowsAffected: response.rowsDeleted,
|
|
3441
3681
|
executionMs: response.executionMs,
|
|
3442
|
-
hasMore: false
|
|
3682
|
+
hasMore: false,
|
|
3683
|
+
token: response.token
|
|
3443
3684
|
};
|
|
3444
3685
|
}
|
|
3445
3686
|
/**
|
|
@@ -3452,7 +3693,14 @@ var TableQuery = class _TableQuery {
|
|
|
3452
3693
|
throw new Error("batch() requires a non-empty operations array");
|
|
3453
3694
|
}
|
|
3454
3695
|
const wireOperations = operations.map((op, index) => {
|
|
3455
|
-
const base = new _TableQuery(
|
|
3696
|
+
const base = new _TableQuery(
|
|
3697
|
+
this.transport,
|
|
3698
|
+
this.tableName,
|
|
3699
|
+
this.database,
|
|
3700
|
+
void 0,
|
|
3701
|
+
this.getWebSocketTransport,
|
|
3702
|
+
this.store
|
|
3703
|
+
);
|
|
3456
3704
|
const scoped = op.where(base);
|
|
3457
3705
|
const where = scoped.buildWhereClause();
|
|
3458
3706
|
if (!where) {
|
|
@@ -4820,12 +5068,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
4820
5068
|
continue;
|
|
4821
5069
|
}
|
|
4822
5070
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
4823
|
-
const
|
|
5071
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
4824
5072
|
sink({
|
|
4825
5073
|
code: warning.code,
|
|
4826
|
-
|
|
5074
|
+
name: warning.name,
|
|
4827
5075
|
sunsetAt: warning.sunsetAt,
|
|
4828
|
-
message: `${warning.code}:${
|
|
5076
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
4829
5077
|
});
|
|
4830
5078
|
}
|
|
4831
5079
|
}
|
|
@@ -4838,24 +5086,28 @@ function emptyStats() {
|
|
|
4838
5086
|
};
|
|
4839
5087
|
}
|
|
4840
5088
|
var NamedQueriesApi = class {
|
|
4841
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5089
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
4842
5090
|
this.transport = transport;
|
|
4843
5091
|
this.database = database;
|
|
4844
5092
|
this.onWarning = onWarning;
|
|
4845
5093
|
this.getStreamingTransport = getStreamingTransport;
|
|
5094
|
+
this.store = store;
|
|
4846
5095
|
}
|
|
4847
|
-
async execute(
|
|
4848
|
-
if (typeof
|
|
4849
|
-
throw new Error("Named query
|
|
5096
|
+
async execute(name, args, options) {
|
|
5097
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5098
|
+
throw new Error("Named query name must be a non-empty string");
|
|
4850
5099
|
}
|
|
4851
5100
|
const prefix = databasePath2(this.database);
|
|
4852
|
-
const path = `${prefix}/named-queries/${encodeURIComponent(
|
|
5101
|
+
const path = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
4853
5102
|
const body = {
|
|
4854
5103
|
args: args ?? {}
|
|
4855
5104
|
};
|
|
4856
5105
|
if (options?.orderByIndex !== void 0) {
|
|
4857
5106
|
body.orderByIndex = options.orderByIndex;
|
|
4858
5107
|
}
|
|
5108
|
+
if (options?.atLeast !== void 0) {
|
|
5109
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5110
|
+
}
|
|
4859
5111
|
const response = await this.transport.post(
|
|
4860
5112
|
path,
|
|
4861
5113
|
body,
|
|
@@ -4867,7 +5119,8 @@ var NamedQueriesApi = class {
|
|
|
4867
5119
|
rows,
|
|
4868
5120
|
stats: response.stats,
|
|
4869
5121
|
warnings: response.warnings,
|
|
4870
|
-
totalMatches: response.totalMatches
|
|
5122
|
+
totalMatches: response.totalMatches,
|
|
5123
|
+
token: response.token
|
|
4871
5124
|
};
|
|
4872
5125
|
}
|
|
4873
5126
|
async batch(items, options) {
|
|
@@ -4885,6 +5138,9 @@ var NamedQueriesApi = class {
|
|
|
4885
5138
|
400
|
|
4886
5139
|
);
|
|
4887
5140
|
}
|
|
5141
|
+
if (options?.atLeast !== void 0) {
|
|
5142
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5143
|
+
}
|
|
4888
5144
|
const prefix = databasePath2(this.database);
|
|
4889
5145
|
const path = `${prefix}/named-queries/batch?format=columnar`;
|
|
4890
5146
|
const envelope = await this.transport.post(
|
|
@@ -4907,34 +5163,41 @@ var NamedQueriesApi = class {
|
|
|
4907
5163
|
rowCount: slot.rowCount ?? 0,
|
|
4908
5164
|
stats: slot.stats ?? emptyStats(),
|
|
4909
5165
|
warnings: slot.warnings,
|
|
4910
|
-
totalMatches: slot.totalMatches
|
|
5166
|
+
totalMatches: slot.totalMatches,
|
|
5167
|
+
token: slot.token
|
|
4911
5168
|
};
|
|
4912
5169
|
const result = {
|
|
4913
5170
|
rows: columnarToRows(columnar),
|
|
4914
5171
|
stats: columnar.stats,
|
|
4915
5172
|
warnings: slot.warnings,
|
|
4916
|
-
totalMatches: slot.totalMatches
|
|
5173
|
+
totalMatches: slot.totalMatches,
|
|
5174
|
+
token: slot.token
|
|
4917
5175
|
};
|
|
4918
5176
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
4919
5177
|
return { isError: false, result };
|
|
4920
5178
|
});
|
|
4921
5179
|
}
|
|
4922
|
-
subscribe(
|
|
4923
|
-
if (typeof
|
|
4924
|
-
throw new Error("Named query
|
|
5180
|
+
subscribe(name, args, options = {}) {
|
|
5181
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5182
|
+
throw new Error("Named query name must be a non-empty string");
|
|
4925
5183
|
}
|
|
4926
5184
|
const subscription = new TableSubscription(
|
|
4927
5185
|
this.getStreamingTransport(),
|
|
4928
|
-
{ kind: "named",
|
|
5186
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
4929
5187
|
{
|
|
4930
5188
|
onSnapshot: options.onSnapshot,
|
|
4931
5189
|
onChange: options.onChange,
|
|
4932
5190
|
onError: options.onError,
|
|
4933
|
-
conflate: options.conflate
|
|
5191
|
+
conflate: options.conflate,
|
|
5192
|
+
atLeast: options.atLeast,
|
|
5193
|
+
waitMs: options.waitMs,
|
|
5194
|
+
onExceeded: options.onExceeded
|
|
4934
5195
|
},
|
|
4935
5196
|
(warnings) => {
|
|
4936
5197
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
4937
|
-
}
|
|
5198
|
+
},
|
|
5199
|
+
this.store,
|
|
5200
|
+
this.database
|
|
4938
5201
|
);
|
|
4939
5202
|
subscription.start();
|
|
4940
5203
|
return subscription;
|
|
@@ -4946,12 +5209,12 @@ var NamedMutationsApi = class {
|
|
|
4946
5209
|
this.database = database;
|
|
4947
5210
|
this.onWarning = onWarning;
|
|
4948
5211
|
}
|
|
4949
|
-
async execute(
|
|
4950
|
-
if (typeof
|
|
4951
|
-
throw new Error("Named mutation
|
|
5212
|
+
async execute(name, args) {
|
|
5213
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5214
|
+
throw new Error("Named mutation name must be a non-empty string");
|
|
4952
5215
|
}
|
|
4953
5216
|
const prefix = databasePath2(this.database);
|
|
4954
|
-
const path = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5217
|
+
const path = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
4955
5218
|
const wire = await this.transport.post(path, {
|
|
4956
5219
|
args: args ?? {}
|
|
4957
5220
|
});
|
|
@@ -5012,6 +5275,7 @@ var WebSocketTransport = class {
|
|
|
5012
5275
|
// Serialized-send queue: each send appends to this tail.
|
|
5013
5276
|
this._sendTail = Promise.resolve();
|
|
5014
5277
|
this._lastVersion = 0;
|
|
5278
|
+
this._lastToken = null;
|
|
5015
5279
|
this._reconnectAttempt = 0;
|
|
5016
5280
|
this._disposed = false;
|
|
5017
5281
|
this._missedPings = 0;
|
|
@@ -5029,6 +5293,7 @@ var WebSocketTransport = class {
|
|
|
5029
5293
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
5030
5294
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
5031
5295
|
this._enableCompression = options.enableCompression ?? true;
|
|
5296
|
+
this._store = options.consistencyTokenStore;
|
|
5032
5297
|
this._wireMode = options.wireMode ?? "json";
|
|
5033
5298
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
5034
5299
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -5037,10 +5302,14 @@ var WebSocketTransport = class {
|
|
|
5037
5302
|
});
|
|
5038
5303
|
}
|
|
5039
5304
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
5040
|
-
/** Latest
|
|
5305
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
5041
5306
|
get lastVersion() {
|
|
5042
5307
|
return this._lastVersion;
|
|
5043
5308
|
}
|
|
5309
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5310
|
+
get lastToken() {
|
|
5311
|
+
return this._lastToken;
|
|
5312
|
+
}
|
|
5044
5313
|
/**
|
|
5045
5314
|
* Registers a handler for incoming server messages with the given channel id.
|
|
5046
5315
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5228,6 +5497,10 @@ var WebSocketTransport = class {
|
|
|
5228
5497
|
}
|
|
5229
5498
|
case "heartbeat":
|
|
5230
5499
|
this._lastVersion = msg.version;
|
|
5500
|
+
this._lastToken = msg.token ?? null;
|
|
5501
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5502
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5503
|
+
}
|
|
5231
5504
|
break;
|
|
5232
5505
|
case "pong":
|
|
5233
5506
|
this._missedPings = 0;
|
|
@@ -5393,16 +5666,21 @@ var LongPollTransport = class {
|
|
|
5393
5666
|
this._connected = false;
|
|
5394
5667
|
this._pollTask = null;
|
|
5395
5668
|
this._lastVersion = 0;
|
|
5669
|
+
this._lastToken = null;
|
|
5396
5670
|
this._serverUrl = serverUrl;
|
|
5397
5671
|
this._database = database;
|
|
5398
5672
|
this._authHandler = options.authHandler;
|
|
5399
5673
|
this._onReconnected = options.onReconnected;
|
|
5400
5674
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5401
5675
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5676
|
+
this._store = options.consistencyTokenStore;
|
|
5402
5677
|
}
|
|
5403
5678
|
get lastVersion() {
|
|
5404
5679
|
return this._lastVersion;
|
|
5405
5680
|
}
|
|
5681
|
+
get lastToken() {
|
|
5682
|
+
return this._lastToken;
|
|
5683
|
+
}
|
|
5406
5684
|
registerHandler(id, handler) {
|
|
5407
5685
|
this._handlers.set(id, handler);
|
|
5408
5686
|
}
|
|
@@ -5525,6 +5803,10 @@ var LongPollTransport = class {
|
|
|
5525
5803
|
for (const msg of payload.messages) {
|
|
5526
5804
|
if (msg.type === "heartbeat") {
|
|
5527
5805
|
this._lastVersion = msg.version;
|
|
5806
|
+
this._lastToken = msg.token ?? null;
|
|
5807
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5808
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5809
|
+
}
|
|
5528
5810
|
}
|
|
5529
5811
|
const id = "id" in msg ? msg.id : void 0;
|
|
5530
5812
|
if (id !== void 0 && id !== null) {
|
|
@@ -5604,6 +5886,9 @@ var FallbackStreamingTransport = class {
|
|
|
5604
5886
|
get lastVersion() {
|
|
5605
5887
|
return this._active.lastVersion;
|
|
5606
5888
|
}
|
|
5889
|
+
get lastToken() {
|
|
5890
|
+
return this._active.lastToken;
|
|
5891
|
+
}
|
|
5607
5892
|
registerHandler(id, handler) {
|
|
5608
5893
|
this._handlers.set(id, handler);
|
|
5609
5894
|
this._active.registerHandler(id, handler);
|
|
@@ -5683,6 +5968,7 @@ var AoudaClient = class {
|
|
|
5683
5968
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5684
5969
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5685
5970
|
this.database = options.database.trim();
|
|
5971
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5686
5972
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5687
5973
|
throw new Error("timeout must be a finite positive number");
|
|
5688
5974
|
}
|
|
@@ -5717,7 +6003,9 @@ var AoudaClient = class {
|
|
|
5717
6003
|
}
|
|
5718
6004
|
const httpTransport = new HttpTransport({
|
|
5719
6005
|
baseUrl: this.baseUrl,
|
|
5720
|
-
timeout: this.timeout
|
|
6006
|
+
timeout: this.timeout,
|
|
6007
|
+
database: this.database,
|
|
6008
|
+
consistencyTokenStore: this._store
|
|
5721
6009
|
});
|
|
5722
6010
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5723
6011
|
if (activeAuth) {
|
|
@@ -5777,7 +6065,8 @@ var AoudaClient = class {
|
|
|
5777
6065
|
this.transport,
|
|
5778
6066
|
this.database,
|
|
5779
6067
|
onNamedArtifactWarning,
|
|
5780
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6068
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6069
|
+
this._store
|
|
5781
6070
|
);
|
|
5782
6071
|
this._namedMutations = new NamedMutationsApi(
|
|
5783
6072
|
this.transport,
|
|
@@ -5876,7 +6165,8 @@ var AoudaClient = class {
|
|
|
5876
6165
|
name,
|
|
5877
6166
|
this.database,
|
|
5878
6167
|
void 0,
|
|
5879
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6168
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6169
|
+
this._store
|
|
5880
6170
|
);
|
|
5881
6171
|
}
|
|
5882
6172
|
/**
|
|
@@ -5928,13 +6218,26 @@ var AoudaClient = class {
|
|
|
5928
6218
|
return this._materializedQueries;
|
|
5929
6219
|
}
|
|
5930
6220
|
/**
|
|
5931
|
-
*
|
|
6221
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
5932
6222
|
*/
|
|
5933
6223
|
get namedQueries() {
|
|
5934
6224
|
return this._namedQueries;
|
|
5935
6225
|
}
|
|
6226
|
+
observeConsistencyToken(token) {
|
|
6227
|
+
this._store.observe(this.database, token);
|
|
6228
|
+
}
|
|
6229
|
+
getObservedConsistencyToken() {
|
|
6230
|
+
return this._store.get(this.database);
|
|
6231
|
+
}
|
|
6232
|
+
async getConsistencyToken() {
|
|
6233
|
+
const body = await this.transport.get(
|
|
6234
|
+
`/api/databases/${encodeURIComponent(this.database)}/token`
|
|
6235
|
+
);
|
|
6236
|
+
this._store.observe(this.database, body.token);
|
|
6237
|
+
return this._store.get(this.database) ?? body.token;
|
|
6238
|
+
}
|
|
5936
6239
|
/**
|
|
5937
|
-
*
|
|
6240
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
5938
6241
|
*/
|
|
5939
6242
|
get namedMutations() {
|
|
5940
6243
|
return this._namedMutations;
|
|
@@ -6061,13 +6364,15 @@ var AoudaClient = class {
|
|
|
6061
6364
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
6062
6365
|
authHandler: this._authHandler,
|
|
6063
6366
|
enableCompression: this._streamingEnableCompression,
|
|
6064
|
-
wireMode: this._streamingWireMode
|
|
6367
|
+
wireMode: this._streamingWireMode,
|
|
6368
|
+
consistencyTokenStore: this._store
|
|
6065
6369
|
});
|
|
6066
6370
|
if (this._streamingEnableLongPollFallback) {
|
|
6067
6371
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
6068
6372
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
6069
6373
|
authHandler: this._authHandler,
|
|
6070
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6374
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6375
|
+
consistencyTokenStore: this._store
|
|
6071
6376
|
});
|
|
6072
6377
|
});
|
|
6073
6378
|
} else {
|
|
@@ -6365,6 +6670,7 @@ var version = package_default.version;
|
|
|
6365
6670
|
MaterializedQueriesApi,
|
|
6366
6671
|
MaterializedQueryState,
|
|
6367
6672
|
MaterializedQueryType,
|
|
6673
|
+
MemoryConsistencyTokenStore,
|
|
6368
6674
|
MetricsAdminApi,
|
|
6369
6675
|
NamedMutationsApi,
|
|
6370
6676
|
NamedQueriesApi,
|
|
@@ -6380,10 +6686,12 @@ var version = package_default.version;
|
|
|
6380
6686
|
applyLocalNetworkAccess,
|
|
6381
6687
|
coerceColumnarValue,
|
|
6382
6688
|
columnarToRows,
|
|
6689
|
+
compareOrdinal,
|
|
6383
6690
|
createAoudaClient,
|
|
6384
6691
|
createAoudaClusterMcpToolSet,
|
|
6385
6692
|
installLocalNetworkFetch,
|
|
6386
6693
|
localNetworkFetch,
|
|
6694
|
+
maxToken,
|
|
6387
6695
|
resolveTargetAddressSpace,
|
|
6388
6696
|
version
|
|
6389
6697
|
});
|