@aouda/client 0.1.13 → 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 +366 -77
- 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 +366 -77
- package/dist/cli/index.js.map +1 -1
- package/dist/{client-DFujaTFB.d.cts → client-CXfjcF61.d.cts} +121 -23
- package/dist/{client-DFujaTFB.d.ts → client-CXfjcF61.d.ts} +121 -23
- package/dist/index.cjs +371 -76
- 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 +368 -76
- 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,10 +2604,13 @@ 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
|
}
|
|
2611
|
+
if (this._identity.orderByIndex !== void 0) {
|
|
2612
|
+
message.orderByIndex = this._identity.orderByIndex;
|
|
2613
|
+
}
|
|
2478
2614
|
} else {
|
|
2479
2615
|
message.target = this._identity.target;
|
|
2480
2616
|
if (this._identity.filter !== void 0) {
|
|
@@ -2487,8 +2623,30 @@ var TableSubscription = class {
|
|
|
2487
2623
|
if (this._conflate !== void 0) {
|
|
2488
2624
|
message.conflate = this._conflate;
|
|
2489
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
|
+
}
|
|
2490
2636
|
await this._transport.send(message);
|
|
2491
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
|
+
}
|
|
2492
2650
|
_handleMessage(message) {
|
|
2493
2651
|
if (!this._active) {
|
|
2494
2652
|
return;
|
|
@@ -2515,6 +2673,7 @@ var TableSubscription = class {
|
|
|
2515
2673
|
}
|
|
2516
2674
|
_handleSnapshotPage(message) {
|
|
2517
2675
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2676
|
+
this._observeToken(message.token);
|
|
2518
2677
|
}
|
|
2519
2678
|
_handleSnapshotComplete(message) {
|
|
2520
2679
|
this._lastVersion = message.version;
|
|
@@ -2523,12 +2682,20 @@ var TableSubscription = class {
|
|
|
2523
2682
|
}
|
|
2524
2683
|
const rows = this._pendingSnapshotRows;
|
|
2525
2684
|
this._pendingSnapshotRows = [];
|
|
2526
|
-
this._onSnapshot?.(rows, message.version);
|
|
2527
|
-
|
|
2685
|
+
this._onSnapshot?.(rows, message.version, message.total_matches);
|
|
2686
|
+
const snapshot = {
|
|
2528
2687
|
type: "snapshot",
|
|
2529
2688
|
rows,
|
|
2530
2689
|
version: message.version
|
|
2531
|
-
}
|
|
2690
|
+
};
|
|
2691
|
+
if (message.total_matches !== void 0) {
|
|
2692
|
+
snapshot.totalMatches = message.total_matches;
|
|
2693
|
+
}
|
|
2694
|
+
if (message.token !== void 0) {
|
|
2695
|
+
snapshot.token = message.token;
|
|
2696
|
+
this._observeToken(message.token);
|
|
2697
|
+
}
|
|
2698
|
+
this._queue.push(snapshot);
|
|
2532
2699
|
}
|
|
2533
2700
|
async _handleGap(message) {
|
|
2534
2701
|
this._pendingSnapshotRows = [];
|
|
@@ -2553,6 +2720,10 @@ var TableSubscription = class {
|
|
|
2553
2720
|
if (message.values_skipped !== void 0) {
|
|
2554
2721
|
event.values_skipped = message.values_skipped;
|
|
2555
2722
|
}
|
|
2723
|
+
if (message.token !== void 0) {
|
|
2724
|
+
event.token = message.token;
|
|
2725
|
+
this._observeToken(message.token);
|
|
2726
|
+
}
|
|
2556
2727
|
this._onChange?.(event);
|
|
2557
2728
|
this._queue.push(event);
|
|
2558
2729
|
}
|
|
@@ -2897,11 +3068,12 @@ var TableQuery = class _TableQuery {
|
|
|
2897
3068
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2898
3069
|
* @internal Use `client.table()` to create queries.
|
|
2899
3070
|
*/
|
|
2900
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
3071
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2901
3072
|
this.transport = transport;
|
|
2902
3073
|
this.tableName = tableName;
|
|
2903
3074
|
this.database = database;
|
|
2904
3075
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
3076
|
+
this.store = store;
|
|
2905
3077
|
this.state = state ?? {
|
|
2906
3078
|
predicates: [],
|
|
2907
3079
|
groupClauses: [],
|
|
@@ -2917,6 +3089,16 @@ var TableQuery = class _TableQuery {
|
|
|
2917
3089
|
isDistinct: false
|
|
2918
3090
|
};
|
|
2919
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
|
+
}
|
|
2920
3102
|
where(column, operator, value) {
|
|
2921
3103
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2922
3104
|
return new _TableQuery(
|
|
@@ -2927,7 +3109,8 @@ var TableQuery = class _TableQuery {
|
|
|
2927
3109
|
...this.state,
|
|
2928
3110
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2929
3111
|
},
|
|
2930
|
-
this.getWebSocketTransport
|
|
3112
|
+
this.getWebSocketTransport,
|
|
3113
|
+
this.store
|
|
2931
3114
|
);
|
|
2932
3115
|
}
|
|
2933
3116
|
/**
|
|
@@ -2946,7 +3129,7 @@ var TableQuery = class _TableQuery {
|
|
|
2946
3129
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2947
3130
|
...this.state,
|
|
2948
3131
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2949
|
-
}, this.getWebSocketTransport);
|
|
3132
|
+
}, this.getWebSocketTransport, this.store);
|
|
2950
3133
|
}
|
|
2951
3134
|
/**
|
|
2952
3135
|
* Sets the primary sort column for the query.
|
|
@@ -2971,7 +3154,7 @@ var TableQuery = class _TableQuery {
|
|
|
2971
3154
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2972
3155
|
...this.state,
|
|
2973
3156
|
orderByClauses: [orderByClause]
|
|
2974
|
-
}, this.getWebSocketTransport);
|
|
3157
|
+
}, this.getWebSocketTransport, this.store);
|
|
2975
3158
|
}
|
|
2976
3159
|
/**
|
|
2977
3160
|
* Sets the primary sort column to descending order.
|
|
@@ -3017,7 +3200,7 @@ var TableQuery = class _TableQuery {
|
|
|
3017
3200
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3018
3201
|
...this.state,
|
|
3019
3202
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
3020
|
-
}, this.getWebSocketTransport);
|
|
3203
|
+
}, this.getWebSocketTransport, this.store);
|
|
3021
3204
|
}
|
|
3022
3205
|
/**
|
|
3023
3206
|
* Sets the maximum number of rows to return.
|
|
@@ -3034,7 +3217,7 @@ var TableQuery = class _TableQuery {
|
|
|
3034
3217
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3035
3218
|
...this.state,
|
|
3036
3219
|
limitValue: count
|
|
3037
|
-
}, this.getWebSocketTransport);
|
|
3220
|
+
}, this.getWebSocketTransport, this.store);
|
|
3038
3221
|
}
|
|
3039
3222
|
/**
|
|
3040
3223
|
* Sets the number of rows to skip.
|
|
@@ -3051,7 +3234,7 @@ var TableQuery = class _TableQuery {
|
|
|
3051
3234
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3052
3235
|
...this.state,
|
|
3053
3236
|
offsetValue: count
|
|
3054
|
-
}, this.getWebSocketTransport);
|
|
3237
|
+
}, this.getWebSocketTransport, this.store);
|
|
3055
3238
|
}
|
|
3056
3239
|
/**
|
|
3057
3240
|
* Requests cross-partition access for this query.
|
|
@@ -3066,10 +3249,21 @@ var TableQuery = class _TableQuery {
|
|
|
3066
3249
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3067
3250
|
...this.state,
|
|
3068
3251
|
crossPartitionAccess: true
|
|
3069
|
-
}, this.getWebSocketTransport);
|
|
3252
|
+
}, this.getWebSocketTransport, this.store);
|
|
3253
|
+
}
|
|
3254
|
+
/**
|
|
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 });
|
|
3070
3264
|
}
|
|
3071
3265
|
/**
|
|
3072
|
-
*
|
|
3266
|
+
* Selects specific columns to return.
|
|
3073
3267
|
* If not called, all columns are returned.
|
|
3074
3268
|
*
|
|
3075
3269
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -3091,7 +3285,7 @@ var TableQuery = class _TableQuery {
|
|
|
3091
3285
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3092
3286
|
...this.state,
|
|
3093
3287
|
selectColumns: columns.length > 0 ? columns : null
|
|
3094
|
-
}, this.getWebSocketTransport);
|
|
3288
|
+
}, this.getWebSocketTransport, this.store);
|
|
3095
3289
|
}
|
|
3096
3290
|
/**
|
|
3097
3291
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -3121,7 +3315,7 @@ var TableQuery = class _TableQuery {
|
|
|
3121
3315
|
...this.state,
|
|
3122
3316
|
selectColumns: columns,
|
|
3123
3317
|
isDistinct: true
|
|
3124
|
-
}, this.getWebSocketTransport);
|
|
3318
|
+
}, this.getWebSocketTransport, this.store);
|
|
3125
3319
|
}
|
|
3126
3320
|
/**
|
|
3127
3321
|
* Adds server-side computed columns to the query result.
|
|
@@ -3150,7 +3344,7 @@ var TableQuery = class _TableQuery {
|
|
|
3150
3344
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3151
3345
|
...this.state,
|
|
3152
3346
|
selectExprs: projections
|
|
3153
|
-
}, this.getWebSocketTransport);
|
|
3347
|
+
}, this.getWebSocketTransport, this.store);
|
|
3154
3348
|
}
|
|
3155
3349
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
3156
3350
|
return this.addJoinClause(
|
|
@@ -3208,7 +3402,8 @@ var TableQuery = class _TableQuery {
|
|
|
3208
3402
|
}
|
|
3209
3403
|
]
|
|
3210
3404
|
},
|
|
3211
|
-
this.getWebSocketTransport
|
|
3405
|
+
this.getWebSocketTransport,
|
|
3406
|
+
this.store
|
|
3212
3407
|
);
|
|
3213
3408
|
}
|
|
3214
3409
|
/**
|
|
@@ -3244,7 +3439,8 @@ var TableQuery = class _TableQuery {
|
|
|
3244
3439
|
...this.state,
|
|
3245
3440
|
groupByColumns: [...columns]
|
|
3246
3441
|
},
|
|
3247
|
-
this.getWebSocketTransport
|
|
3442
|
+
this.getWebSocketTransport,
|
|
3443
|
+
this.store
|
|
3248
3444
|
);
|
|
3249
3445
|
}
|
|
3250
3446
|
/**
|
|
@@ -3278,8 +3474,11 @@ var TableQuery = class _TableQuery {
|
|
|
3278
3474
|
onSnapshot: options.onSnapshot,
|
|
3279
3475
|
onChange: options.onChange,
|
|
3280
3476
|
onError: options.onError,
|
|
3281
|
-
conflate: options.conflate
|
|
3282
|
-
|
|
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);
|
|
3283
3482
|
subscription.start();
|
|
3284
3483
|
return subscription;
|
|
3285
3484
|
}
|
|
@@ -3394,7 +3593,8 @@ var TableQuery = class _TableQuery {
|
|
|
3394
3593
|
...this.state,
|
|
3395
3594
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3396
3595
|
},
|
|
3397
|
-
this.getWebSocketTransport
|
|
3596
|
+
this.getWebSocketTransport,
|
|
3597
|
+
this.store
|
|
3398
3598
|
);
|
|
3399
3599
|
}
|
|
3400
3600
|
addAggregate(op, column) {
|
|
@@ -3415,7 +3615,8 @@ var TableQuery = class _TableQuery {
|
|
|
3415
3615
|
}
|
|
3416
3616
|
]
|
|
3417
3617
|
},
|
|
3418
|
-
this.getWebSocketTransport
|
|
3618
|
+
this.getWebSocketTransport,
|
|
3619
|
+
this.store
|
|
3419
3620
|
);
|
|
3420
3621
|
}
|
|
3421
3622
|
requireWebSocketTransport() {
|
|
@@ -3445,17 +3646,23 @@ var TableQuery = class _TableQuery {
|
|
|
3445
3646
|
* ```
|
|
3446
3647
|
*/
|
|
3447
3648
|
async execute() {
|
|
3649
|
+
if (this.state.atLeast) {
|
|
3650
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3651
|
+
}
|
|
3448
3652
|
const request = this.buildRequest();
|
|
3449
3653
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3450
3654
|
const response = await this.transport.post(path4, request);
|
|
3451
3655
|
const rows = columnarToRows(response);
|
|
3452
3656
|
const stats = response.stats;
|
|
3453
|
-
return { rows, stats };
|
|
3657
|
+
return { rows, stats, token: response.token };
|
|
3454
3658
|
}
|
|
3455
3659
|
/**
|
|
3456
3660
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3457
3661
|
*/
|
|
3458
3662
|
async toColumnar() {
|
|
3663
|
+
if (this.state.atLeast) {
|
|
3664
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3665
|
+
}
|
|
3459
3666
|
const request = this.buildRequest();
|
|
3460
3667
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3461
3668
|
return this.transport.post(path4, request);
|
|
@@ -3485,8 +3692,12 @@ var TableQuery = class _TableQuery {
|
|
|
3485
3692
|
limitValue: 0,
|
|
3486
3693
|
selectColumns: []
|
|
3487
3694
|
},
|
|
3488
|
-
this.getWebSocketTransport
|
|
3695
|
+
this.getWebSocketTransport,
|
|
3696
|
+
this.store
|
|
3489
3697
|
);
|
|
3698
|
+
if (this.state.atLeast) {
|
|
3699
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3700
|
+
}
|
|
3490
3701
|
const request = countQuery.buildRequest();
|
|
3491
3702
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3492
3703
|
const response = await this.transport.post(path4, request);
|
|
@@ -3533,7 +3744,8 @@ var TableQuery = class _TableQuery {
|
|
|
3533
3744
|
const response = await this.transport.post(path4, body);
|
|
3534
3745
|
const result = {
|
|
3535
3746
|
rowsInserted: response.rowsInserted,
|
|
3536
|
-
executionMs: response.executionMs
|
|
3747
|
+
executionMs: response.executionMs,
|
|
3748
|
+
token: response.token
|
|
3537
3749
|
};
|
|
3538
3750
|
if (response.generatedValues !== void 0) {
|
|
3539
3751
|
result.generatedValues = response.generatedValues;
|
|
@@ -3583,7 +3795,8 @@ var TableQuery = class _TableQuery {
|
|
|
3583
3795
|
const response = await this.transport.post(path4, body);
|
|
3584
3796
|
const result = {
|
|
3585
3797
|
rowsInserted: response.rowsInserted,
|
|
3586
|
-
executionMs: response.executionMs
|
|
3798
|
+
executionMs: response.executionMs,
|
|
3799
|
+
token: response.token
|
|
3587
3800
|
};
|
|
3588
3801
|
if (response.generatedValues !== void 0) {
|
|
3589
3802
|
result.generatedValues = response.generatedValues;
|
|
@@ -3635,6 +3848,7 @@ var TableQuery = class _TableQuery {
|
|
|
3635
3848
|
return {
|
|
3636
3849
|
rowsAffected: response.rowsUpdated,
|
|
3637
3850
|
executionMs: response.executionMs,
|
|
3851
|
+
token: response.token,
|
|
3638
3852
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3639
3853
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3640
3854
|
};
|
|
@@ -3685,6 +3899,7 @@ var TableQuery = class _TableQuery {
|
|
|
3685
3899
|
rowsAffected: response.rowsDeleted,
|
|
3686
3900
|
executionMs: response.executionMs,
|
|
3687
3901
|
hasMore: response.hasMore,
|
|
3902
|
+
token: response.token,
|
|
3688
3903
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3689
3904
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3690
3905
|
};
|
|
@@ -3704,7 +3919,8 @@ var TableQuery = class _TableQuery {
|
|
|
3704
3919
|
return {
|
|
3705
3920
|
rowsAffected: response.rowsDeleted,
|
|
3706
3921
|
executionMs: response.executionMs,
|
|
3707
|
-
hasMore: false
|
|
3922
|
+
hasMore: false,
|
|
3923
|
+
token: response.token
|
|
3708
3924
|
};
|
|
3709
3925
|
}
|
|
3710
3926
|
/**
|
|
@@ -3717,7 +3933,14 @@ var TableQuery = class _TableQuery {
|
|
|
3717
3933
|
throw new Error("batch() requires a non-empty operations array");
|
|
3718
3934
|
}
|
|
3719
3935
|
const wireOperations = operations.map((op, index) => {
|
|
3720
|
-
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
|
+
);
|
|
3721
3944
|
const scoped = op.where(base);
|
|
3722
3945
|
const where = scoped.buildWhereClause();
|
|
3723
3946
|
if (!where) {
|
|
@@ -5054,12 +5277,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
5054
5277
|
continue;
|
|
5055
5278
|
}
|
|
5056
5279
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
5057
|
-
const
|
|
5280
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
5058
5281
|
sink({
|
|
5059
5282
|
code: warning.code,
|
|
5060
|
-
|
|
5283
|
+
name: warning.name,
|
|
5061
5284
|
sunsetAt: warning.sunsetAt,
|
|
5062
|
-
message: `${warning.code}:${
|
|
5285
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
5063
5286
|
});
|
|
5064
5287
|
}
|
|
5065
5288
|
}
|
|
@@ -5072,21 +5295,31 @@ function emptyStats() {
|
|
|
5072
5295
|
};
|
|
5073
5296
|
}
|
|
5074
5297
|
var NamedQueriesApi = class {
|
|
5075
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5298
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
5076
5299
|
this.transport = transport;
|
|
5077
5300
|
this.database = database;
|
|
5078
5301
|
this.onWarning = onWarning;
|
|
5079
5302
|
this.getStreamingTransport = getStreamingTransport;
|
|
5303
|
+
this.store = store;
|
|
5080
5304
|
}
|
|
5081
|
-
async execute(
|
|
5082
|
-
if (typeof
|
|
5083
|
-
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");
|
|
5084
5308
|
}
|
|
5085
5309
|
const prefix = databasePath2(this.database);
|
|
5086
|
-
const path4 = `${prefix}/named-queries/${encodeURIComponent(
|
|
5310
|
+
const path4 = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
5311
|
+
const body = {
|
|
5312
|
+
args: args ?? {}
|
|
5313
|
+
};
|
|
5314
|
+
if (options?.orderByIndex !== void 0) {
|
|
5315
|
+
body.orderByIndex = options.orderByIndex;
|
|
5316
|
+
}
|
|
5317
|
+
if (options?.atLeast !== void 0) {
|
|
5318
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5319
|
+
}
|
|
5087
5320
|
const response = await this.transport.post(
|
|
5088
5321
|
path4,
|
|
5089
|
-
|
|
5322
|
+
body,
|
|
5090
5323
|
{ signal: options?.signal }
|
|
5091
5324
|
);
|
|
5092
5325
|
const rows = columnarToRows(response);
|
|
@@ -5094,7 +5327,9 @@ var NamedQueriesApi = class {
|
|
|
5094
5327
|
return {
|
|
5095
5328
|
rows,
|
|
5096
5329
|
stats: response.stats,
|
|
5097
|
-
warnings: response.warnings
|
|
5330
|
+
warnings: response.warnings,
|
|
5331
|
+
totalMatches: response.totalMatches,
|
|
5332
|
+
token: response.token
|
|
5098
5333
|
};
|
|
5099
5334
|
}
|
|
5100
5335
|
async batch(items, options) {
|
|
@@ -5112,6 +5347,9 @@ var NamedQueriesApi = class {
|
|
|
5112
5347
|
400
|
|
5113
5348
|
);
|
|
5114
5349
|
}
|
|
5350
|
+
if (options?.atLeast !== void 0) {
|
|
5351
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5352
|
+
}
|
|
5115
5353
|
const prefix = databasePath2(this.database);
|
|
5116
5354
|
const path4 = `${prefix}/named-queries/batch?format=columnar`;
|
|
5117
5355
|
const envelope = await this.transport.post(
|
|
@@ -5133,33 +5371,42 @@ var NamedQueriesApi = class {
|
|
|
5133
5371
|
data: slot.data ?? [],
|
|
5134
5372
|
rowCount: slot.rowCount ?? 0,
|
|
5135
5373
|
stats: slot.stats ?? emptyStats(),
|
|
5136
|
-
warnings: slot.warnings
|
|
5374
|
+
warnings: slot.warnings,
|
|
5375
|
+
totalMatches: slot.totalMatches,
|
|
5376
|
+
token: slot.token
|
|
5137
5377
|
};
|
|
5138
5378
|
const result = {
|
|
5139
5379
|
rows: columnarToRows(columnar),
|
|
5140
5380
|
stats: columnar.stats,
|
|
5141
|
-
warnings: slot.warnings
|
|
5381
|
+
warnings: slot.warnings,
|
|
5382
|
+
totalMatches: slot.totalMatches,
|
|
5383
|
+
token: slot.token
|
|
5142
5384
|
};
|
|
5143
5385
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
5144
5386
|
return { isError: false, result };
|
|
5145
5387
|
});
|
|
5146
5388
|
}
|
|
5147
|
-
subscribe(
|
|
5148
|
-
if (typeof
|
|
5149
|
-
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");
|
|
5150
5392
|
}
|
|
5151
5393
|
const subscription = new TableSubscription(
|
|
5152
5394
|
this.getStreamingTransport(),
|
|
5153
|
-
{ kind: "named",
|
|
5395
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
5154
5396
|
{
|
|
5155
5397
|
onSnapshot: options.onSnapshot,
|
|
5156
5398
|
onChange: options.onChange,
|
|
5157
5399
|
onError: options.onError,
|
|
5158
|
-
conflate: options.conflate
|
|
5400
|
+
conflate: options.conflate,
|
|
5401
|
+
atLeast: options.atLeast,
|
|
5402
|
+
waitMs: options.waitMs,
|
|
5403
|
+
onExceeded: options.onExceeded
|
|
5159
5404
|
},
|
|
5160
5405
|
(warnings) => {
|
|
5161
5406
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
5162
|
-
}
|
|
5407
|
+
},
|
|
5408
|
+
this.store,
|
|
5409
|
+
this.database
|
|
5163
5410
|
);
|
|
5164
5411
|
subscription.start();
|
|
5165
5412
|
return subscription;
|
|
@@ -5171,12 +5418,12 @@ var NamedMutationsApi = class {
|
|
|
5171
5418
|
this.database = database;
|
|
5172
5419
|
this.onWarning = onWarning;
|
|
5173
5420
|
}
|
|
5174
|
-
async execute(
|
|
5175
|
-
if (typeof
|
|
5176
|
-
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");
|
|
5177
5424
|
}
|
|
5178
5425
|
const prefix = databasePath2(this.database);
|
|
5179
|
-
const path4 = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5426
|
+
const path4 = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
5180
5427
|
const wire = await this.transport.post(path4, {
|
|
5181
5428
|
args: args ?? {}
|
|
5182
5429
|
});
|
|
@@ -5237,6 +5484,7 @@ var WebSocketTransport = class {
|
|
|
5237
5484
|
// Serialized-send queue: each send appends to this tail.
|
|
5238
5485
|
this._sendTail = Promise.resolve();
|
|
5239
5486
|
this._lastVersion = 0;
|
|
5487
|
+
this._lastToken = null;
|
|
5240
5488
|
this._reconnectAttempt = 0;
|
|
5241
5489
|
this._disposed = false;
|
|
5242
5490
|
this._missedPings = 0;
|
|
@@ -5254,6 +5502,7 @@ var WebSocketTransport = class {
|
|
|
5254
5502
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
5255
5503
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
5256
5504
|
this._enableCompression = options.enableCompression ?? true;
|
|
5505
|
+
this._store = options.consistencyTokenStore;
|
|
5257
5506
|
this._wireMode = options.wireMode ?? "json";
|
|
5258
5507
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
5259
5508
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -5262,10 +5511,14 @@ var WebSocketTransport = class {
|
|
|
5262
5511
|
});
|
|
5263
5512
|
}
|
|
5264
5513
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
5265
|
-
/** Latest
|
|
5514
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
5266
5515
|
get lastVersion() {
|
|
5267
5516
|
return this._lastVersion;
|
|
5268
5517
|
}
|
|
5518
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5519
|
+
get lastToken() {
|
|
5520
|
+
return this._lastToken;
|
|
5521
|
+
}
|
|
5269
5522
|
/**
|
|
5270
5523
|
* Registers a handler for incoming server messages with the given channel id.
|
|
5271
5524
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5453,6 +5706,10 @@ var WebSocketTransport = class {
|
|
|
5453
5706
|
}
|
|
5454
5707
|
case "heartbeat":
|
|
5455
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
|
+
}
|
|
5456
5713
|
break;
|
|
5457
5714
|
case "pong":
|
|
5458
5715
|
this._missedPings = 0;
|
|
@@ -5618,16 +5875,21 @@ var LongPollTransport = class {
|
|
|
5618
5875
|
this._connected = false;
|
|
5619
5876
|
this._pollTask = null;
|
|
5620
5877
|
this._lastVersion = 0;
|
|
5878
|
+
this._lastToken = null;
|
|
5621
5879
|
this._serverUrl = serverUrl;
|
|
5622
5880
|
this._database = database;
|
|
5623
5881
|
this._authHandler = options.authHandler;
|
|
5624
5882
|
this._onReconnected = options.onReconnected;
|
|
5625
5883
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5626
5884
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5885
|
+
this._store = options.consistencyTokenStore;
|
|
5627
5886
|
}
|
|
5628
5887
|
get lastVersion() {
|
|
5629
5888
|
return this._lastVersion;
|
|
5630
5889
|
}
|
|
5890
|
+
get lastToken() {
|
|
5891
|
+
return this._lastToken;
|
|
5892
|
+
}
|
|
5631
5893
|
registerHandler(id, handler) {
|
|
5632
5894
|
this._handlers.set(id, handler);
|
|
5633
5895
|
}
|
|
@@ -5750,6 +6012,10 @@ var LongPollTransport = class {
|
|
|
5750
6012
|
for (const msg of payload.messages) {
|
|
5751
6013
|
if (msg.type === "heartbeat") {
|
|
5752
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
|
+
}
|
|
5753
6019
|
}
|
|
5754
6020
|
const id = "id" in msg ? msg.id : void 0;
|
|
5755
6021
|
if (id !== void 0 && id !== null) {
|
|
@@ -5829,6 +6095,9 @@ var FallbackStreamingTransport = class {
|
|
|
5829
6095
|
get lastVersion() {
|
|
5830
6096
|
return this._active.lastVersion;
|
|
5831
6097
|
}
|
|
6098
|
+
get lastToken() {
|
|
6099
|
+
return this._active.lastToken;
|
|
6100
|
+
}
|
|
5832
6101
|
registerHandler(id, handler) {
|
|
5833
6102
|
this._handlers.set(id, handler);
|
|
5834
6103
|
this._active.registerHandler(id, handler);
|
|
@@ -5908,6 +6177,7 @@ var AoudaClient = class {
|
|
|
5908
6177
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5909
6178
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5910
6179
|
this.database = options.database.trim();
|
|
6180
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5911
6181
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5912
6182
|
throw new Error("timeout must be a finite positive number");
|
|
5913
6183
|
}
|
|
@@ -5942,7 +6212,9 @@ var AoudaClient = class {
|
|
|
5942
6212
|
}
|
|
5943
6213
|
const httpTransport = new HttpTransport({
|
|
5944
6214
|
baseUrl: this.baseUrl,
|
|
5945
|
-
timeout: this.timeout
|
|
6215
|
+
timeout: this.timeout,
|
|
6216
|
+
database: this.database,
|
|
6217
|
+
consistencyTokenStore: this._store
|
|
5946
6218
|
});
|
|
5947
6219
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5948
6220
|
if (activeAuth) {
|
|
@@ -6002,7 +6274,8 @@ var AoudaClient = class {
|
|
|
6002
6274
|
this.transport,
|
|
6003
6275
|
this.database,
|
|
6004
6276
|
onNamedArtifactWarning,
|
|
6005
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6277
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6278
|
+
this._store
|
|
6006
6279
|
);
|
|
6007
6280
|
this._namedMutations = new NamedMutationsApi(
|
|
6008
6281
|
this.transport,
|
|
@@ -6101,7 +6374,8 @@ var AoudaClient = class {
|
|
|
6101
6374
|
name,
|
|
6102
6375
|
this.database,
|
|
6103
6376
|
void 0,
|
|
6104
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6377
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6378
|
+
this._store
|
|
6105
6379
|
);
|
|
6106
6380
|
}
|
|
6107
6381
|
/**
|
|
@@ -6153,13 +6427,26 @@ var AoudaClient = class {
|
|
|
6153
6427
|
return this._materializedQueries;
|
|
6154
6428
|
}
|
|
6155
6429
|
/**
|
|
6156
|
-
*
|
|
6430
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
6157
6431
|
*/
|
|
6158
6432
|
get namedQueries() {
|
|
6159
6433
|
return this._namedQueries;
|
|
6160
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
|
+
}
|
|
6161
6448
|
/**
|
|
6162
|
-
*
|
|
6449
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
6163
6450
|
*/
|
|
6164
6451
|
get namedMutations() {
|
|
6165
6452
|
return this._namedMutations;
|
|
@@ -6286,13 +6573,15 @@ var AoudaClient = class {
|
|
|
6286
6573
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
6287
6574
|
authHandler: this._authHandler,
|
|
6288
6575
|
enableCompression: this._streamingEnableCompression,
|
|
6289
|
-
wireMode: this._streamingWireMode
|
|
6576
|
+
wireMode: this._streamingWireMode,
|
|
6577
|
+
consistencyTokenStore: this._store
|
|
6290
6578
|
});
|
|
6291
6579
|
if (this._streamingEnableLongPollFallback) {
|
|
6292
6580
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
6293
6581
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
6294
6582
|
authHandler: this._authHandler,
|
|
6295
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6583
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6584
|
+
consistencyTokenStore: this._store
|
|
6296
6585
|
});
|
|
6297
6586
|
});
|
|
6298
6587
|
} else {
|
|
@@ -6317,7 +6606,7 @@ Usage:
|
|
|
6317
6606
|
npx @aouda/client schema <command> [options]
|
|
6318
6607
|
|
|
6319
6608
|
Commands:
|
|
6320
|
-
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)
|
|
6321
6610
|
schema Schema management (diff, apply, export, validate, history, seed)
|
|
6322
6611
|
diff Show migration plan (desired vs current)
|
|
6323
6612
|
apply Apply schema (use --allow-destructive for drops; --dry-run to preview)
|