@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.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@aouda/client",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.16",
|
|
5
5
|
description: "Official TypeScript/JavaScript client library for Aouda",
|
|
6
6
|
type: "module",
|
|
7
7
|
main: "./dist/index.cjs",
|
|
@@ -111,9 +111,10 @@ var AoudaError = class extends Error {
|
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
113
|
var AoudaConnectionError = class extends AoudaError {
|
|
114
|
-
constructor(message, cause) {
|
|
114
|
+
constructor(message, cause, rowErrors) {
|
|
115
115
|
super(message);
|
|
116
116
|
this.cause = cause;
|
|
117
|
+
this.rowErrors = rowErrors;
|
|
117
118
|
this.name = "AoudaConnectionError";
|
|
118
119
|
}
|
|
119
120
|
};
|
|
@@ -133,43 +134,45 @@ var AoudaResponseError = class extends AoudaError {
|
|
|
133
134
|
}
|
|
134
135
|
};
|
|
135
136
|
var AoudaApiError = class extends AoudaError {
|
|
136
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
137
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
137
138
|
super(message);
|
|
138
139
|
this.code = code;
|
|
139
140
|
this.statusCode = statusCode;
|
|
140
141
|
this.details = details;
|
|
141
142
|
this.requestId = requestId;
|
|
142
143
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
144
|
+
this.token = token;
|
|
145
|
+
this.rowErrors = rowErrors;
|
|
143
146
|
this.name = "AoudaApiError";
|
|
144
147
|
}
|
|
145
148
|
};
|
|
146
149
|
var AoudaNotFoundError = class extends AoudaApiError {
|
|
147
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
148
|
-
super(message, code, statusCode, details, requestId);
|
|
150
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
151
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
149
152
|
this.name = "AoudaNotFoundError";
|
|
150
153
|
}
|
|
151
154
|
};
|
|
152
155
|
var AoudaConflictError = class extends AoudaApiError {
|
|
153
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
154
|
-
super(message, code, statusCode, details, requestId);
|
|
156
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
157
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
155
158
|
this.name = "AoudaConflictError";
|
|
156
159
|
}
|
|
157
160
|
};
|
|
158
161
|
var AoudaValidationError = class extends AoudaApiError {
|
|
159
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
160
|
-
super(message, code, statusCode, details, requestId);
|
|
162
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
163
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
161
164
|
this.name = "AoudaValidationError";
|
|
162
165
|
}
|
|
163
166
|
};
|
|
164
167
|
var AoudaServerError = class extends AoudaApiError {
|
|
165
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
166
|
-
super(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
168
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
169
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
167
170
|
this.name = "AoudaServerError";
|
|
168
171
|
}
|
|
169
172
|
};
|
|
170
173
|
var AoudaAuthenticationError = class extends AoudaApiError {
|
|
171
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
172
|
-
super(message, code, statusCode, details, requestId);
|
|
174
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors) {
|
|
175
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token, rowErrors);
|
|
173
176
|
this.name = "AoudaAuthenticationError";
|
|
174
177
|
}
|
|
175
178
|
};
|
|
@@ -981,7 +984,7 @@ function buildHandle(jobId, commitResp, wasResumed, transport, database, signal)
|
|
|
981
984
|
rowsDurablyCommitted: commitResp.rowsLoaded,
|
|
982
985
|
segmentsCreated: commitResp.segmentsCreated,
|
|
983
986
|
committedAtUtc: commitResp.committedAtUtc,
|
|
984
|
-
|
|
987
|
+
token: commitResp.token,
|
|
985
988
|
writeConcernSatisfied: commitResp.writeConcernAchieved ?? "acknowledged",
|
|
986
989
|
writeConcernTimedOut: commitResp.writeConcernTimedOut,
|
|
987
990
|
wasResumed,
|
|
@@ -1107,6 +1110,7 @@ var PROTOCOL_VERSION_HEADER = "X-Aouda-Protocol-Version";
|
|
|
1107
1110
|
var PROTOCOL_VERSION = "1";
|
|
1108
1111
|
var CONTENT_TYPE_JSON2 = "application/json";
|
|
1109
1112
|
var REQUEST_ID_HEADER2 = "X-Request-Id";
|
|
1113
|
+
var TOKEN_HEADER = "X-Aouda-Token";
|
|
1110
1114
|
var ERROR_CODE_MAP = {
|
|
1111
1115
|
TABLE_NOT_FOUND: AoudaNotFoundError,
|
|
1112
1116
|
COLUMN_NOT_FOUND: AoudaNotFoundError,
|
|
@@ -1121,6 +1125,10 @@ var ERROR_CODE_MAP = {
|
|
|
1121
1125
|
INVALID_OPERATOR: AoudaValidationError,
|
|
1122
1126
|
INVALID_COLUMN: AoudaValidationError,
|
|
1123
1127
|
INVALID_VALUE: AoudaValidationError,
|
|
1128
|
+
CONSTRAINT_CHECK_VIOLATION: AoudaValidationError,
|
|
1129
|
+
TRANSFORM_DERIVED_READONLY: AoudaValidationError,
|
|
1130
|
+
TRANSFORM_ROUTE_UNMATCHED: AoudaValidationError,
|
|
1131
|
+
TRANSFORM_ROUTE_AMBIGUOUS: AoudaValidationError,
|
|
1124
1132
|
UNSUPPORTED_VERSION: AoudaValidationError,
|
|
1125
1133
|
MALFORMED_REQUEST: AoudaValidationError,
|
|
1126
1134
|
INTERNAL_ERROR: AoudaServerError,
|
|
@@ -1146,7 +1154,12 @@ var ERROR_CODE_MAP = {
|
|
|
1146
1154
|
AUTH_IDENTITY_INVALID: AoudaValidationError,
|
|
1147
1155
|
AUTH_IDENTITY_NOT_FOUND: AoudaValidationError,
|
|
1148
1156
|
BULK_LOAD_TRANSFORM_INTENT_REQUIRED: AoudaValidationError,
|
|
1149
|
-
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError
|
|
1157
|
+
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError,
|
|
1158
|
+
TOKEN_MALFORMED: AoudaValidationError,
|
|
1159
|
+
TOKEN_FOREIGN_DATABASE: AoudaValidationError,
|
|
1160
|
+
TOKEN_EPOCH_SUPERSEDED: AoudaConflictError,
|
|
1161
|
+
TOKEN_UNSATISFIED: AoudaConflictError,
|
|
1162
|
+
TOKEN_FETCH_PRIMARY: AoudaApiError
|
|
1150
1163
|
};
|
|
1151
1164
|
function createComposedAbortController(...signals) {
|
|
1152
1165
|
const controller = new AbortController();
|
|
@@ -1176,6 +1189,9 @@ function parseRetryAfterSeconds(header) {
|
|
|
1176
1189
|
if (!Number.isFinite(n) || n < 0) return void 0;
|
|
1177
1190
|
return n;
|
|
1178
1191
|
}
|
|
1192
|
+
function nonEmptyRowErrors(rowErrors) {
|
|
1193
|
+
return Array.isArray(rowErrors) && rowErrors.length > 0 ? rowErrors : void 0;
|
|
1194
|
+
}
|
|
1179
1195
|
function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
1180
1196
|
const message = body.error ?? `${statusCode} ${statusText}`;
|
|
1181
1197
|
const code = body.code ?? "UNKNOWN";
|
|
@@ -1183,7 +1199,16 @@ function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
|
1183
1199
|
const requestId = body.requestId;
|
|
1184
1200
|
const retryAfterSeconds = parseRetryAfterSeconds(retryAfterHeader ?? null);
|
|
1185
1201
|
const Ctor = ERROR_CODE_MAP[code] ?? AoudaApiError;
|
|
1186
|
-
return new Ctor(
|
|
1202
|
+
return new Ctor(
|
|
1203
|
+
message,
|
|
1204
|
+
code,
|
|
1205
|
+
statusCode,
|
|
1206
|
+
details,
|
|
1207
|
+
requestId,
|
|
1208
|
+
retryAfterSeconds,
|
|
1209
|
+
body.token,
|
|
1210
|
+
nonEmptyRowErrors(body.rowErrors)
|
|
1211
|
+
);
|
|
1187
1212
|
}
|
|
1188
1213
|
var HttpTransport = class {
|
|
1189
1214
|
constructor(options) {
|
|
@@ -1195,6 +1220,29 @@ var HttpTransport = class {
|
|
|
1195
1220
|
...options.defaultHeaders
|
|
1196
1221
|
};
|
|
1197
1222
|
this.abortController = new AbortController();
|
|
1223
|
+
this.database = options.database;
|
|
1224
|
+
this.store = options.consistencyTokenStore;
|
|
1225
|
+
}
|
|
1226
|
+
presentTokenHeaders(path, headers) {
|
|
1227
|
+
if (this.store == null || this.database == null || isAuthPath(path)) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
const token = this.store.get(this.database);
|
|
1231
|
+
if (token != null && token.length > 0) {
|
|
1232
|
+
headers[TOKEN_HEADER] = token;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
observeResponse(_path, response, bodyText, errorCode) {
|
|
1236
|
+
if (this.store == null || this.database == null) {
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
if (errorCode === "TOKEN_MALFORMED" || errorCode === "TOKEN_FOREIGN_DATABASE") {
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
const header = response.headers.get(TOKEN_HEADER);
|
|
1243
|
+
const bodyToken = readBodyToken(bodyText);
|
|
1244
|
+
const token = header != null && header.trim().length > 0 ? header : bodyToken;
|
|
1245
|
+
this.store.observe(this.database, token);
|
|
1198
1246
|
}
|
|
1199
1247
|
/**
|
|
1200
1248
|
* Abort all in-flight and future requests (e.g. on client disconnect).
|
|
@@ -1232,6 +1280,7 @@ var HttpTransport = class {
|
|
|
1232
1280
|
...this.defaultHeaders,
|
|
1233
1281
|
...config.headers
|
|
1234
1282
|
};
|
|
1283
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1235
1284
|
if (config.body !== void 0 && config.body !== null) {
|
|
1236
1285
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1237
1286
|
}
|
|
@@ -1251,6 +1300,7 @@ var HttpTransport = class {
|
|
|
1251
1300
|
const text = await response.text();
|
|
1252
1301
|
if (config.allowStatuses?.includes(response.status) && text) {
|
|
1253
1302
|
try {
|
|
1303
|
+
this.observeResponse(config.path, response, text);
|
|
1254
1304
|
return JSON.parse(text);
|
|
1255
1305
|
} catch {
|
|
1256
1306
|
}
|
|
@@ -1264,15 +1314,20 @@ var HttpTransport = class {
|
|
|
1264
1314
|
}
|
|
1265
1315
|
if (response.status === 401) {
|
|
1266
1316
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1317
|
+
this.observeResponse(config.path, response, text, code);
|
|
1267
1318
|
throw new AoudaAuthenticationError(
|
|
1268
1319
|
errorBody?.error ?? "Unauthorized",
|
|
1269
1320
|
code,
|
|
1270
1321
|
401,
|
|
1271
1322
|
errorBody?.details,
|
|
1272
|
-
errorBody?.requestId
|
|
1323
|
+
errorBody?.requestId,
|
|
1324
|
+
void 0,
|
|
1325
|
+
errorBody?.token,
|
|
1326
|
+
nonEmptyRowErrors(errorBody?.rowErrors)
|
|
1273
1327
|
);
|
|
1274
1328
|
}
|
|
1275
1329
|
if (errorBody?.code != null) {
|
|
1330
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1276
1331
|
throw createApiError(
|
|
1277
1332
|
response.status,
|
|
1278
1333
|
response.statusText,
|
|
@@ -1280,6 +1335,7 @@ var HttpTransport = class {
|
|
|
1280
1335
|
response.headers.get("Retry-After")
|
|
1281
1336
|
);
|
|
1282
1337
|
}
|
|
1338
|
+
this.observeResponse(config.path, response, text);
|
|
1283
1339
|
throw new AoudaResponseError(
|
|
1284
1340
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1285
1341
|
response.status,
|
|
@@ -1287,6 +1343,7 @@ var HttpTransport = class {
|
|
|
1287
1343
|
);
|
|
1288
1344
|
}
|
|
1289
1345
|
const responseText = await response.text();
|
|
1346
|
+
this.observeResponse(config.path, response, responseText);
|
|
1290
1347
|
if (config.rawText) {
|
|
1291
1348
|
return responseText;
|
|
1292
1349
|
}
|
|
@@ -1347,6 +1404,7 @@ var HttpTransport = class {
|
|
|
1347
1404
|
...this.defaultHeaders,
|
|
1348
1405
|
...config.headers
|
|
1349
1406
|
};
|
|
1407
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1350
1408
|
if (config.rawBodyStr === void 0 && config.body !== void 0 && config.body !== null) {
|
|
1351
1409
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1352
1410
|
}
|
|
@@ -1363,6 +1421,7 @@ var HttpTransport = class {
|
|
|
1363
1421
|
try {
|
|
1364
1422
|
const response = await localNetworkFetch(url, init);
|
|
1365
1423
|
if (response.ok || config.allowStatuses?.includes(response.status)) {
|
|
1424
|
+
this.observeResponse(config.path, response, void 0);
|
|
1366
1425
|
return response;
|
|
1367
1426
|
}
|
|
1368
1427
|
const text = await response.text();
|
|
@@ -1375,15 +1434,20 @@ var HttpTransport = class {
|
|
|
1375
1434
|
}
|
|
1376
1435
|
if (response.status === 401) {
|
|
1377
1436
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1437
|
+
this.observeResponse(config.path, response, text, code);
|
|
1378
1438
|
throw new AoudaAuthenticationError(
|
|
1379
1439
|
errorBody?.error ?? "Unauthorized",
|
|
1380
1440
|
code,
|
|
1381
1441
|
401,
|
|
1382
1442
|
errorBody?.details,
|
|
1383
|
-
errorBody?.requestId
|
|
1443
|
+
errorBody?.requestId,
|
|
1444
|
+
void 0,
|
|
1445
|
+
errorBody?.token,
|
|
1446
|
+
nonEmptyRowErrors(errorBody?.rowErrors)
|
|
1384
1447
|
);
|
|
1385
1448
|
}
|
|
1386
1449
|
if (errorBody?.code != null) {
|
|
1450
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1387
1451
|
throw createApiError(
|
|
1388
1452
|
response.status,
|
|
1389
1453
|
response.statusText,
|
|
@@ -1391,6 +1455,7 @@ var HttpTransport = class {
|
|
|
1391
1455
|
response.headers.get("Retry-After")
|
|
1392
1456
|
);
|
|
1393
1457
|
}
|
|
1458
|
+
this.observeResponse(config.path, response, text);
|
|
1394
1459
|
throw new AoudaResponseError(
|
|
1395
1460
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1396
1461
|
response.status,
|
|
@@ -1545,6 +1610,47 @@ var HttpTransport = class {
|
|
|
1545
1610
|
});
|
|
1546
1611
|
}
|
|
1547
1612
|
};
|
|
1613
|
+
function isAuthPath(path) {
|
|
1614
|
+
let p = path;
|
|
1615
|
+
const q = p.indexOf("?");
|
|
1616
|
+
if (q >= 0) {
|
|
1617
|
+
p = p.slice(0, q);
|
|
1618
|
+
}
|
|
1619
|
+
if (/^https?:\/\//i.test(p)) {
|
|
1620
|
+
try {
|
|
1621
|
+
p = new URL(p).pathname;
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
const lower = p.toLowerCase();
|
|
1626
|
+
if (lower === "/api/auth" || lower.startsWith("/api/auth/")) {
|
|
1627
|
+
return true;
|
|
1628
|
+
}
|
|
1629
|
+
const prefix = "/api/databases/";
|
|
1630
|
+
if (!lower.startsWith(prefix)) {
|
|
1631
|
+
return false;
|
|
1632
|
+
}
|
|
1633
|
+
const rest = lower.slice(prefix.length);
|
|
1634
|
+
const slash = rest.indexOf("/");
|
|
1635
|
+
if (slash < 0) {
|
|
1636
|
+
return false;
|
|
1637
|
+
}
|
|
1638
|
+
const afterDb = rest.slice(slash + 1);
|
|
1639
|
+
return afterDb === "auth" || afterDb.startsWith("auth/");
|
|
1640
|
+
}
|
|
1641
|
+
function readBodyToken(bodyText) {
|
|
1642
|
+
if (bodyText == null || bodyText.trim().length === 0) {
|
|
1643
|
+
return void 0;
|
|
1644
|
+
}
|
|
1645
|
+
try {
|
|
1646
|
+
const parsed = JSON.parse(bodyText);
|
|
1647
|
+
if (parsed !== null && typeof parsed === "object" && "token" in parsed && typeof parsed.token === "string") {
|
|
1648
|
+
return parsed.token;
|
|
1649
|
+
}
|
|
1650
|
+
} catch {
|
|
1651
|
+
}
|
|
1652
|
+
return void 0;
|
|
1653
|
+
}
|
|
1548
1654
|
|
|
1549
1655
|
// src/resilience/retry.ts
|
|
1550
1656
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -1977,6 +2083,48 @@ function databasePath2(db) {
|
|
|
1977
2083
|
return `/api/databases/${encodeURIComponent(db)}`;
|
|
1978
2084
|
}
|
|
1979
2085
|
|
|
2086
|
+
// src/consistency-token-store.ts
|
|
2087
|
+
var MemoryConsistencyTokenStore = class {
|
|
2088
|
+
constructor() {
|
|
2089
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
2090
|
+
}
|
|
2091
|
+
get(database) {
|
|
2092
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2093
|
+
throw new Error("database must be a non-empty string");
|
|
2094
|
+
}
|
|
2095
|
+
return this.tokens.get(normalizeKey(database));
|
|
2096
|
+
}
|
|
2097
|
+
observe(database, token) {
|
|
2098
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2099
|
+
throw new Error("database must be a non-empty string");
|
|
2100
|
+
}
|
|
2101
|
+
if (token == null || token.trim().length === 0) {
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
const key = normalizeKey(database);
|
|
2105
|
+
const stored = this.tokens.get(key);
|
|
2106
|
+
if (stored === void 0 || compareOrdinal(token, stored) > 0) {
|
|
2107
|
+
this.tokens.set(key, token);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
function compareOrdinal(left, right) {
|
|
2112
|
+
if (left === right) return 0;
|
|
2113
|
+
return left < right ? -1 : 1;
|
|
2114
|
+
}
|
|
2115
|
+
function maxToken(left, right) {
|
|
2116
|
+
if (left == null || left.length === 0) {
|
|
2117
|
+
return right == null || right.length === 0 ? void 0 : right;
|
|
2118
|
+
}
|
|
2119
|
+
if (right == null || right.length === 0) {
|
|
2120
|
+
return left;
|
|
2121
|
+
}
|
|
2122
|
+
return compareOrdinal(left, right) >= 0 ? left : right;
|
|
2123
|
+
}
|
|
2124
|
+
function normalizeKey(database) {
|
|
2125
|
+
return database.toLowerCase();
|
|
2126
|
+
}
|
|
2127
|
+
|
|
1980
2128
|
// src/streaming/subscription.ts
|
|
1981
2129
|
var AsyncEventQueue = class {
|
|
1982
2130
|
constructor() {
|
|
@@ -2033,7 +2181,7 @@ var AsyncEventQueue = class {
|
|
|
2033
2181
|
}
|
|
2034
2182
|
};
|
|
2035
2183
|
var TableSubscription = class {
|
|
2036
|
-
constructor(transport, identity, options = {}, onWarnings) {
|
|
2184
|
+
constructor(transport, identity, options = {}, onWarnings, store, database) {
|
|
2037
2185
|
this._queue = new AsyncEventQueue();
|
|
2038
2186
|
this._active = true;
|
|
2039
2187
|
this._started = false;
|
|
@@ -2049,6 +2197,11 @@ var TableSubscription = class {
|
|
|
2049
2197
|
this._onError = options.onError;
|
|
2050
2198
|
this._onWarnings = onWarnings;
|
|
2051
2199
|
this._conflate = options.conflate;
|
|
2200
|
+
this._atLeast = options.atLeast;
|
|
2201
|
+
this._waitMs = options.waitMs;
|
|
2202
|
+
this._onExceeded = options.onExceeded;
|
|
2203
|
+
this._store = store;
|
|
2204
|
+
this._database = database;
|
|
2052
2205
|
this._reconnectHandlerKey = `${this.id}::reconnect`;
|
|
2053
2206
|
}
|
|
2054
2207
|
get lastVersion() {
|
|
@@ -2113,7 +2266,7 @@ var TableSubscription = class {
|
|
|
2113
2266
|
id: this.id
|
|
2114
2267
|
};
|
|
2115
2268
|
if (this._identity.kind === "named") {
|
|
2116
|
-
message.
|
|
2269
|
+
message.name = this._identity.name;
|
|
2117
2270
|
if (this._identity.args !== void 0) {
|
|
2118
2271
|
message.args = this._identity.args;
|
|
2119
2272
|
}
|
|
@@ -2132,8 +2285,30 @@ var TableSubscription = class {
|
|
|
2132
2285
|
if (this._conflate !== void 0) {
|
|
2133
2286
|
message.conflate = this._conflate;
|
|
2134
2287
|
}
|
|
2288
|
+
const pin = this._resolvePin();
|
|
2289
|
+
if (pin !== void 0) {
|
|
2290
|
+
message.at_least = pin;
|
|
2291
|
+
}
|
|
2292
|
+
if (this._waitMs !== void 0) {
|
|
2293
|
+
message.wait_ms = this._waitMs;
|
|
2294
|
+
}
|
|
2295
|
+
if (this._onExceeded !== void 0) {
|
|
2296
|
+
message.on_exceeded = this._onExceeded;
|
|
2297
|
+
}
|
|
2135
2298
|
await this._transport.send(message);
|
|
2136
2299
|
}
|
|
2300
|
+
_resolvePin() {
|
|
2301
|
+
if (this._atLeast !== void 0 && this._store != null && this._database != null) {
|
|
2302
|
+
this._store.observe(this._database, this._atLeast);
|
|
2303
|
+
}
|
|
2304
|
+
const stored = this._store != null && this._database != null ? this._store.get(this._database) : void 0;
|
|
2305
|
+
return maxToken(this._atLeast, stored);
|
|
2306
|
+
}
|
|
2307
|
+
_observeToken(token) {
|
|
2308
|
+
if (token !== void 0 && this._store != null && this._database != null) {
|
|
2309
|
+
this._store.observe(this._database, token);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2137
2312
|
_handleMessage(message) {
|
|
2138
2313
|
if (!this._active) {
|
|
2139
2314
|
return;
|
|
@@ -2160,6 +2335,7 @@ var TableSubscription = class {
|
|
|
2160
2335
|
}
|
|
2161
2336
|
_handleSnapshotPage(message) {
|
|
2162
2337
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2338
|
+
this._observeToken(message.token);
|
|
2163
2339
|
}
|
|
2164
2340
|
_handleSnapshotComplete(message) {
|
|
2165
2341
|
this._lastVersion = message.version;
|
|
@@ -2177,6 +2353,10 @@ var TableSubscription = class {
|
|
|
2177
2353
|
if (message.total_matches !== void 0) {
|
|
2178
2354
|
snapshot.totalMatches = message.total_matches;
|
|
2179
2355
|
}
|
|
2356
|
+
if (message.token !== void 0) {
|
|
2357
|
+
snapshot.token = message.token;
|
|
2358
|
+
this._observeToken(message.token);
|
|
2359
|
+
}
|
|
2180
2360
|
this._queue.push(snapshot);
|
|
2181
2361
|
}
|
|
2182
2362
|
async _handleGap(message) {
|
|
@@ -2202,6 +2382,10 @@ var TableSubscription = class {
|
|
|
2202
2382
|
if (message.values_skipped !== void 0) {
|
|
2203
2383
|
event.values_skipped = message.values_skipped;
|
|
2204
2384
|
}
|
|
2385
|
+
if (message.token !== void 0) {
|
|
2386
|
+
event.token = message.token;
|
|
2387
|
+
this._observeToken(message.token);
|
|
2388
|
+
}
|
|
2205
2389
|
this._onChange?.(event);
|
|
2206
2390
|
this._queue.push(event);
|
|
2207
2391
|
}
|
|
@@ -2349,8 +2533,11 @@ var TableWriteStream = class {
|
|
|
2349
2533
|
resolve?.();
|
|
2350
2534
|
}
|
|
2351
2535
|
_handleServerError(message) {
|
|
2536
|
+
const rowErrors = Array.isArray(message.errors) && message.errors.length > 0 ? message.errors : void 0;
|
|
2352
2537
|
const error = new AoudaConnectionError(
|
|
2353
|
-
`Write stream error (${message.code}): ${message.message}
|
|
2538
|
+
`Write stream error (${message.code}): ${message.message}`,
|
|
2539
|
+
void 0,
|
|
2540
|
+
rowErrors
|
|
2354
2541
|
);
|
|
2355
2542
|
const openReject = this._openReject;
|
|
2356
2543
|
this._openResolve = null;
|
|
@@ -2546,11 +2733,12 @@ var TableQuery = class _TableQuery {
|
|
|
2546
2733
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2547
2734
|
* @internal Use `client.table()` to create queries.
|
|
2548
2735
|
*/
|
|
2549
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
2736
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2550
2737
|
this.transport = transport;
|
|
2551
2738
|
this.tableName = tableName;
|
|
2552
2739
|
this.database = database;
|
|
2553
2740
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
2741
|
+
this.store = store;
|
|
2554
2742
|
this.state = state ?? {
|
|
2555
2743
|
predicates: [],
|
|
2556
2744
|
groupClauses: [],
|
|
@@ -2566,6 +2754,16 @@ var TableQuery = class _TableQuery {
|
|
|
2566
2754
|
isDistinct: false
|
|
2567
2755
|
};
|
|
2568
2756
|
}
|
|
2757
|
+
withState(state) {
|
|
2758
|
+
return new _TableQuery(
|
|
2759
|
+
this.transport,
|
|
2760
|
+
this.tableName,
|
|
2761
|
+
this.database,
|
|
2762
|
+
state,
|
|
2763
|
+
this.getWebSocketTransport,
|
|
2764
|
+
this.store
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2569
2767
|
where(column, operator, value) {
|
|
2570
2768
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2571
2769
|
return new _TableQuery(
|
|
@@ -2576,7 +2774,8 @@ var TableQuery = class _TableQuery {
|
|
|
2576
2774
|
...this.state,
|
|
2577
2775
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2578
2776
|
},
|
|
2579
|
-
this.getWebSocketTransport
|
|
2777
|
+
this.getWebSocketTransport,
|
|
2778
|
+
this.store
|
|
2580
2779
|
);
|
|
2581
2780
|
}
|
|
2582
2781
|
/**
|
|
@@ -2595,7 +2794,7 @@ var TableQuery = class _TableQuery {
|
|
|
2595
2794
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2596
2795
|
...this.state,
|
|
2597
2796
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2598
|
-
}, this.getWebSocketTransport);
|
|
2797
|
+
}, this.getWebSocketTransport, this.store);
|
|
2599
2798
|
}
|
|
2600
2799
|
/**
|
|
2601
2800
|
* Sets the primary sort column for the query.
|
|
@@ -2620,7 +2819,7 @@ var TableQuery = class _TableQuery {
|
|
|
2620
2819
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2621
2820
|
...this.state,
|
|
2622
2821
|
orderByClauses: [orderByClause]
|
|
2623
|
-
}, this.getWebSocketTransport);
|
|
2822
|
+
}, this.getWebSocketTransport, this.store);
|
|
2624
2823
|
}
|
|
2625
2824
|
/**
|
|
2626
2825
|
* Sets the primary sort column to descending order.
|
|
@@ -2666,7 +2865,7 @@ var TableQuery = class _TableQuery {
|
|
|
2666
2865
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2667
2866
|
...this.state,
|
|
2668
2867
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
2669
|
-
}, this.getWebSocketTransport);
|
|
2868
|
+
}, this.getWebSocketTransport, this.store);
|
|
2670
2869
|
}
|
|
2671
2870
|
/**
|
|
2672
2871
|
* Sets the maximum number of rows to return.
|
|
@@ -2683,7 +2882,7 @@ var TableQuery = class _TableQuery {
|
|
|
2683
2882
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2684
2883
|
...this.state,
|
|
2685
2884
|
limitValue: count
|
|
2686
|
-
}, this.getWebSocketTransport);
|
|
2885
|
+
}, this.getWebSocketTransport, this.store);
|
|
2687
2886
|
}
|
|
2688
2887
|
/**
|
|
2689
2888
|
* Sets the number of rows to skip.
|
|
@@ -2700,7 +2899,7 @@ var TableQuery = class _TableQuery {
|
|
|
2700
2899
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2701
2900
|
...this.state,
|
|
2702
2901
|
offsetValue: count
|
|
2703
|
-
}, this.getWebSocketTransport);
|
|
2902
|
+
}, this.getWebSocketTransport, this.store);
|
|
2704
2903
|
}
|
|
2705
2904
|
/**
|
|
2706
2905
|
* Requests cross-partition access for this query.
|
|
@@ -2715,10 +2914,21 @@ var TableQuery = class _TableQuery {
|
|
|
2715
2914
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2716
2915
|
...this.state,
|
|
2717
2916
|
crossPartitionAccess: true
|
|
2718
|
-
}, this.getWebSocketTransport);
|
|
2917
|
+
}, this.getWebSocketTransport, this.store);
|
|
2719
2918
|
}
|
|
2720
2919
|
/**
|
|
2721
|
-
*
|
|
2920
|
+
* Pin this query at at least this C-1 token. Observes the token into the
|
|
2921
|
+
* client store (I3, sticky) and presents it on execute via `X-Aouda-Token`.
|
|
2922
|
+
*/
|
|
2923
|
+
atLeast(token) {
|
|
2924
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
2925
|
+
throw new Error("atLeast() requires a non-empty token");
|
|
2926
|
+
}
|
|
2927
|
+
this.store?.observe(this.database, token);
|
|
2928
|
+
return this.withState({ ...this.state, atLeast: token });
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* Selects specific columns to return.
|
|
2722
2932
|
* If not called, all columns are returned.
|
|
2723
2933
|
*
|
|
2724
2934
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -2740,7 +2950,7 @@ var TableQuery = class _TableQuery {
|
|
|
2740
2950
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2741
2951
|
...this.state,
|
|
2742
2952
|
selectColumns: columns.length > 0 ? columns : null
|
|
2743
|
-
}, this.getWebSocketTransport);
|
|
2953
|
+
}, this.getWebSocketTransport, this.store);
|
|
2744
2954
|
}
|
|
2745
2955
|
/**
|
|
2746
2956
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -2770,7 +2980,7 @@ var TableQuery = class _TableQuery {
|
|
|
2770
2980
|
...this.state,
|
|
2771
2981
|
selectColumns: columns,
|
|
2772
2982
|
isDistinct: true
|
|
2773
|
-
}, this.getWebSocketTransport);
|
|
2983
|
+
}, this.getWebSocketTransport, this.store);
|
|
2774
2984
|
}
|
|
2775
2985
|
/**
|
|
2776
2986
|
* Adds server-side computed columns to the query result.
|
|
@@ -2779,6 +2989,12 @@ var TableQuery = class _TableQuery {
|
|
|
2779
2989
|
* evaluated per row on the server. Computed columns are appended after any physical-column
|
|
2780
2990
|
* `select()` projection.
|
|
2781
2991
|
*
|
|
2992
|
+
* Result types are inferred by the server where the expression permits
|
|
2993
|
+
* (e.g. Int32 → `number`). Uninferable expressions use wire `"Unknown"` /
|
|
2994
|
+
* codegen `unknown`. Computed columns are always nullable. Named-query
|
|
2995
|
+
* `*Row` properties pick this up when regenerated against a post-S08 server.
|
|
2996
|
+
* See aouda-docs/guides/browser-tier-read-limits.md#selectexpr-result-types
|
|
2997
|
+
*
|
|
2782
2998
|
* @param projections - One or more `{ alias, expr }` pairs.
|
|
2783
2999
|
* @returns A new TableQuery with computed columns set.
|
|
2784
3000
|
*
|
|
@@ -2799,7 +3015,7 @@ var TableQuery = class _TableQuery {
|
|
|
2799
3015
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2800
3016
|
...this.state,
|
|
2801
3017
|
selectExprs: projections
|
|
2802
|
-
}, this.getWebSocketTransport);
|
|
3018
|
+
}, this.getWebSocketTransport, this.store);
|
|
2803
3019
|
}
|
|
2804
3020
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
2805
3021
|
return this.addJoinClause(
|
|
@@ -2857,7 +3073,8 @@ var TableQuery = class _TableQuery {
|
|
|
2857
3073
|
}
|
|
2858
3074
|
]
|
|
2859
3075
|
},
|
|
2860
|
-
this.getWebSocketTransport
|
|
3076
|
+
this.getWebSocketTransport,
|
|
3077
|
+
this.store
|
|
2861
3078
|
);
|
|
2862
3079
|
}
|
|
2863
3080
|
/**
|
|
@@ -2893,7 +3110,8 @@ var TableQuery = class _TableQuery {
|
|
|
2893
3110
|
...this.state,
|
|
2894
3111
|
groupByColumns: [...columns]
|
|
2895
3112
|
},
|
|
2896
|
-
this.getWebSocketTransport
|
|
3113
|
+
this.getWebSocketTransport,
|
|
3114
|
+
this.store
|
|
2897
3115
|
);
|
|
2898
3116
|
}
|
|
2899
3117
|
/**
|
|
@@ -2927,8 +3145,11 @@ var TableQuery = class _TableQuery {
|
|
|
2927
3145
|
onSnapshot: options.onSnapshot,
|
|
2928
3146
|
onChange: options.onChange,
|
|
2929
3147
|
onError: options.onError,
|
|
2930
|
-
conflate: options.conflate
|
|
2931
|
-
|
|
3148
|
+
conflate: options.conflate,
|
|
3149
|
+
atLeast: options.atLeast ?? this.state.atLeast,
|
|
3150
|
+
waitMs: options.waitMs,
|
|
3151
|
+
onExceeded: options.onExceeded
|
|
3152
|
+
}, void 0, this.store, this.database);
|
|
2932
3153
|
subscription.start();
|
|
2933
3154
|
return subscription;
|
|
2934
3155
|
}
|
|
@@ -3043,7 +3264,8 @@ var TableQuery = class _TableQuery {
|
|
|
3043
3264
|
...this.state,
|
|
3044
3265
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3045
3266
|
},
|
|
3046
|
-
this.getWebSocketTransport
|
|
3267
|
+
this.getWebSocketTransport,
|
|
3268
|
+
this.store
|
|
3047
3269
|
);
|
|
3048
3270
|
}
|
|
3049
3271
|
addAggregate(op, column) {
|
|
@@ -3064,7 +3286,8 @@ var TableQuery = class _TableQuery {
|
|
|
3064
3286
|
}
|
|
3065
3287
|
]
|
|
3066
3288
|
},
|
|
3067
|
-
this.getWebSocketTransport
|
|
3289
|
+
this.getWebSocketTransport,
|
|
3290
|
+
this.store
|
|
3068
3291
|
);
|
|
3069
3292
|
}
|
|
3070
3293
|
requireWebSocketTransport() {
|
|
@@ -3094,17 +3317,23 @@ var TableQuery = class _TableQuery {
|
|
|
3094
3317
|
* ```
|
|
3095
3318
|
*/
|
|
3096
3319
|
async execute() {
|
|
3320
|
+
if (this.state.atLeast) {
|
|
3321
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3322
|
+
}
|
|
3097
3323
|
const request = this.buildRequest();
|
|
3098
3324
|
const path = `${databasePath2(this.database)}/query`;
|
|
3099
3325
|
const response = await this.transport.post(path, request);
|
|
3100
3326
|
const rows = columnarToRows(response);
|
|
3101
3327
|
const stats = response.stats;
|
|
3102
|
-
return { rows, stats };
|
|
3328
|
+
return { rows, stats, token: response.token };
|
|
3103
3329
|
}
|
|
3104
3330
|
/**
|
|
3105
3331
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3106
3332
|
*/
|
|
3107
3333
|
async toColumnar() {
|
|
3334
|
+
if (this.state.atLeast) {
|
|
3335
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3336
|
+
}
|
|
3108
3337
|
const request = this.buildRequest();
|
|
3109
3338
|
const path = `${databasePath2(this.database)}/query`;
|
|
3110
3339
|
return this.transport.post(path, request);
|
|
@@ -3134,8 +3363,12 @@ var TableQuery = class _TableQuery {
|
|
|
3134
3363
|
limitValue: 0,
|
|
3135
3364
|
selectColumns: []
|
|
3136
3365
|
},
|
|
3137
|
-
this.getWebSocketTransport
|
|
3366
|
+
this.getWebSocketTransport,
|
|
3367
|
+
this.store
|
|
3138
3368
|
);
|
|
3369
|
+
if (this.state.atLeast) {
|
|
3370
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3371
|
+
}
|
|
3139
3372
|
const request = countQuery.buildRequest();
|
|
3140
3373
|
const path = `${databasePath2(this.database)}/query`;
|
|
3141
3374
|
const response = await this.transport.post(path, request);
|
|
@@ -3182,7 +3415,8 @@ var TableQuery = class _TableQuery {
|
|
|
3182
3415
|
const response = await this.transport.post(path, body);
|
|
3183
3416
|
const result = {
|
|
3184
3417
|
rowsInserted: response.rowsInserted,
|
|
3185
|
-
executionMs: response.executionMs
|
|
3418
|
+
executionMs: response.executionMs,
|
|
3419
|
+
token: response.token
|
|
3186
3420
|
};
|
|
3187
3421
|
if (response.generatedValues !== void 0) {
|
|
3188
3422
|
result.generatedValues = response.generatedValues;
|
|
@@ -3232,7 +3466,8 @@ var TableQuery = class _TableQuery {
|
|
|
3232
3466
|
const response = await this.transport.post(path, body);
|
|
3233
3467
|
const result = {
|
|
3234
3468
|
rowsInserted: response.rowsInserted,
|
|
3235
|
-
executionMs: response.executionMs
|
|
3469
|
+
executionMs: response.executionMs,
|
|
3470
|
+
token: response.token
|
|
3236
3471
|
};
|
|
3237
3472
|
if (response.generatedValues !== void 0) {
|
|
3238
3473
|
result.generatedValues = response.generatedValues;
|
|
@@ -3284,6 +3519,7 @@ var TableQuery = class _TableQuery {
|
|
|
3284
3519
|
return {
|
|
3285
3520
|
rowsAffected: response.rowsUpdated,
|
|
3286
3521
|
executionMs: response.executionMs,
|
|
3522
|
+
token: response.token,
|
|
3287
3523
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3288
3524
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3289
3525
|
};
|
|
@@ -3334,6 +3570,7 @@ var TableQuery = class _TableQuery {
|
|
|
3334
3570
|
rowsAffected: response.rowsDeleted,
|
|
3335
3571
|
executionMs: response.executionMs,
|
|
3336
3572
|
hasMore: response.hasMore,
|
|
3573
|
+
token: response.token,
|
|
3337
3574
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3338
3575
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3339
3576
|
};
|
|
@@ -3353,7 +3590,8 @@ var TableQuery = class _TableQuery {
|
|
|
3353
3590
|
return {
|
|
3354
3591
|
rowsAffected: response.rowsDeleted,
|
|
3355
3592
|
executionMs: response.executionMs,
|
|
3356
|
-
hasMore: false
|
|
3593
|
+
hasMore: false,
|
|
3594
|
+
token: response.token
|
|
3357
3595
|
};
|
|
3358
3596
|
}
|
|
3359
3597
|
/**
|
|
@@ -3366,7 +3604,14 @@ var TableQuery = class _TableQuery {
|
|
|
3366
3604
|
throw new Error("batch() requires a non-empty operations array");
|
|
3367
3605
|
}
|
|
3368
3606
|
const wireOperations = operations.map((op, index) => {
|
|
3369
|
-
const base = new _TableQuery(
|
|
3607
|
+
const base = new _TableQuery(
|
|
3608
|
+
this.transport,
|
|
3609
|
+
this.tableName,
|
|
3610
|
+
this.database,
|
|
3611
|
+
void 0,
|
|
3612
|
+
this.getWebSocketTransport,
|
|
3613
|
+
this.store
|
|
3614
|
+
);
|
|
3370
3615
|
const scoped = op.where(base);
|
|
3371
3616
|
const where = scoped.buildWhereClause();
|
|
3372
3617
|
if (!where) {
|
|
@@ -4734,12 +4979,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
4734
4979
|
continue;
|
|
4735
4980
|
}
|
|
4736
4981
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
4737
|
-
const
|
|
4982
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
4738
4983
|
sink({
|
|
4739
4984
|
code: warning.code,
|
|
4740
|
-
|
|
4985
|
+
name: warning.name,
|
|
4741
4986
|
sunsetAt: warning.sunsetAt,
|
|
4742
|
-
message: `${warning.code}:${
|
|
4987
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
4743
4988
|
});
|
|
4744
4989
|
}
|
|
4745
4990
|
}
|
|
@@ -4752,24 +4997,28 @@ function emptyStats() {
|
|
|
4752
4997
|
};
|
|
4753
4998
|
}
|
|
4754
4999
|
var NamedQueriesApi = class {
|
|
4755
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5000
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
4756
5001
|
this.transport = transport;
|
|
4757
5002
|
this.database = database;
|
|
4758
5003
|
this.onWarning = onWarning;
|
|
4759
5004
|
this.getStreamingTransport = getStreamingTransport;
|
|
5005
|
+
this.store = store;
|
|
4760
5006
|
}
|
|
4761
|
-
async execute(
|
|
4762
|
-
if (typeof
|
|
4763
|
-
throw new Error("Named query
|
|
5007
|
+
async execute(name, args, options) {
|
|
5008
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5009
|
+
throw new Error("Named query name must be a non-empty string");
|
|
4764
5010
|
}
|
|
4765
5011
|
const prefix = databasePath2(this.database);
|
|
4766
|
-
const path = `${prefix}/named-queries/${encodeURIComponent(
|
|
5012
|
+
const path = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
4767
5013
|
const body = {
|
|
4768
5014
|
args: args ?? {}
|
|
4769
5015
|
};
|
|
4770
5016
|
if (options?.orderByIndex !== void 0) {
|
|
4771
5017
|
body.orderByIndex = options.orderByIndex;
|
|
4772
5018
|
}
|
|
5019
|
+
if (options?.atLeast !== void 0) {
|
|
5020
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5021
|
+
}
|
|
4773
5022
|
const response = await this.transport.post(
|
|
4774
5023
|
path,
|
|
4775
5024
|
body,
|
|
@@ -4781,7 +5030,8 @@ var NamedQueriesApi = class {
|
|
|
4781
5030
|
rows,
|
|
4782
5031
|
stats: response.stats,
|
|
4783
5032
|
warnings: response.warnings,
|
|
4784
|
-
totalMatches: response.totalMatches
|
|
5033
|
+
totalMatches: response.totalMatches,
|
|
5034
|
+
token: response.token
|
|
4785
5035
|
};
|
|
4786
5036
|
}
|
|
4787
5037
|
async batch(items, options) {
|
|
@@ -4799,6 +5049,9 @@ var NamedQueriesApi = class {
|
|
|
4799
5049
|
400
|
|
4800
5050
|
);
|
|
4801
5051
|
}
|
|
5052
|
+
if (options?.atLeast !== void 0) {
|
|
5053
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5054
|
+
}
|
|
4802
5055
|
const prefix = databasePath2(this.database);
|
|
4803
5056
|
const path = `${prefix}/named-queries/batch?format=columnar`;
|
|
4804
5057
|
const envelope = await this.transport.post(
|
|
@@ -4821,34 +5074,41 @@ var NamedQueriesApi = class {
|
|
|
4821
5074
|
rowCount: slot.rowCount ?? 0,
|
|
4822
5075
|
stats: slot.stats ?? emptyStats(),
|
|
4823
5076
|
warnings: slot.warnings,
|
|
4824
|
-
totalMatches: slot.totalMatches
|
|
5077
|
+
totalMatches: slot.totalMatches,
|
|
5078
|
+
token: slot.token
|
|
4825
5079
|
};
|
|
4826
5080
|
const result = {
|
|
4827
5081
|
rows: columnarToRows(columnar),
|
|
4828
5082
|
stats: columnar.stats,
|
|
4829
5083
|
warnings: slot.warnings,
|
|
4830
|
-
totalMatches: slot.totalMatches
|
|
5084
|
+
totalMatches: slot.totalMatches,
|
|
5085
|
+
token: slot.token
|
|
4831
5086
|
};
|
|
4832
5087
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
4833
5088
|
return { isError: false, result };
|
|
4834
5089
|
});
|
|
4835
5090
|
}
|
|
4836
|
-
subscribe(
|
|
4837
|
-
if (typeof
|
|
4838
|
-
throw new Error("Named query
|
|
5091
|
+
subscribe(name, args, options = {}) {
|
|
5092
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5093
|
+
throw new Error("Named query name must be a non-empty string");
|
|
4839
5094
|
}
|
|
4840
5095
|
const subscription = new TableSubscription(
|
|
4841
5096
|
this.getStreamingTransport(),
|
|
4842
|
-
{ kind: "named",
|
|
5097
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
4843
5098
|
{
|
|
4844
5099
|
onSnapshot: options.onSnapshot,
|
|
4845
5100
|
onChange: options.onChange,
|
|
4846
5101
|
onError: options.onError,
|
|
4847
|
-
conflate: options.conflate
|
|
5102
|
+
conflate: options.conflate,
|
|
5103
|
+
atLeast: options.atLeast,
|
|
5104
|
+
waitMs: options.waitMs,
|
|
5105
|
+
onExceeded: options.onExceeded
|
|
4848
5106
|
},
|
|
4849
5107
|
(warnings) => {
|
|
4850
5108
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
4851
|
-
}
|
|
5109
|
+
},
|
|
5110
|
+
this.store,
|
|
5111
|
+
this.database
|
|
4852
5112
|
);
|
|
4853
5113
|
subscription.start();
|
|
4854
5114
|
return subscription;
|
|
@@ -4860,12 +5120,12 @@ var NamedMutationsApi = class {
|
|
|
4860
5120
|
this.database = database;
|
|
4861
5121
|
this.onWarning = onWarning;
|
|
4862
5122
|
}
|
|
4863
|
-
async execute(
|
|
4864
|
-
if (typeof
|
|
4865
|
-
throw new Error("Named mutation
|
|
5123
|
+
async execute(name, args) {
|
|
5124
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5125
|
+
throw new Error("Named mutation name must be a non-empty string");
|
|
4866
5126
|
}
|
|
4867
5127
|
const prefix = databasePath2(this.database);
|
|
4868
|
-
const path = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5128
|
+
const path = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
4869
5129
|
const wire = await this.transport.post(path, {
|
|
4870
5130
|
args: args ?? {}
|
|
4871
5131
|
});
|
|
@@ -4926,6 +5186,7 @@ var WebSocketTransport = class {
|
|
|
4926
5186
|
// Serialized-send queue: each send appends to this tail.
|
|
4927
5187
|
this._sendTail = Promise.resolve();
|
|
4928
5188
|
this._lastVersion = 0;
|
|
5189
|
+
this._lastToken = null;
|
|
4929
5190
|
this._reconnectAttempt = 0;
|
|
4930
5191
|
this._disposed = false;
|
|
4931
5192
|
this._missedPings = 0;
|
|
@@ -4943,6 +5204,7 @@ var WebSocketTransport = class {
|
|
|
4943
5204
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
4944
5205
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
4945
5206
|
this._enableCompression = options.enableCompression ?? true;
|
|
5207
|
+
this._store = options.consistencyTokenStore;
|
|
4946
5208
|
this._wireMode = options.wireMode ?? "json";
|
|
4947
5209
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
4948
5210
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -4951,10 +5213,14 @@ var WebSocketTransport = class {
|
|
|
4951
5213
|
});
|
|
4952
5214
|
}
|
|
4953
5215
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
4954
|
-
/** Latest
|
|
5216
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
4955
5217
|
get lastVersion() {
|
|
4956
5218
|
return this._lastVersion;
|
|
4957
5219
|
}
|
|
5220
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5221
|
+
get lastToken() {
|
|
5222
|
+
return this._lastToken;
|
|
5223
|
+
}
|
|
4958
5224
|
/**
|
|
4959
5225
|
* Registers a handler for incoming server messages with the given channel id.
|
|
4960
5226
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5142,6 +5408,10 @@ var WebSocketTransport = class {
|
|
|
5142
5408
|
}
|
|
5143
5409
|
case "heartbeat":
|
|
5144
5410
|
this._lastVersion = msg.version;
|
|
5411
|
+
this._lastToken = msg.token ?? null;
|
|
5412
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5413
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5414
|
+
}
|
|
5145
5415
|
break;
|
|
5146
5416
|
case "pong":
|
|
5147
5417
|
this._missedPings = 0;
|
|
@@ -5307,16 +5577,21 @@ var LongPollTransport = class {
|
|
|
5307
5577
|
this._connected = false;
|
|
5308
5578
|
this._pollTask = null;
|
|
5309
5579
|
this._lastVersion = 0;
|
|
5580
|
+
this._lastToken = null;
|
|
5310
5581
|
this._serverUrl = serverUrl;
|
|
5311
5582
|
this._database = database;
|
|
5312
5583
|
this._authHandler = options.authHandler;
|
|
5313
5584
|
this._onReconnected = options.onReconnected;
|
|
5314
5585
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5315
5586
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5587
|
+
this._store = options.consistencyTokenStore;
|
|
5316
5588
|
}
|
|
5317
5589
|
get lastVersion() {
|
|
5318
5590
|
return this._lastVersion;
|
|
5319
5591
|
}
|
|
5592
|
+
get lastToken() {
|
|
5593
|
+
return this._lastToken;
|
|
5594
|
+
}
|
|
5320
5595
|
registerHandler(id, handler) {
|
|
5321
5596
|
this._handlers.set(id, handler);
|
|
5322
5597
|
}
|
|
@@ -5439,6 +5714,10 @@ var LongPollTransport = class {
|
|
|
5439
5714
|
for (const msg of payload.messages) {
|
|
5440
5715
|
if (msg.type === "heartbeat") {
|
|
5441
5716
|
this._lastVersion = msg.version;
|
|
5717
|
+
this._lastToken = msg.token ?? null;
|
|
5718
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5719
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5720
|
+
}
|
|
5442
5721
|
}
|
|
5443
5722
|
const id = "id" in msg ? msg.id : void 0;
|
|
5444
5723
|
if (id !== void 0 && id !== null) {
|
|
@@ -5518,6 +5797,9 @@ var FallbackStreamingTransport = class {
|
|
|
5518
5797
|
get lastVersion() {
|
|
5519
5798
|
return this._active.lastVersion;
|
|
5520
5799
|
}
|
|
5800
|
+
get lastToken() {
|
|
5801
|
+
return this._active.lastToken;
|
|
5802
|
+
}
|
|
5521
5803
|
registerHandler(id, handler) {
|
|
5522
5804
|
this._handlers.set(id, handler);
|
|
5523
5805
|
this._active.registerHandler(id, handler);
|
|
@@ -5597,6 +5879,7 @@ var AoudaClient = class {
|
|
|
5597
5879
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5598
5880
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5599
5881
|
this.database = options.database.trim();
|
|
5882
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5600
5883
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5601
5884
|
throw new Error("timeout must be a finite positive number");
|
|
5602
5885
|
}
|
|
@@ -5631,7 +5914,9 @@ var AoudaClient = class {
|
|
|
5631
5914
|
}
|
|
5632
5915
|
const httpTransport = new HttpTransport({
|
|
5633
5916
|
baseUrl: this.baseUrl,
|
|
5634
|
-
timeout: this.timeout
|
|
5917
|
+
timeout: this.timeout,
|
|
5918
|
+
database: this.database,
|
|
5919
|
+
consistencyTokenStore: this._store
|
|
5635
5920
|
});
|
|
5636
5921
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5637
5922
|
if (activeAuth) {
|
|
@@ -5691,7 +5976,8 @@ var AoudaClient = class {
|
|
|
5691
5976
|
this.transport,
|
|
5692
5977
|
this.database,
|
|
5693
5978
|
onNamedArtifactWarning,
|
|
5694
|
-
() => this._getOrCreateWebSocketTransport()
|
|
5979
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
5980
|
+
this._store
|
|
5695
5981
|
);
|
|
5696
5982
|
this._namedMutations = new NamedMutationsApi(
|
|
5697
5983
|
this.transport,
|
|
@@ -5790,7 +6076,8 @@ var AoudaClient = class {
|
|
|
5790
6076
|
name,
|
|
5791
6077
|
this.database,
|
|
5792
6078
|
void 0,
|
|
5793
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6079
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6080
|
+
this._store
|
|
5794
6081
|
);
|
|
5795
6082
|
}
|
|
5796
6083
|
/**
|
|
@@ -5842,13 +6129,26 @@ var AoudaClient = class {
|
|
|
5842
6129
|
return this._materializedQueries;
|
|
5843
6130
|
}
|
|
5844
6131
|
/**
|
|
5845
|
-
*
|
|
6132
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
5846
6133
|
*/
|
|
5847
6134
|
get namedQueries() {
|
|
5848
6135
|
return this._namedQueries;
|
|
5849
6136
|
}
|
|
6137
|
+
observeConsistencyToken(token) {
|
|
6138
|
+
this._store.observe(this.database, token);
|
|
6139
|
+
}
|
|
6140
|
+
getObservedConsistencyToken() {
|
|
6141
|
+
return this._store.get(this.database);
|
|
6142
|
+
}
|
|
6143
|
+
async getConsistencyToken() {
|
|
6144
|
+
const body = await this.transport.get(
|
|
6145
|
+
`/api/databases/${encodeURIComponent(this.database)}/token`
|
|
6146
|
+
);
|
|
6147
|
+
this._store.observe(this.database, body.token);
|
|
6148
|
+
return this._store.get(this.database) ?? body.token;
|
|
6149
|
+
}
|
|
5850
6150
|
/**
|
|
5851
|
-
*
|
|
6151
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
5852
6152
|
*/
|
|
5853
6153
|
get namedMutations() {
|
|
5854
6154
|
return this._namedMutations;
|
|
@@ -5975,13 +6275,15 @@ var AoudaClient = class {
|
|
|
5975
6275
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
5976
6276
|
authHandler: this._authHandler,
|
|
5977
6277
|
enableCompression: this._streamingEnableCompression,
|
|
5978
|
-
wireMode: this._streamingWireMode
|
|
6278
|
+
wireMode: this._streamingWireMode,
|
|
6279
|
+
consistencyTokenStore: this._store
|
|
5979
6280
|
});
|
|
5980
6281
|
if (this._streamingEnableLongPollFallback) {
|
|
5981
6282
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
5982
6283
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
5983
6284
|
authHandler: this._authHandler,
|
|
5984
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6285
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6286
|
+
consistencyTokenStore: this._store
|
|
5985
6287
|
});
|
|
5986
6288
|
});
|
|
5987
6289
|
} else {
|
|
@@ -6278,6 +6580,7 @@ export {
|
|
|
6278
6580
|
MaterializedQueriesApi,
|
|
6279
6581
|
MaterializedQueryState,
|
|
6280
6582
|
MaterializedQueryType,
|
|
6583
|
+
MemoryConsistencyTokenStore,
|
|
6281
6584
|
MetricsAdminApi,
|
|
6282
6585
|
NamedMutationsApi,
|
|
6283
6586
|
NamedQueriesApi,
|
|
@@ -6293,10 +6596,12 @@ export {
|
|
|
6293
6596
|
applyLocalNetworkAccess,
|
|
6294
6597
|
coerceColumnarValue,
|
|
6295
6598
|
columnarToRows,
|
|
6599
|
+
compareOrdinal,
|
|
6296
6600
|
createAoudaClient,
|
|
6297
6601
|
createAoudaClusterMcpToolSet,
|
|
6298
6602
|
installLocalNetworkFetch,
|
|
6299
6603
|
localNetworkFetch,
|
|
6604
|
+
maxToken,
|
|
6300
6605
|
resolveTargetAddressSpace,
|
|
6301
6606
|
version
|
|
6302
6607
|
};
|