@aouda/client 0.1.14 → 0.1.15
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/dist/cli/index.cjs +346 -73
- 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 +346 -73
- package/dist/cli/index.js.map +1 -1
- package/dist/{client-BCMP-Fge.d.cts → client-CXfjcF61.d.cts} +99 -21
- package/dist/{client-BCMP-Fge.d.ts → client-CXfjcF61.d.ts} +99 -21
- package/dist/index.cjs +351 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.js +348 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -392,7 +392,7 @@ import { fileURLToPath } from "url";
|
|
|
392
392
|
// package.json
|
|
393
393
|
var package_default = {
|
|
394
394
|
name: "@aouda/client",
|
|
395
|
-
version: "0.1.
|
|
395
|
+
version: "0.1.15",
|
|
396
396
|
description: "Official TypeScript/JavaScript client library for Aouda",
|
|
397
397
|
type: "module",
|
|
398
398
|
main: "./dist/index.cjs",
|
|
@@ -507,43 +507,44 @@ var AoudaResponseError = class extends AoudaError {
|
|
|
507
507
|
}
|
|
508
508
|
};
|
|
509
509
|
var AoudaApiError = class extends AoudaError {
|
|
510
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
510
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
511
511
|
super(message);
|
|
512
512
|
this.code = code;
|
|
513
513
|
this.statusCode = statusCode;
|
|
514
514
|
this.details = details;
|
|
515
515
|
this.requestId = requestId;
|
|
516
516
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
517
|
+
this.token = token;
|
|
517
518
|
this.name = "AoudaApiError";
|
|
518
519
|
}
|
|
519
520
|
};
|
|
520
521
|
var AoudaNotFoundError = class extends AoudaApiError {
|
|
521
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
522
|
-
super(message, code, statusCode, details, requestId);
|
|
522
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
523
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
523
524
|
this.name = "AoudaNotFoundError";
|
|
524
525
|
}
|
|
525
526
|
};
|
|
526
527
|
var AoudaConflictError = class extends AoudaApiError {
|
|
527
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
528
|
-
super(message, code, statusCode, details, requestId);
|
|
528
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
529
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
529
530
|
this.name = "AoudaConflictError";
|
|
530
531
|
}
|
|
531
532
|
};
|
|
532
533
|
var AoudaValidationError = class extends AoudaApiError {
|
|
533
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
534
|
-
super(message, code, statusCode, details, requestId);
|
|
534
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
535
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
535
536
|
this.name = "AoudaValidationError";
|
|
536
537
|
}
|
|
537
538
|
};
|
|
538
539
|
var AoudaServerError = class extends AoudaApiError {
|
|
539
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
540
|
-
super(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
540
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
541
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
541
542
|
this.name = "AoudaServerError";
|
|
542
543
|
}
|
|
543
544
|
};
|
|
544
545
|
var AoudaAuthenticationError = class extends AoudaApiError {
|
|
545
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
546
|
-
super(message, code, statusCode, details, requestId);
|
|
546
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
547
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
547
548
|
this.name = "AoudaAuthenticationError";
|
|
548
549
|
}
|
|
549
550
|
};
|
|
@@ -1339,7 +1340,7 @@ function buildHandle(jobId, commitResp, wasResumed, transport, database, signal)
|
|
|
1339
1340
|
rowsDurablyCommitted: commitResp.rowsLoaded,
|
|
1340
1341
|
segmentsCreated: commitResp.segmentsCreated,
|
|
1341
1342
|
committedAtUtc: commitResp.committedAtUtc,
|
|
1342
|
-
|
|
1343
|
+
token: commitResp.token,
|
|
1343
1344
|
writeConcernSatisfied: commitResp.writeConcernAchieved ?? "acknowledged",
|
|
1344
1345
|
writeConcernTimedOut: commitResp.writeConcernTimedOut,
|
|
1345
1346
|
wasResumed,
|
|
@@ -1465,6 +1466,7 @@ var PROTOCOL_VERSION_HEADER = "X-Aouda-Protocol-Version";
|
|
|
1465
1466
|
var PROTOCOL_VERSION = "1";
|
|
1466
1467
|
var CONTENT_TYPE_JSON2 = "application/json";
|
|
1467
1468
|
var REQUEST_ID_HEADER2 = "X-Request-Id";
|
|
1469
|
+
var TOKEN_HEADER = "X-Aouda-Token";
|
|
1468
1470
|
var ERROR_CODE_MAP = {
|
|
1469
1471
|
TABLE_NOT_FOUND: AoudaNotFoundError,
|
|
1470
1472
|
COLUMN_NOT_FOUND: AoudaNotFoundError,
|
|
@@ -1504,7 +1506,12 @@ var ERROR_CODE_MAP = {
|
|
|
1504
1506
|
AUTH_IDENTITY_INVALID: AoudaValidationError,
|
|
1505
1507
|
AUTH_IDENTITY_NOT_FOUND: AoudaValidationError,
|
|
1506
1508
|
BULK_LOAD_TRANSFORM_INTENT_REQUIRED: AoudaValidationError,
|
|
1507
|
-
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError
|
|
1509
|
+
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError,
|
|
1510
|
+
TOKEN_MALFORMED: AoudaValidationError,
|
|
1511
|
+
TOKEN_FOREIGN_DATABASE: AoudaValidationError,
|
|
1512
|
+
TOKEN_EPOCH_SUPERSEDED: AoudaConflictError,
|
|
1513
|
+
TOKEN_UNSATISFIED: AoudaConflictError,
|
|
1514
|
+
TOKEN_FETCH_PRIMARY: AoudaApiError
|
|
1508
1515
|
};
|
|
1509
1516
|
function createComposedAbortController(...signals) {
|
|
1510
1517
|
const controller = new AbortController();
|
|
@@ -1541,7 +1548,7 @@ function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
|
1541
1548
|
const requestId = body.requestId;
|
|
1542
1549
|
const retryAfterSeconds = parseRetryAfterSeconds(retryAfterHeader ?? null);
|
|
1543
1550
|
const Ctor = ERROR_CODE_MAP[code] ?? AoudaApiError;
|
|
1544
|
-
return new Ctor(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
1551
|
+
return new Ctor(message, code, statusCode, details, requestId, retryAfterSeconds, body.token);
|
|
1545
1552
|
}
|
|
1546
1553
|
var HttpTransport = class {
|
|
1547
1554
|
constructor(options) {
|
|
@@ -1553,6 +1560,29 @@ var HttpTransport = class {
|
|
|
1553
1560
|
...options.defaultHeaders
|
|
1554
1561
|
};
|
|
1555
1562
|
this.abortController = new AbortController();
|
|
1563
|
+
this.database = options.database;
|
|
1564
|
+
this.store = options.consistencyTokenStore;
|
|
1565
|
+
}
|
|
1566
|
+
presentTokenHeaders(path4, headers) {
|
|
1567
|
+
if (this.store == null || this.database == null || isAuthPath(path4)) {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
const token = this.store.get(this.database);
|
|
1571
|
+
if (token != null && token.length > 0) {
|
|
1572
|
+
headers[TOKEN_HEADER] = token;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
observeResponse(_path, response, bodyText, errorCode) {
|
|
1576
|
+
if (this.store == null || this.database == null) {
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (errorCode === "TOKEN_MALFORMED" || errorCode === "TOKEN_FOREIGN_DATABASE") {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
const header = response.headers.get(TOKEN_HEADER);
|
|
1583
|
+
const bodyToken = readBodyToken(bodyText);
|
|
1584
|
+
const token = header != null && header.trim().length > 0 ? header : bodyToken;
|
|
1585
|
+
this.store.observe(this.database, token);
|
|
1556
1586
|
}
|
|
1557
1587
|
/**
|
|
1558
1588
|
* Abort all in-flight and future requests (e.g. on client disconnect).
|
|
@@ -1590,6 +1620,7 @@ var HttpTransport = class {
|
|
|
1590
1620
|
...this.defaultHeaders,
|
|
1591
1621
|
...config.headers
|
|
1592
1622
|
};
|
|
1623
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1593
1624
|
if (config.body !== void 0 && config.body !== null) {
|
|
1594
1625
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1595
1626
|
}
|
|
@@ -1609,6 +1640,7 @@ var HttpTransport = class {
|
|
|
1609
1640
|
const text = await response.text();
|
|
1610
1641
|
if (config.allowStatuses?.includes(response.status) && text) {
|
|
1611
1642
|
try {
|
|
1643
|
+
this.observeResponse(config.path, response, text);
|
|
1612
1644
|
return JSON.parse(text);
|
|
1613
1645
|
} catch {
|
|
1614
1646
|
}
|
|
@@ -1622,15 +1654,19 @@ var HttpTransport = class {
|
|
|
1622
1654
|
}
|
|
1623
1655
|
if (response.status === 401) {
|
|
1624
1656
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1657
|
+
this.observeResponse(config.path, response, text, code);
|
|
1625
1658
|
throw new AoudaAuthenticationError(
|
|
1626
1659
|
errorBody?.error ?? "Unauthorized",
|
|
1627
1660
|
code,
|
|
1628
1661
|
401,
|
|
1629
1662
|
errorBody?.details,
|
|
1630
|
-
errorBody?.requestId
|
|
1663
|
+
errorBody?.requestId,
|
|
1664
|
+
void 0,
|
|
1665
|
+
errorBody?.token
|
|
1631
1666
|
);
|
|
1632
1667
|
}
|
|
1633
1668
|
if (errorBody?.code != null) {
|
|
1669
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1634
1670
|
throw createApiError(
|
|
1635
1671
|
response.status,
|
|
1636
1672
|
response.statusText,
|
|
@@ -1638,6 +1674,7 @@ var HttpTransport = class {
|
|
|
1638
1674
|
response.headers.get("Retry-After")
|
|
1639
1675
|
);
|
|
1640
1676
|
}
|
|
1677
|
+
this.observeResponse(config.path, response, text);
|
|
1641
1678
|
throw new AoudaResponseError(
|
|
1642
1679
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1643
1680
|
response.status,
|
|
@@ -1645,6 +1682,7 @@ var HttpTransport = class {
|
|
|
1645
1682
|
);
|
|
1646
1683
|
}
|
|
1647
1684
|
const responseText = await response.text();
|
|
1685
|
+
this.observeResponse(config.path, response, responseText);
|
|
1648
1686
|
if (config.rawText) {
|
|
1649
1687
|
return responseText;
|
|
1650
1688
|
}
|
|
@@ -1705,6 +1743,7 @@ var HttpTransport = class {
|
|
|
1705
1743
|
...this.defaultHeaders,
|
|
1706
1744
|
...config.headers
|
|
1707
1745
|
};
|
|
1746
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1708
1747
|
if (config.rawBodyStr === void 0 && config.body !== void 0 && config.body !== null) {
|
|
1709
1748
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1710
1749
|
}
|
|
@@ -1721,6 +1760,7 @@ var HttpTransport = class {
|
|
|
1721
1760
|
try {
|
|
1722
1761
|
const response = await localNetworkFetch(url, init);
|
|
1723
1762
|
if (response.ok || config.allowStatuses?.includes(response.status)) {
|
|
1763
|
+
this.observeResponse(config.path, response, void 0);
|
|
1724
1764
|
return response;
|
|
1725
1765
|
}
|
|
1726
1766
|
const text = await response.text();
|
|
@@ -1733,15 +1773,19 @@ var HttpTransport = class {
|
|
|
1733
1773
|
}
|
|
1734
1774
|
if (response.status === 401) {
|
|
1735
1775
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1776
|
+
this.observeResponse(config.path, response, text, code);
|
|
1736
1777
|
throw new AoudaAuthenticationError(
|
|
1737
1778
|
errorBody?.error ?? "Unauthorized",
|
|
1738
1779
|
code,
|
|
1739
1780
|
401,
|
|
1740
1781
|
errorBody?.details,
|
|
1741
|
-
errorBody?.requestId
|
|
1782
|
+
errorBody?.requestId,
|
|
1783
|
+
void 0,
|
|
1784
|
+
errorBody?.token
|
|
1742
1785
|
);
|
|
1743
1786
|
}
|
|
1744
1787
|
if (errorBody?.code != null) {
|
|
1788
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1745
1789
|
throw createApiError(
|
|
1746
1790
|
response.status,
|
|
1747
1791
|
response.statusText,
|
|
@@ -1749,6 +1793,7 @@ var HttpTransport = class {
|
|
|
1749
1793
|
response.headers.get("Retry-After")
|
|
1750
1794
|
);
|
|
1751
1795
|
}
|
|
1796
|
+
this.observeResponse(config.path, response, text);
|
|
1752
1797
|
throw new AoudaResponseError(
|
|
1753
1798
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1754
1799
|
response.status,
|
|
@@ -1903,6 +1948,47 @@ var HttpTransport = class {
|
|
|
1903
1948
|
});
|
|
1904
1949
|
}
|
|
1905
1950
|
};
|
|
1951
|
+
function isAuthPath(path4) {
|
|
1952
|
+
let p = path4;
|
|
1953
|
+
const q = p.indexOf("?");
|
|
1954
|
+
if (q >= 0) {
|
|
1955
|
+
p = p.slice(0, q);
|
|
1956
|
+
}
|
|
1957
|
+
if (/^https?:\/\//i.test(p)) {
|
|
1958
|
+
try {
|
|
1959
|
+
p = new URL(p).pathname;
|
|
1960
|
+
} catch {
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
const lower = p.toLowerCase();
|
|
1964
|
+
if (lower === "/api/auth" || lower.startsWith("/api/auth/")) {
|
|
1965
|
+
return true;
|
|
1966
|
+
}
|
|
1967
|
+
const prefix = "/api/databases/";
|
|
1968
|
+
if (!lower.startsWith(prefix)) {
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
const rest = lower.slice(prefix.length);
|
|
1972
|
+
const slash = rest.indexOf("/");
|
|
1973
|
+
if (slash < 0) {
|
|
1974
|
+
return false;
|
|
1975
|
+
}
|
|
1976
|
+
const afterDb = rest.slice(slash + 1);
|
|
1977
|
+
return afterDb === "auth" || afterDb.startsWith("auth/");
|
|
1978
|
+
}
|
|
1979
|
+
function readBodyToken(bodyText) {
|
|
1980
|
+
if (bodyText == null || bodyText.trim().length === 0) {
|
|
1981
|
+
return void 0;
|
|
1982
|
+
}
|
|
1983
|
+
try {
|
|
1984
|
+
const parsed = JSON.parse(bodyText);
|
|
1985
|
+
if (parsed !== null && typeof parsed === "object" && "token" in parsed && typeof parsed.token === "string") {
|
|
1986
|
+
return parsed.token;
|
|
1987
|
+
}
|
|
1988
|
+
} catch {
|
|
1989
|
+
}
|
|
1990
|
+
return void 0;
|
|
1991
|
+
}
|
|
1906
1992
|
|
|
1907
1993
|
// src/resilience/retry.ts
|
|
1908
1994
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -2335,6 +2421,48 @@ function databasePath2(db) {
|
|
|
2335
2421
|
return `/api/databases/${encodeURIComponent(db)}`;
|
|
2336
2422
|
}
|
|
2337
2423
|
|
|
2424
|
+
// src/consistency-token-store.ts
|
|
2425
|
+
var MemoryConsistencyTokenStore = class {
|
|
2426
|
+
constructor() {
|
|
2427
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
2428
|
+
}
|
|
2429
|
+
get(database) {
|
|
2430
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2431
|
+
throw new Error("database must be a non-empty string");
|
|
2432
|
+
}
|
|
2433
|
+
return this.tokens.get(normalizeKey(database));
|
|
2434
|
+
}
|
|
2435
|
+
observe(database, token) {
|
|
2436
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2437
|
+
throw new Error("database must be a non-empty string");
|
|
2438
|
+
}
|
|
2439
|
+
if (token == null || token.trim().length === 0) {
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
const key = normalizeKey(database);
|
|
2443
|
+
const stored = this.tokens.get(key);
|
|
2444
|
+
if (stored === void 0 || compareOrdinal(token, stored) > 0) {
|
|
2445
|
+
this.tokens.set(key, token);
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
};
|
|
2449
|
+
function compareOrdinal(left, right) {
|
|
2450
|
+
if (left === right) return 0;
|
|
2451
|
+
return left < right ? -1 : 1;
|
|
2452
|
+
}
|
|
2453
|
+
function maxToken(left, right) {
|
|
2454
|
+
if (left == null || left.length === 0) {
|
|
2455
|
+
return right == null || right.length === 0 ? void 0 : right;
|
|
2456
|
+
}
|
|
2457
|
+
if (right == null || right.length === 0) {
|
|
2458
|
+
return left;
|
|
2459
|
+
}
|
|
2460
|
+
return compareOrdinal(left, right) >= 0 ? left : right;
|
|
2461
|
+
}
|
|
2462
|
+
function normalizeKey(database) {
|
|
2463
|
+
return database.toLowerCase();
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2338
2466
|
// src/streaming/subscription.ts
|
|
2339
2467
|
var AsyncEventQueue = class {
|
|
2340
2468
|
constructor() {
|
|
@@ -2391,7 +2519,7 @@ var AsyncEventQueue = class {
|
|
|
2391
2519
|
}
|
|
2392
2520
|
};
|
|
2393
2521
|
var TableSubscription = class {
|
|
2394
|
-
constructor(transport, identity, options = {}, onWarnings) {
|
|
2522
|
+
constructor(transport, identity, options = {}, onWarnings, store, database) {
|
|
2395
2523
|
this._queue = new AsyncEventQueue();
|
|
2396
2524
|
this._active = true;
|
|
2397
2525
|
this._started = false;
|
|
@@ -2407,6 +2535,11 @@ var TableSubscription = class {
|
|
|
2407
2535
|
this._onError = options.onError;
|
|
2408
2536
|
this._onWarnings = onWarnings;
|
|
2409
2537
|
this._conflate = options.conflate;
|
|
2538
|
+
this._atLeast = options.atLeast;
|
|
2539
|
+
this._waitMs = options.waitMs;
|
|
2540
|
+
this._onExceeded = options.onExceeded;
|
|
2541
|
+
this._store = store;
|
|
2542
|
+
this._database = database;
|
|
2410
2543
|
this._reconnectHandlerKey = `${this.id}::reconnect`;
|
|
2411
2544
|
}
|
|
2412
2545
|
get lastVersion() {
|
|
@@ -2471,7 +2604,7 @@ var TableSubscription = class {
|
|
|
2471
2604
|
id: this.id
|
|
2472
2605
|
};
|
|
2473
2606
|
if (this._identity.kind === "named") {
|
|
2474
|
-
message.
|
|
2607
|
+
message.name = this._identity.name;
|
|
2475
2608
|
if (this._identity.args !== void 0) {
|
|
2476
2609
|
message.args = this._identity.args;
|
|
2477
2610
|
}
|
|
@@ -2490,8 +2623,30 @@ var TableSubscription = class {
|
|
|
2490
2623
|
if (this._conflate !== void 0) {
|
|
2491
2624
|
message.conflate = this._conflate;
|
|
2492
2625
|
}
|
|
2626
|
+
const pin = this._resolvePin();
|
|
2627
|
+
if (pin !== void 0) {
|
|
2628
|
+
message.at_least = pin;
|
|
2629
|
+
}
|
|
2630
|
+
if (this._waitMs !== void 0) {
|
|
2631
|
+
message.wait_ms = this._waitMs;
|
|
2632
|
+
}
|
|
2633
|
+
if (this._onExceeded !== void 0) {
|
|
2634
|
+
message.on_exceeded = this._onExceeded;
|
|
2635
|
+
}
|
|
2493
2636
|
await this._transport.send(message);
|
|
2494
2637
|
}
|
|
2638
|
+
_resolvePin() {
|
|
2639
|
+
if (this._atLeast !== void 0 && this._store != null && this._database != null) {
|
|
2640
|
+
this._store.observe(this._database, this._atLeast);
|
|
2641
|
+
}
|
|
2642
|
+
const stored = this._store != null && this._database != null ? this._store.get(this._database) : void 0;
|
|
2643
|
+
return maxToken(this._atLeast, stored);
|
|
2644
|
+
}
|
|
2645
|
+
_observeToken(token) {
|
|
2646
|
+
if (token !== void 0 && this._store != null && this._database != null) {
|
|
2647
|
+
this._store.observe(this._database, token);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2495
2650
|
_handleMessage(message) {
|
|
2496
2651
|
if (!this._active) {
|
|
2497
2652
|
return;
|
|
@@ -2518,6 +2673,7 @@ var TableSubscription = class {
|
|
|
2518
2673
|
}
|
|
2519
2674
|
_handleSnapshotPage(message) {
|
|
2520
2675
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2676
|
+
this._observeToken(message.token);
|
|
2521
2677
|
}
|
|
2522
2678
|
_handleSnapshotComplete(message) {
|
|
2523
2679
|
this._lastVersion = message.version;
|
|
@@ -2535,6 +2691,10 @@ var TableSubscription = class {
|
|
|
2535
2691
|
if (message.total_matches !== void 0) {
|
|
2536
2692
|
snapshot.totalMatches = message.total_matches;
|
|
2537
2693
|
}
|
|
2694
|
+
if (message.token !== void 0) {
|
|
2695
|
+
snapshot.token = message.token;
|
|
2696
|
+
this._observeToken(message.token);
|
|
2697
|
+
}
|
|
2538
2698
|
this._queue.push(snapshot);
|
|
2539
2699
|
}
|
|
2540
2700
|
async _handleGap(message) {
|
|
@@ -2560,6 +2720,10 @@ var TableSubscription = class {
|
|
|
2560
2720
|
if (message.values_skipped !== void 0) {
|
|
2561
2721
|
event.values_skipped = message.values_skipped;
|
|
2562
2722
|
}
|
|
2723
|
+
if (message.token !== void 0) {
|
|
2724
|
+
event.token = message.token;
|
|
2725
|
+
this._observeToken(message.token);
|
|
2726
|
+
}
|
|
2563
2727
|
this._onChange?.(event);
|
|
2564
2728
|
this._queue.push(event);
|
|
2565
2729
|
}
|
|
@@ -2904,11 +3068,12 @@ var TableQuery = class _TableQuery {
|
|
|
2904
3068
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2905
3069
|
* @internal Use `client.table()` to create queries.
|
|
2906
3070
|
*/
|
|
2907
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
3071
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2908
3072
|
this.transport = transport;
|
|
2909
3073
|
this.tableName = tableName;
|
|
2910
3074
|
this.database = database;
|
|
2911
3075
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
3076
|
+
this.store = store;
|
|
2912
3077
|
this.state = state ?? {
|
|
2913
3078
|
predicates: [],
|
|
2914
3079
|
groupClauses: [],
|
|
@@ -2924,6 +3089,16 @@ var TableQuery = class _TableQuery {
|
|
|
2924
3089
|
isDistinct: false
|
|
2925
3090
|
};
|
|
2926
3091
|
}
|
|
3092
|
+
withState(state) {
|
|
3093
|
+
return new _TableQuery(
|
|
3094
|
+
this.transport,
|
|
3095
|
+
this.tableName,
|
|
3096
|
+
this.database,
|
|
3097
|
+
state,
|
|
3098
|
+
this.getWebSocketTransport,
|
|
3099
|
+
this.store
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
2927
3102
|
where(column, operator, value) {
|
|
2928
3103
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2929
3104
|
return new _TableQuery(
|
|
@@ -2934,7 +3109,8 @@ var TableQuery = class _TableQuery {
|
|
|
2934
3109
|
...this.state,
|
|
2935
3110
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2936
3111
|
},
|
|
2937
|
-
this.getWebSocketTransport
|
|
3112
|
+
this.getWebSocketTransport,
|
|
3113
|
+
this.store
|
|
2938
3114
|
);
|
|
2939
3115
|
}
|
|
2940
3116
|
/**
|
|
@@ -2953,7 +3129,7 @@ var TableQuery = class _TableQuery {
|
|
|
2953
3129
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2954
3130
|
...this.state,
|
|
2955
3131
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2956
|
-
}, this.getWebSocketTransport);
|
|
3132
|
+
}, this.getWebSocketTransport, this.store);
|
|
2957
3133
|
}
|
|
2958
3134
|
/**
|
|
2959
3135
|
* Sets the primary sort column for the query.
|
|
@@ -2978,7 +3154,7 @@ var TableQuery = class _TableQuery {
|
|
|
2978
3154
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2979
3155
|
...this.state,
|
|
2980
3156
|
orderByClauses: [orderByClause]
|
|
2981
|
-
}, this.getWebSocketTransport);
|
|
3157
|
+
}, this.getWebSocketTransport, this.store);
|
|
2982
3158
|
}
|
|
2983
3159
|
/**
|
|
2984
3160
|
* Sets the primary sort column to descending order.
|
|
@@ -3024,7 +3200,7 @@ var TableQuery = class _TableQuery {
|
|
|
3024
3200
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3025
3201
|
...this.state,
|
|
3026
3202
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
3027
|
-
}, this.getWebSocketTransport);
|
|
3203
|
+
}, this.getWebSocketTransport, this.store);
|
|
3028
3204
|
}
|
|
3029
3205
|
/**
|
|
3030
3206
|
* Sets the maximum number of rows to return.
|
|
@@ -3041,7 +3217,7 @@ var TableQuery = class _TableQuery {
|
|
|
3041
3217
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3042
3218
|
...this.state,
|
|
3043
3219
|
limitValue: count
|
|
3044
|
-
}, this.getWebSocketTransport);
|
|
3220
|
+
}, this.getWebSocketTransport, this.store);
|
|
3045
3221
|
}
|
|
3046
3222
|
/**
|
|
3047
3223
|
* Sets the number of rows to skip.
|
|
@@ -3058,7 +3234,7 @@ var TableQuery = class _TableQuery {
|
|
|
3058
3234
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3059
3235
|
...this.state,
|
|
3060
3236
|
offsetValue: count
|
|
3061
|
-
}, this.getWebSocketTransport);
|
|
3237
|
+
}, this.getWebSocketTransport, this.store);
|
|
3062
3238
|
}
|
|
3063
3239
|
/**
|
|
3064
3240
|
* Requests cross-partition access for this query.
|
|
@@ -3073,10 +3249,21 @@ var TableQuery = class _TableQuery {
|
|
|
3073
3249
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3074
3250
|
...this.state,
|
|
3075
3251
|
crossPartitionAccess: true
|
|
3076
|
-
}, this.getWebSocketTransport);
|
|
3252
|
+
}, this.getWebSocketTransport, this.store);
|
|
3077
3253
|
}
|
|
3078
3254
|
/**
|
|
3079
|
-
*
|
|
3255
|
+
* Pin this query at at least this C-1 token. Observes the token into the
|
|
3256
|
+
* client store (I3, sticky) and presents it on execute via `X-Aouda-Token`.
|
|
3257
|
+
*/
|
|
3258
|
+
atLeast(token) {
|
|
3259
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
3260
|
+
throw new Error("atLeast() requires a non-empty token");
|
|
3261
|
+
}
|
|
3262
|
+
this.store?.observe(this.database, token);
|
|
3263
|
+
return this.withState({ ...this.state, atLeast: token });
|
|
3264
|
+
}
|
|
3265
|
+
/**
|
|
3266
|
+
* Selects specific columns to return.
|
|
3080
3267
|
* If not called, all columns are returned.
|
|
3081
3268
|
*
|
|
3082
3269
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -3098,7 +3285,7 @@ var TableQuery = class _TableQuery {
|
|
|
3098
3285
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3099
3286
|
...this.state,
|
|
3100
3287
|
selectColumns: columns.length > 0 ? columns : null
|
|
3101
|
-
}, this.getWebSocketTransport);
|
|
3288
|
+
}, this.getWebSocketTransport, this.store);
|
|
3102
3289
|
}
|
|
3103
3290
|
/**
|
|
3104
3291
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -3128,7 +3315,7 @@ var TableQuery = class _TableQuery {
|
|
|
3128
3315
|
...this.state,
|
|
3129
3316
|
selectColumns: columns,
|
|
3130
3317
|
isDistinct: true
|
|
3131
|
-
}, this.getWebSocketTransport);
|
|
3318
|
+
}, this.getWebSocketTransport, this.store);
|
|
3132
3319
|
}
|
|
3133
3320
|
/**
|
|
3134
3321
|
* Adds server-side computed columns to the query result.
|
|
@@ -3157,7 +3344,7 @@ var TableQuery = class _TableQuery {
|
|
|
3157
3344
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3158
3345
|
...this.state,
|
|
3159
3346
|
selectExprs: projections
|
|
3160
|
-
}, this.getWebSocketTransport);
|
|
3347
|
+
}, this.getWebSocketTransport, this.store);
|
|
3161
3348
|
}
|
|
3162
3349
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
3163
3350
|
return this.addJoinClause(
|
|
@@ -3215,7 +3402,8 @@ var TableQuery = class _TableQuery {
|
|
|
3215
3402
|
}
|
|
3216
3403
|
]
|
|
3217
3404
|
},
|
|
3218
|
-
this.getWebSocketTransport
|
|
3405
|
+
this.getWebSocketTransport,
|
|
3406
|
+
this.store
|
|
3219
3407
|
);
|
|
3220
3408
|
}
|
|
3221
3409
|
/**
|
|
@@ -3251,7 +3439,8 @@ var TableQuery = class _TableQuery {
|
|
|
3251
3439
|
...this.state,
|
|
3252
3440
|
groupByColumns: [...columns]
|
|
3253
3441
|
},
|
|
3254
|
-
this.getWebSocketTransport
|
|
3442
|
+
this.getWebSocketTransport,
|
|
3443
|
+
this.store
|
|
3255
3444
|
);
|
|
3256
3445
|
}
|
|
3257
3446
|
/**
|
|
@@ -3285,8 +3474,11 @@ var TableQuery = class _TableQuery {
|
|
|
3285
3474
|
onSnapshot: options.onSnapshot,
|
|
3286
3475
|
onChange: options.onChange,
|
|
3287
3476
|
onError: options.onError,
|
|
3288
|
-
conflate: options.conflate
|
|
3289
|
-
|
|
3477
|
+
conflate: options.conflate,
|
|
3478
|
+
atLeast: options.atLeast ?? this.state.atLeast,
|
|
3479
|
+
waitMs: options.waitMs,
|
|
3480
|
+
onExceeded: options.onExceeded
|
|
3481
|
+
}, void 0, this.store, this.database);
|
|
3290
3482
|
subscription.start();
|
|
3291
3483
|
return subscription;
|
|
3292
3484
|
}
|
|
@@ -3401,7 +3593,8 @@ var TableQuery = class _TableQuery {
|
|
|
3401
3593
|
...this.state,
|
|
3402
3594
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3403
3595
|
},
|
|
3404
|
-
this.getWebSocketTransport
|
|
3596
|
+
this.getWebSocketTransport,
|
|
3597
|
+
this.store
|
|
3405
3598
|
);
|
|
3406
3599
|
}
|
|
3407
3600
|
addAggregate(op, column) {
|
|
@@ -3422,7 +3615,8 @@ var TableQuery = class _TableQuery {
|
|
|
3422
3615
|
}
|
|
3423
3616
|
]
|
|
3424
3617
|
},
|
|
3425
|
-
this.getWebSocketTransport
|
|
3618
|
+
this.getWebSocketTransport,
|
|
3619
|
+
this.store
|
|
3426
3620
|
);
|
|
3427
3621
|
}
|
|
3428
3622
|
requireWebSocketTransport() {
|
|
@@ -3452,17 +3646,23 @@ var TableQuery = class _TableQuery {
|
|
|
3452
3646
|
* ```
|
|
3453
3647
|
*/
|
|
3454
3648
|
async execute() {
|
|
3649
|
+
if (this.state.atLeast) {
|
|
3650
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3651
|
+
}
|
|
3455
3652
|
const request = this.buildRequest();
|
|
3456
3653
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3457
3654
|
const response = await this.transport.post(path4, request);
|
|
3458
3655
|
const rows = columnarToRows(response);
|
|
3459
3656
|
const stats = response.stats;
|
|
3460
|
-
return { rows, stats };
|
|
3657
|
+
return { rows, stats, token: response.token };
|
|
3461
3658
|
}
|
|
3462
3659
|
/**
|
|
3463
3660
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3464
3661
|
*/
|
|
3465
3662
|
async toColumnar() {
|
|
3663
|
+
if (this.state.atLeast) {
|
|
3664
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3665
|
+
}
|
|
3466
3666
|
const request = this.buildRequest();
|
|
3467
3667
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3468
3668
|
return this.transport.post(path4, request);
|
|
@@ -3492,8 +3692,12 @@ var TableQuery = class _TableQuery {
|
|
|
3492
3692
|
limitValue: 0,
|
|
3493
3693
|
selectColumns: []
|
|
3494
3694
|
},
|
|
3495
|
-
this.getWebSocketTransport
|
|
3695
|
+
this.getWebSocketTransport,
|
|
3696
|
+
this.store
|
|
3496
3697
|
);
|
|
3698
|
+
if (this.state.atLeast) {
|
|
3699
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3700
|
+
}
|
|
3497
3701
|
const request = countQuery.buildRequest();
|
|
3498
3702
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3499
3703
|
const response = await this.transport.post(path4, request);
|
|
@@ -3540,7 +3744,8 @@ var TableQuery = class _TableQuery {
|
|
|
3540
3744
|
const response = await this.transport.post(path4, body);
|
|
3541
3745
|
const result = {
|
|
3542
3746
|
rowsInserted: response.rowsInserted,
|
|
3543
|
-
executionMs: response.executionMs
|
|
3747
|
+
executionMs: response.executionMs,
|
|
3748
|
+
token: response.token
|
|
3544
3749
|
};
|
|
3545
3750
|
if (response.generatedValues !== void 0) {
|
|
3546
3751
|
result.generatedValues = response.generatedValues;
|
|
@@ -3590,7 +3795,8 @@ var TableQuery = class _TableQuery {
|
|
|
3590
3795
|
const response = await this.transport.post(path4, body);
|
|
3591
3796
|
const result = {
|
|
3592
3797
|
rowsInserted: response.rowsInserted,
|
|
3593
|
-
executionMs: response.executionMs
|
|
3798
|
+
executionMs: response.executionMs,
|
|
3799
|
+
token: response.token
|
|
3594
3800
|
};
|
|
3595
3801
|
if (response.generatedValues !== void 0) {
|
|
3596
3802
|
result.generatedValues = response.generatedValues;
|
|
@@ -3642,6 +3848,7 @@ var TableQuery = class _TableQuery {
|
|
|
3642
3848
|
return {
|
|
3643
3849
|
rowsAffected: response.rowsUpdated,
|
|
3644
3850
|
executionMs: response.executionMs,
|
|
3851
|
+
token: response.token,
|
|
3645
3852
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3646
3853
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3647
3854
|
};
|
|
@@ -3692,6 +3899,7 @@ var TableQuery = class _TableQuery {
|
|
|
3692
3899
|
rowsAffected: response.rowsDeleted,
|
|
3693
3900
|
executionMs: response.executionMs,
|
|
3694
3901
|
hasMore: response.hasMore,
|
|
3902
|
+
token: response.token,
|
|
3695
3903
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3696
3904
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3697
3905
|
};
|
|
@@ -3711,7 +3919,8 @@ var TableQuery = class _TableQuery {
|
|
|
3711
3919
|
return {
|
|
3712
3920
|
rowsAffected: response.rowsDeleted,
|
|
3713
3921
|
executionMs: response.executionMs,
|
|
3714
|
-
hasMore: false
|
|
3922
|
+
hasMore: false,
|
|
3923
|
+
token: response.token
|
|
3715
3924
|
};
|
|
3716
3925
|
}
|
|
3717
3926
|
/**
|
|
@@ -3724,7 +3933,14 @@ var TableQuery = class _TableQuery {
|
|
|
3724
3933
|
throw new Error("batch() requires a non-empty operations array");
|
|
3725
3934
|
}
|
|
3726
3935
|
const wireOperations = operations.map((op, index) => {
|
|
3727
|
-
const base = new _TableQuery(
|
|
3936
|
+
const base = new _TableQuery(
|
|
3937
|
+
this.transport,
|
|
3938
|
+
this.tableName,
|
|
3939
|
+
this.database,
|
|
3940
|
+
void 0,
|
|
3941
|
+
this.getWebSocketTransport,
|
|
3942
|
+
this.store
|
|
3943
|
+
);
|
|
3728
3944
|
const scoped = op.where(base);
|
|
3729
3945
|
const where = scoped.buildWhereClause();
|
|
3730
3946
|
if (!where) {
|
|
@@ -5061,12 +5277,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
5061
5277
|
continue;
|
|
5062
5278
|
}
|
|
5063
5279
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
5064
|
-
const
|
|
5280
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
5065
5281
|
sink({
|
|
5066
5282
|
code: warning.code,
|
|
5067
|
-
|
|
5283
|
+
name: warning.name,
|
|
5068
5284
|
sunsetAt: warning.sunsetAt,
|
|
5069
|
-
message: `${warning.code}:${
|
|
5285
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
5070
5286
|
});
|
|
5071
5287
|
}
|
|
5072
5288
|
}
|
|
@@ -5079,24 +5295,28 @@ function emptyStats() {
|
|
|
5079
5295
|
};
|
|
5080
5296
|
}
|
|
5081
5297
|
var NamedQueriesApi = class {
|
|
5082
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5298
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
5083
5299
|
this.transport = transport;
|
|
5084
5300
|
this.database = database;
|
|
5085
5301
|
this.onWarning = onWarning;
|
|
5086
5302
|
this.getStreamingTransport = getStreamingTransport;
|
|
5303
|
+
this.store = store;
|
|
5087
5304
|
}
|
|
5088
|
-
async execute(
|
|
5089
|
-
if (typeof
|
|
5090
|
-
throw new Error("Named query
|
|
5305
|
+
async execute(name, args, options) {
|
|
5306
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5307
|
+
throw new Error("Named query name must be a non-empty string");
|
|
5091
5308
|
}
|
|
5092
5309
|
const prefix = databasePath2(this.database);
|
|
5093
|
-
const path4 = `${prefix}/named-queries/${encodeURIComponent(
|
|
5310
|
+
const path4 = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
5094
5311
|
const body = {
|
|
5095
5312
|
args: args ?? {}
|
|
5096
5313
|
};
|
|
5097
5314
|
if (options?.orderByIndex !== void 0) {
|
|
5098
5315
|
body.orderByIndex = options.orderByIndex;
|
|
5099
5316
|
}
|
|
5317
|
+
if (options?.atLeast !== void 0) {
|
|
5318
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5319
|
+
}
|
|
5100
5320
|
const response = await this.transport.post(
|
|
5101
5321
|
path4,
|
|
5102
5322
|
body,
|
|
@@ -5108,7 +5328,8 @@ var NamedQueriesApi = class {
|
|
|
5108
5328
|
rows,
|
|
5109
5329
|
stats: response.stats,
|
|
5110
5330
|
warnings: response.warnings,
|
|
5111
|
-
totalMatches: response.totalMatches
|
|
5331
|
+
totalMatches: response.totalMatches,
|
|
5332
|
+
token: response.token
|
|
5112
5333
|
};
|
|
5113
5334
|
}
|
|
5114
5335
|
async batch(items, options) {
|
|
@@ -5126,6 +5347,9 @@ var NamedQueriesApi = class {
|
|
|
5126
5347
|
400
|
|
5127
5348
|
);
|
|
5128
5349
|
}
|
|
5350
|
+
if (options?.atLeast !== void 0) {
|
|
5351
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5352
|
+
}
|
|
5129
5353
|
const prefix = databasePath2(this.database);
|
|
5130
5354
|
const path4 = `${prefix}/named-queries/batch?format=columnar`;
|
|
5131
5355
|
const envelope = await this.transport.post(
|
|
@@ -5148,34 +5372,41 @@ var NamedQueriesApi = class {
|
|
|
5148
5372
|
rowCount: slot.rowCount ?? 0,
|
|
5149
5373
|
stats: slot.stats ?? emptyStats(),
|
|
5150
5374
|
warnings: slot.warnings,
|
|
5151
|
-
totalMatches: slot.totalMatches
|
|
5375
|
+
totalMatches: slot.totalMatches,
|
|
5376
|
+
token: slot.token
|
|
5152
5377
|
};
|
|
5153
5378
|
const result = {
|
|
5154
5379
|
rows: columnarToRows(columnar),
|
|
5155
5380
|
stats: columnar.stats,
|
|
5156
5381
|
warnings: slot.warnings,
|
|
5157
|
-
totalMatches: slot.totalMatches
|
|
5382
|
+
totalMatches: slot.totalMatches,
|
|
5383
|
+
token: slot.token
|
|
5158
5384
|
};
|
|
5159
5385
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
5160
5386
|
return { isError: false, result };
|
|
5161
5387
|
});
|
|
5162
5388
|
}
|
|
5163
|
-
subscribe(
|
|
5164
|
-
if (typeof
|
|
5165
|
-
throw new Error("Named query
|
|
5389
|
+
subscribe(name, args, options = {}) {
|
|
5390
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5391
|
+
throw new Error("Named query name must be a non-empty string");
|
|
5166
5392
|
}
|
|
5167
5393
|
const subscription = new TableSubscription(
|
|
5168
5394
|
this.getStreamingTransport(),
|
|
5169
|
-
{ kind: "named",
|
|
5395
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
5170
5396
|
{
|
|
5171
5397
|
onSnapshot: options.onSnapshot,
|
|
5172
5398
|
onChange: options.onChange,
|
|
5173
5399
|
onError: options.onError,
|
|
5174
|
-
conflate: options.conflate
|
|
5400
|
+
conflate: options.conflate,
|
|
5401
|
+
atLeast: options.atLeast,
|
|
5402
|
+
waitMs: options.waitMs,
|
|
5403
|
+
onExceeded: options.onExceeded
|
|
5175
5404
|
},
|
|
5176
5405
|
(warnings) => {
|
|
5177
5406
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
5178
|
-
}
|
|
5407
|
+
},
|
|
5408
|
+
this.store,
|
|
5409
|
+
this.database
|
|
5179
5410
|
);
|
|
5180
5411
|
subscription.start();
|
|
5181
5412
|
return subscription;
|
|
@@ -5187,12 +5418,12 @@ var NamedMutationsApi = class {
|
|
|
5187
5418
|
this.database = database;
|
|
5188
5419
|
this.onWarning = onWarning;
|
|
5189
5420
|
}
|
|
5190
|
-
async execute(
|
|
5191
|
-
if (typeof
|
|
5192
|
-
throw new Error("Named mutation
|
|
5421
|
+
async execute(name, args) {
|
|
5422
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5423
|
+
throw new Error("Named mutation name must be a non-empty string");
|
|
5193
5424
|
}
|
|
5194
5425
|
const prefix = databasePath2(this.database);
|
|
5195
|
-
const path4 = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5426
|
+
const path4 = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
5196
5427
|
const wire = await this.transport.post(path4, {
|
|
5197
5428
|
args: args ?? {}
|
|
5198
5429
|
});
|
|
@@ -5253,6 +5484,7 @@ var WebSocketTransport = class {
|
|
|
5253
5484
|
// Serialized-send queue: each send appends to this tail.
|
|
5254
5485
|
this._sendTail = Promise.resolve();
|
|
5255
5486
|
this._lastVersion = 0;
|
|
5487
|
+
this._lastToken = null;
|
|
5256
5488
|
this._reconnectAttempt = 0;
|
|
5257
5489
|
this._disposed = false;
|
|
5258
5490
|
this._missedPings = 0;
|
|
@@ -5270,6 +5502,7 @@ var WebSocketTransport = class {
|
|
|
5270
5502
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
5271
5503
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
5272
5504
|
this._enableCompression = options.enableCompression ?? true;
|
|
5505
|
+
this._store = options.consistencyTokenStore;
|
|
5273
5506
|
this._wireMode = options.wireMode ?? "json";
|
|
5274
5507
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
5275
5508
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -5278,10 +5511,14 @@ var WebSocketTransport = class {
|
|
|
5278
5511
|
});
|
|
5279
5512
|
}
|
|
5280
5513
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
5281
|
-
/** Latest
|
|
5514
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
5282
5515
|
get lastVersion() {
|
|
5283
5516
|
return this._lastVersion;
|
|
5284
5517
|
}
|
|
5518
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5519
|
+
get lastToken() {
|
|
5520
|
+
return this._lastToken;
|
|
5521
|
+
}
|
|
5285
5522
|
/**
|
|
5286
5523
|
* Registers a handler for incoming server messages with the given channel id.
|
|
5287
5524
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5469,6 +5706,10 @@ var WebSocketTransport = class {
|
|
|
5469
5706
|
}
|
|
5470
5707
|
case "heartbeat":
|
|
5471
5708
|
this._lastVersion = msg.version;
|
|
5709
|
+
this._lastToken = msg.token ?? null;
|
|
5710
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5711
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5712
|
+
}
|
|
5472
5713
|
break;
|
|
5473
5714
|
case "pong":
|
|
5474
5715
|
this._missedPings = 0;
|
|
@@ -5634,16 +5875,21 @@ var LongPollTransport = class {
|
|
|
5634
5875
|
this._connected = false;
|
|
5635
5876
|
this._pollTask = null;
|
|
5636
5877
|
this._lastVersion = 0;
|
|
5878
|
+
this._lastToken = null;
|
|
5637
5879
|
this._serverUrl = serverUrl;
|
|
5638
5880
|
this._database = database;
|
|
5639
5881
|
this._authHandler = options.authHandler;
|
|
5640
5882
|
this._onReconnected = options.onReconnected;
|
|
5641
5883
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5642
5884
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5885
|
+
this._store = options.consistencyTokenStore;
|
|
5643
5886
|
}
|
|
5644
5887
|
get lastVersion() {
|
|
5645
5888
|
return this._lastVersion;
|
|
5646
5889
|
}
|
|
5890
|
+
get lastToken() {
|
|
5891
|
+
return this._lastToken;
|
|
5892
|
+
}
|
|
5647
5893
|
registerHandler(id, handler) {
|
|
5648
5894
|
this._handlers.set(id, handler);
|
|
5649
5895
|
}
|
|
@@ -5766,6 +6012,10 @@ var LongPollTransport = class {
|
|
|
5766
6012
|
for (const msg of payload.messages) {
|
|
5767
6013
|
if (msg.type === "heartbeat") {
|
|
5768
6014
|
this._lastVersion = msg.version;
|
|
6015
|
+
this._lastToken = msg.token ?? null;
|
|
6016
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
6017
|
+
this._store?.observe(this._database, this._lastToken);
|
|
6018
|
+
}
|
|
5769
6019
|
}
|
|
5770
6020
|
const id = "id" in msg ? msg.id : void 0;
|
|
5771
6021
|
if (id !== void 0 && id !== null) {
|
|
@@ -5845,6 +6095,9 @@ var FallbackStreamingTransport = class {
|
|
|
5845
6095
|
get lastVersion() {
|
|
5846
6096
|
return this._active.lastVersion;
|
|
5847
6097
|
}
|
|
6098
|
+
get lastToken() {
|
|
6099
|
+
return this._active.lastToken;
|
|
6100
|
+
}
|
|
5848
6101
|
registerHandler(id, handler) {
|
|
5849
6102
|
this._handlers.set(id, handler);
|
|
5850
6103
|
this._active.registerHandler(id, handler);
|
|
@@ -5924,6 +6177,7 @@ var AoudaClient = class {
|
|
|
5924
6177
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5925
6178
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5926
6179
|
this.database = options.database.trim();
|
|
6180
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5927
6181
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5928
6182
|
throw new Error("timeout must be a finite positive number");
|
|
5929
6183
|
}
|
|
@@ -5958,7 +6212,9 @@ var AoudaClient = class {
|
|
|
5958
6212
|
}
|
|
5959
6213
|
const httpTransport = new HttpTransport({
|
|
5960
6214
|
baseUrl: this.baseUrl,
|
|
5961
|
-
timeout: this.timeout
|
|
6215
|
+
timeout: this.timeout,
|
|
6216
|
+
database: this.database,
|
|
6217
|
+
consistencyTokenStore: this._store
|
|
5962
6218
|
});
|
|
5963
6219
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5964
6220
|
if (activeAuth) {
|
|
@@ -6018,7 +6274,8 @@ var AoudaClient = class {
|
|
|
6018
6274
|
this.transport,
|
|
6019
6275
|
this.database,
|
|
6020
6276
|
onNamedArtifactWarning,
|
|
6021
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6277
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6278
|
+
this._store
|
|
6022
6279
|
);
|
|
6023
6280
|
this._namedMutations = new NamedMutationsApi(
|
|
6024
6281
|
this.transport,
|
|
@@ -6117,7 +6374,8 @@ var AoudaClient = class {
|
|
|
6117
6374
|
name,
|
|
6118
6375
|
this.database,
|
|
6119
6376
|
void 0,
|
|
6120
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6377
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6378
|
+
this._store
|
|
6121
6379
|
);
|
|
6122
6380
|
}
|
|
6123
6381
|
/**
|
|
@@ -6169,13 +6427,26 @@ var AoudaClient = class {
|
|
|
6169
6427
|
return this._materializedQueries;
|
|
6170
6428
|
}
|
|
6171
6429
|
/**
|
|
6172
|
-
*
|
|
6430
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
6173
6431
|
*/
|
|
6174
6432
|
get namedQueries() {
|
|
6175
6433
|
return this._namedQueries;
|
|
6176
6434
|
}
|
|
6435
|
+
observeConsistencyToken(token) {
|
|
6436
|
+
this._store.observe(this.database, token);
|
|
6437
|
+
}
|
|
6438
|
+
getObservedConsistencyToken() {
|
|
6439
|
+
return this._store.get(this.database);
|
|
6440
|
+
}
|
|
6441
|
+
async getConsistencyToken() {
|
|
6442
|
+
const body = await this.transport.get(
|
|
6443
|
+
`/api/databases/${encodeURIComponent(this.database)}/token`
|
|
6444
|
+
);
|
|
6445
|
+
this._store.observe(this.database, body.token);
|
|
6446
|
+
return this._store.get(this.database) ?? body.token;
|
|
6447
|
+
}
|
|
6177
6448
|
/**
|
|
6178
|
-
*
|
|
6449
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
6179
6450
|
*/
|
|
6180
6451
|
get namedMutations() {
|
|
6181
6452
|
return this._namedMutations;
|
|
@@ -6302,13 +6573,15 @@ var AoudaClient = class {
|
|
|
6302
6573
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
6303
6574
|
authHandler: this._authHandler,
|
|
6304
6575
|
enableCompression: this._streamingEnableCompression,
|
|
6305
|
-
wireMode: this._streamingWireMode
|
|
6576
|
+
wireMode: this._streamingWireMode,
|
|
6577
|
+
consistencyTokenStore: this._store
|
|
6306
6578
|
});
|
|
6307
6579
|
if (this._streamingEnableLongPollFallback) {
|
|
6308
6580
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
6309
6581
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
6310
6582
|
authHandler: this._authHandler,
|
|
6311
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6583
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6584
|
+
consistencyTokenStore: this._store
|
|
6312
6585
|
});
|
|
6313
6586
|
});
|
|
6314
6587
|
} else {
|
|
@@ -6333,7 +6606,7 @@ Usage:
|
|
|
6333
6606
|
npx @aouda/client schema <command> [options]
|
|
6334
6607
|
|
|
6335
6608
|
Commands:
|
|
6336
|
-
generate Fetch schema from Aouda server and output TypeScript types (tables + named query/mutation
|
|
6609
|
+
generate Fetch schema from Aouda server and output TypeScript types (tables + optional named query/mutation Args/Row)
|
|
6337
6610
|
schema Schema management (diff, apply, export, validate, history, seed)
|
|
6338
6611
|
diff Show migration plan (desired vs current)
|
|
6339
6612
|
apply Apply schema (use --allow-destructive for drops; --dry-run to preview)
|