@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.cjs
CHANGED
|
@@ -421,7 +421,7 @@ var import_node_url = require("url");
|
|
|
421
421
|
// package.json
|
|
422
422
|
var package_default = {
|
|
423
423
|
name: "@aouda/client",
|
|
424
|
-
version: "0.1.
|
|
424
|
+
version: "0.1.15",
|
|
425
425
|
description: "Official TypeScript/JavaScript client library for Aouda",
|
|
426
426
|
type: "module",
|
|
427
427
|
main: "./dist/index.cjs",
|
|
@@ -536,43 +536,44 @@ var AoudaResponseError = class extends AoudaError {
|
|
|
536
536
|
}
|
|
537
537
|
};
|
|
538
538
|
var AoudaApiError = class extends AoudaError {
|
|
539
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
539
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
540
540
|
super(message);
|
|
541
541
|
this.code = code;
|
|
542
542
|
this.statusCode = statusCode;
|
|
543
543
|
this.details = details;
|
|
544
544
|
this.requestId = requestId;
|
|
545
545
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
546
|
+
this.token = token;
|
|
546
547
|
this.name = "AoudaApiError";
|
|
547
548
|
}
|
|
548
549
|
};
|
|
549
550
|
var AoudaNotFoundError = class extends AoudaApiError {
|
|
550
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
551
|
-
super(message, code, statusCode, details, requestId);
|
|
551
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
552
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
552
553
|
this.name = "AoudaNotFoundError";
|
|
553
554
|
}
|
|
554
555
|
};
|
|
555
556
|
var AoudaConflictError = class extends AoudaApiError {
|
|
556
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
557
|
-
super(message, code, statusCode, details, requestId);
|
|
557
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
558
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
558
559
|
this.name = "AoudaConflictError";
|
|
559
560
|
}
|
|
560
561
|
};
|
|
561
562
|
var AoudaValidationError = class extends AoudaApiError {
|
|
562
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
563
|
-
super(message, code, statusCode, details, requestId);
|
|
563
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
564
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
564
565
|
this.name = "AoudaValidationError";
|
|
565
566
|
}
|
|
566
567
|
};
|
|
567
568
|
var AoudaServerError = class extends AoudaApiError {
|
|
568
|
-
constructor(message, code, statusCode, details, requestId, retryAfterSeconds) {
|
|
569
|
-
super(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
569
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
570
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
570
571
|
this.name = "AoudaServerError";
|
|
571
572
|
}
|
|
572
573
|
};
|
|
573
574
|
var AoudaAuthenticationError = class extends AoudaApiError {
|
|
574
|
-
constructor(message, code, statusCode, details, requestId) {
|
|
575
|
-
super(message, code, statusCode, details, requestId);
|
|
575
|
+
constructor(message, code, statusCode, details, requestId, retryAfterSeconds, token) {
|
|
576
|
+
super(message, code, statusCode, details, requestId, retryAfterSeconds, token);
|
|
576
577
|
this.name = "AoudaAuthenticationError";
|
|
577
578
|
}
|
|
578
579
|
};
|
|
@@ -1368,7 +1369,7 @@ function buildHandle(jobId, commitResp, wasResumed, transport, database, signal)
|
|
|
1368
1369
|
rowsDurablyCommitted: commitResp.rowsLoaded,
|
|
1369
1370
|
segmentsCreated: commitResp.segmentsCreated,
|
|
1370
1371
|
committedAtUtc: commitResp.committedAtUtc,
|
|
1371
|
-
|
|
1372
|
+
token: commitResp.token,
|
|
1372
1373
|
writeConcernSatisfied: commitResp.writeConcernAchieved ?? "acknowledged",
|
|
1373
1374
|
writeConcernTimedOut: commitResp.writeConcernTimedOut,
|
|
1374
1375
|
wasResumed,
|
|
@@ -1494,6 +1495,7 @@ var PROTOCOL_VERSION_HEADER = "X-Aouda-Protocol-Version";
|
|
|
1494
1495
|
var PROTOCOL_VERSION = "1";
|
|
1495
1496
|
var CONTENT_TYPE_JSON2 = "application/json";
|
|
1496
1497
|
var REQUEST_ID_HEADER2 = "X-Request-Id";
|
|
1498
|
+
var TOKEN_HEADER = "X-Aouda-Token";
|
|
1497
1499
|
var ERROR_CODE_MAP = {
|
|
1498
1500
|
TABLE_NOT_FOUND: AoudaNotFoundError,
|
|
1499
1501
|
COLUMN_NOT_FOUND: AoudaNotFoundError,
|
|
@@ -1533,7 +1535,12 @@ var ERROR_CODE_MAP = {
|
|
|
1533
1535
|
AUTH_IDENTITY_INVALID: AoudaValidationError,
|
|
1534
1536
|
AUTH_IDENTITY_NOT_FOUND: AoudaValidationError,
|
|
1535
1537
|
BULK_LOAD_TRANSFORM_INTENT_REQUIRED: AoudaValidationError,
|
|
1536
|
-
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError
|
|
1538
|
+
BULK_LOAD_TRANSFORM_INTENT_CONFLICT: AoudaValidationError,
|
|
1539
|
+
TOKEN_MALFORMED: AoudaValidationError,
|
|
1540
|
+
TOKEN_FOREIGN_DATABASE: AoudaValidationError,
|
|
1541
|
+
TOKEN_EPOCH_SUPERSEDED: AoudaConflictError,
|
|
1542
|
+
TOKEN_UNSATISFIED: AoudaConflictError,
|
|
1543
|
+
TOKEN_FETCH_PRIMARY: AoudaApiError
|
|
1537
1544
|
};
|
|
1538
1545
|
function createComposedAbortController(...signals) {
|
|
1539
1546
|
const controller = new AbortController();
|
|
@@ -1570,7 +1577,7 @@ function createApiError(statusCode, statusText, body, retryAfterHeader) {
|
|
|
1570
1577
|
const requestId = body.requestId;
|
|
1571
1578
|
const retryAfterSeconds = parseRetryAfterSeconds(retryAfterHeader ?? null);
|
|
1572
1579
|
const Ctor = ERROR_CODE_MAP[code] ?? AoudaApiError;
|
|
1573
|
-
return new Ctor(message, code, statusCode, details, requestId, retryAfterSeconds);
|
|
1580
|
+
return new Ctor(message, code, statusCode, details, requestId, retryAfterSeconds, body.token);
|
|
1574
1581
|
}
|
|
1575
1582
|
var HttpTransport = class {
|
|
1576
1583
|
constructor(options) {
|
|
@@ -1582,6 +1589,29 @@ var HttpTransport = class {
|
|
|
1582
1589
|
...options.defaultHeaders
|
|
1583
1590
|
};
|
|
1584
1591
|
this.abortController = new AbortController();
|
|
1592
|
+
this.database = options.database;
|
|
1593
|
+
this.store = options.consistencyTokenStore;
|
|
1594
|
+
}
|
|
1595
|
+
presentTokenHeaders(path4, headers) {
|
|
1596
|
+
if (this.store == null || this.database == null || isAuthPath(path4)) {
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
const token = this.store.get(this.database);
|
|
1600
|
+
if (token != null && token.length > 0) {
|
|
1601
|
+
headers[TOKEN_HEADER] = token;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
observeResponse(_path, response, bodyText, errorCode) {
|
|
1605
|
+
if (this.store == null || this.database == null) {
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
if (errorCode === "TOKEN_MALFORMED" || errorCode === "TOKEN_FOREIGN_DATABASE") {
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
const header = response.headers.get(TOKEN_HEADER);
|
|
1612
|
+
const bodyToken = readBodyToken(bodyText);
|
|
1613
|
+
const token = header != null && header.trim().length > 0 ? header : bodyToken;
|
|
1614
|
+
this.store.observe(this.database, token);
|
|
1585
1615
|
}
|
|
1586
1616
|
/**
|
|
1587
1617
|
* Abort all in-flight and future requests (e.g. on client disconnect).
|
|
@@ -1619,6 +1649,7 @@ var HttpTransport = class {
|
|
|
1619
1649
|
...this.defaultHeaders,
|
|
1620
1650
|
...config.headers
|
|
1621
1651
|
};
|
|
1652
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1622
1653
|
if (config.body !== void 0 && config.body !== null) {
|
|
1623
1654
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1624
1655
|
}
|
|
@@ -1638,6 +1669,7 @@ var HttpTransport = class {
|
|
|
1638
1669
|
const text = await response.text();
|
|
1639
1670
|
if (config.allowStatuses?.includes(response.status) && text) {
|
|
1640
1671
|
try {
|
|
1672
|
+
this.observeResponse(config.path, response, text);
|
|
1641
1673
|
return JSON.parse(text);
|
|
1642
1674
|
} catch {
|
|
1643
1675
|
}
|
|
@@ -1651,15 +1683,19 @@ var HttpTransport = class {
|
|
|
1651
1683
|
}
|
|
1652
1684
|
if (response.status === 401) {
|
|
1653
1685
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1686
|
+
this.observeResponse(config.path, response, text, code);
|
|
1654
1687
|
throw new AoudaAuthenticationError(
|
|
1655
1688
|
errorBody?.error ?? "Unauthorized",
|
|
1656
1689
|
code,
|
|
1657
1690
|
401,
|
|
1658
1691
|
errorBody?.details,
|
|
1659
|
-
errorBody?.requestId
|
|
1692
|
+
errorBody?.requestId,
|
|
1693
|
+
void 0,
|
|
1694
|
+
errorBody?.token
|
|
1660
1695
|
);
|
|
1661
1696
|
}
|
|
1662
1697
|
if (errorBody?.code != null) {
|
|
1698
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1663
1699
|
throw createApiError(
|
|
1664
1700
|
response.status,
|
|
1665
1701
|
response.statusText,
|
|
@@ -1667,6 +1703,7 @@ var HttpTransport = class {
|
|
|
1667
1703
|
response.headers.get("Retry-After")
|
|
1668
1704
|
);
|
|
1669
1705
|
}
|
|
1706
|
+
this.observeResponse(config.path, response, text);
|
|
1670
1707
|
throw new AoudaResponseError(
|
|
1671
1708
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1672
1709
|
response.status,
|
|
@@ -1674,6 +1711,7 @@ var HttpTransport = class {
|
|
|
1674
1711
|
);
|
|
1675
1712
|
}
|
|
1676
1713
|
const responseText = await response.text();
|
|
1714
|
+
this.observeResponse(config.path, response, responseText);
|
|
1677
1715
|
if (config.rawText) {
|
|
1678
1716
|
return responseText;
|
|
1679
1717
|
}
|
|
@@ -1734,6 +1772,7 @@ var HttpTransport = class {
|
|
|
1734
1772
|
...this.defaultHeaders,
|
|
1735
1773
|
...config.headers
|
|
1736
1774
|
};
|
|
1775
|
+
this.presentTokenHeaders(config.path, headers);
|
|
1737
1776
|
if (config.rawBodyStr === void 0 && config.body !== void 0 && config.body !== null) {
|
|
1738
1777
|
headers["Content-Type"] = CONTENT_TYPE_JSON2;
|
|
1739
1778
|
}
|
|
@@ -1750,6 +1789,7 @@ var HttpTransport = class {
|
|
|
1750
1789
|
try {
|
|
1751
1790
|
const response = await localNetworkFetch(url, init);
|
|
1752
1791
|
if (response.ok || config.allowStatuses?.includes(response.status)) {
|
|
1792
|
+
this.observeResponse(config.path, response, void 0);
|
|
1753
1793
|
return response;
|
|
1754
1794
|
}
|
|
1755
1795
|
const text = await response.text();
|
|
@@ -1762,15 +1802,19 @@ var HttpTransport = class {
|
|
|
1762
1802
|
}
|
|
1763
1803
|
if (response.status === 401) {
|
|
1764
1804
|
const code = errorBody?.code ?? "AUTH_TOKEN_MISSING";
|
|
1805
|
+
this.observeResponse(config.path, response, text, code);
|
|
1765
1806
|
throw new AoudaAuthenticationError(
|
|
1766
1807
|
errorBody?.error ?? "Unauthorized",
|
|
1767
1808
|
code,
|
|
1768
1809
|
401,
|
|
1769
1810
|
errorBody?.details,
|
|
1770
|
-
errorBody?.requestId
|
|
1811
|
+
errorBody?.requestId,
|
|
1812
|
+
void 0,
|
|
1813
|
+
errorBody?.token
|
|
1771
1814
|
);
|
|
1772
1815
|
}
|
|
1773
1816
|
if (errorBody?.code != null) {
|
|
1817
|
+
this.observeResponse(config.path, response, text, errorBody.code);
|
|
1774
1818
|
throw createApiError(
|
|
1775
1819
|
response.status,
|
|
1776
1820
|
response.statusText,
|
|
@@ -1778,6 +1822,7 @@ var HttpTransport = class {
|
|
|
1778
1822
|
response.headers.get("Retry-After")
|
|
1779
1823
|
);
|
|
1780
1824
|
}
|
|
1825
|
+
this.observeResponse(config.path, response, text);
|
|
1781
1826
|
throw new AoudaResponseError(
|
|
1782
1827
|
errorBody?.error ?? `${response.status} ${response.statusText}`,
|
|
1783
1828
|
response.status,
|
|
@@ -1932,6 +1977,47 @@ var HttpTransport = class {
|
|
|
1932
1977
|
});
|
|
1933
1978
|
}
|
|
1934
1979
|
};
|
|
1980
|
+
function isAuthPath(path4) {
|
|
1981
|
+
let p = path4;
|
|
1982
|
+
const q = p.indexOf("?");
|
|
1983
|
+
if (q >= 0) {
|
|
1984
|
+
p = p.slice(0, q);
|
|
1985
|
+
}
|
|
1986
|
+
if (/^https?:\/\//i.test(p)) {
|
|
1987
|
+
try {
|
|
1988
|
+
p = new URL(p).pathname;
|
|
1989
|
+
} catch {
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
const lower = p.toLowerCase();
|
|
1993
|
+
if (lower === "/api/auth" || lower.startsWith("/api/auth/")) {
|
|
1994
|
+
return true;
|
|
1995
|
+
}
|
|
1996
|
+
const prefix = "/api/databases/";
|
|
1997
|
+
if (!lower.startsWith(prefix)) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
2000
|
+
const rest = lower.slice(prefix.length);
|
|
2001
|
+
const slash = rest.indexOf("/");
|
|
2002
|
+
if (slash < 0) {
|
|
2003
|
+
return false;
|
|
2004
|
+
}
|
|
2005
|
+
const afterDb = rest.slice(slash + 1);
|
|
2006
|
+
return afterDb === "auth" || afterDb.startsWith("auth/");
|
|
2007
|
+
}
|
|
2008
|
+
function readBodyToken(bodyText) {
|
|
2009
|
+
if (bodyText == null || bodyText.trim().length === 0) {
|
|
2010
|
+
return void 0;
|
|
2011
|
+
}
|
|
2012
|
+
try {
|
|
2013
|
+
const parsed = JSON.parse(bodyText);
|
|
2014
|
+
if (parsed !== null && typeof parsed === "object" && "token" in parsed && typeof parsed.token === "string") {
|
|
2015
|
+
return parsed.token;
|
|
2016
|
+
}
|
|
2017
|
+
} catch {
|
|
2018
|
+
}
|
|
2019
|
+
return void 0;
|
|
2020
|
+
}
|
|
1935
2021
|
|
|
1936
2022
|
// src/resilience/retry.ts
|
|
1937
2023
|
var DEFAULT_MAX_RETRIES = 3;
|
|
@@ -2364,6 +2450,48 @@ function databasePath2(db) {
|
|
|
2364
2450
|
return `/api/databases/${encodeURIComponent(db)}`;
|
|
2365
2451
|
}
|
|
2366
2452
|
|
|
2453
|
+
// src/consistency-token-store.ts
|
|
2454
|
+
var MemoryConsistencyTokenStore = class {
|
|
2455
|
+
constructor() {
|
|
2456
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
2457
|
+
}
|
|
2458
|
+
get(database) {
|
|
2459
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2460
|
+
throw new Error("database must be a non-empty string");
|
|
2461
|
+
}
|
|
2462
|
+
return this.tokens.get(normalizeKey(database));
|
|
2463
|
+
}
|
|
2464
|
+
observe(database, token) {
|
|
2465
|
+
if (typeof database !== "string" || database.trim().length === 0) {
|
|
2466
|
+
throw new Error("database must be a non-empty string");
|
|
2467
|
+
}
|
|
2468
|
+
if (token == null || token.trim().length === 0) {
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
const key = normalizeKey(database);
|
|
2472
|
+
const stored = this.tokens.get(key);
|
|
2473
|
+
if (stored === void 0 || compareOrdinal(token, stored) > 0) {
|
|
2474
|
+
this.tokens.set(key, token);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
function compareOrdinal(left, right) {
|
|
2479
|
+
if (left === right) return 0;
|
|
2480
|
+
return left < right ? -1 : 1;
|
|
2481
|
+
}
|
|
2482
|
+
function maxToken(left, right) {
|
|
2483
|
+
if (left == null || left.length === 0) {
|
|
2484
|
+
return right == null || right.length === 0 ? void 0 : right;
|
|
2485
|
+
}
|
|
2486
|
+
if (right == null || right.length === 0) {
|
|
2487
|
+
return left;
|
|
2488
|
+
}
|
|
2489
|
+
return compareOrdinal(left, right) >= 0 ? left : right;
|
|
2490
|
+
}
|
|
2491
|
+
function normalizeKey(database) {
|
|
2492
|
+
return database.toLowerCase();
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2367
2495
|
// src/streaming/subscription.ts
|
|
2368
2496
|
var AsyncEventQueue = class {
|
|
2369
2497
|
constructor() {
|
|
@@ -2420,7 +2548,7 @@ var AsyncEventQueue = class {
|
|
|
2420
2548
|
}
|
|
2421
2549
|
};
|
|
2422
2550
|
var TableSubscription = class {
|
|
2423
|
-
constructor(transport, identity, options = {}, onWarnings) {
|
|
2551
|
+
constructor(transport, identity, options = {}, onWarnings, store, database) {
|
|
2424
2552
|
this._queue = new AsyncEventQueue();
|
|
2425
2553
|
this._active = true;
|
|
2426
2554
|
this._started = false;
|
|
@@ -2436,6 +2564,11 @@ var TableSubscription = class {
|
|
|
2436
2564
|
this._onError = options.onError;
|
|
2437
2565
|
this._onWarnings = onWarnings;
|
|
2438
2566
|
this._conflate = options.conflate;
|
|
2567
|
+
this._atLeast = options.atLeast;
|
|
2568
|
+
this._waitMs = options.waitMs;
|
|
2569
|
+
this._onExceeded = options.onExceeded;
|
|
2570
|
+
this._store = store;
|
|
2571
|
+
this._database = database;
|
|
2439
2572
|
this._reconnectHandlerKey = `${this.id}::reconnect`;
|
|
2440
2573
|
}
|
|
2441
2574
|
get lastVersion() {
|
|
@@ -2500,7 +2633,7 @@ var TableSubscription = class {
|
|
|
2500
2633
|
id: this.id
|
|
2501
2634
|
};
|
|
2502
2635
|
if (this._identity.kind === "named") {
|
|
2503
|
-
message.
|
|
2636
|
+
message.name = this._identity.name;
|
|
2504
2637
|
if (this._identity.args !== void 0) {
|
|
2505
2638
|
message.args = this._identity.args;
|
|
2506
2639
|
}
|
|
@@ -2519,8 +2652,30 @@ var TableSubscription = class {
|
|
|
2519
2652
|
if (this._conflate !== void 0) {
|
|
2520
2653
|
message.conflate = this._conflate;
|
|
2521
2654
|
}
|
|
2655
|
+
const pin = this._resolvePin();
|
|
2656
|
+
if (pin !== void 0) {
|
|
2657
|
+
message.at_least = pin;
|
|
2658
|
+
}
|
|
2659
|
+
if (this._waitMs !== void 0) {
|
|
2660
|
+
message.wait_ms = this._waitMs;
|
|
2661
|
+
}
|
|
2662
|
+
if (this._onExceeded !== void 0) {
|
|
2663
|
+
message.on_exceeded = this._onExceeded;
|
|
2664
|
+
}
|
|
2522
2665
|
await this._transport.send(message);
|
|
2523
2666
|
}
|
|
2667
|
+
_resolvePin() {
|
|
2668
|
+
if (this._atLeast !== void 0 && this._store != null && this._database != null) {
|
|
2669
|
+
this._store.observe(this._database, this._atLeast);
|
|
2670
|
+
}
|
|
2671
|
+
const stored = this._store != null && this._database != null ? this._store.get(this._database) : void 0;
|
|
2672
|
+
return maxToken(this._atLeast, stored);
|
|
2673
|
+
}
|
|
2674
|
+
_observeToken(token) {
|
|
2675
|
+
if (token !== void 0 && this._store != null && this._database != null) {
|
|
2676
|
+
this._store.observe(this._database, token);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2524
2679
|
_handleMessage(message) {
|
|
2525
2680
|
if (!this._active) {
|
|
2526
2681
|
return;
|
|
@@ -2547,6 +2702,7 @@ var TableSubscription = class {
|
|
|
2547
2702
|
}
|
|
2548
2703
|
_handleSnapshotPage(message) {
|
|
2549
2704
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2705
|
+
this._observeToken(message.token);
|
|
2550
2706
|
}
|
|
2551
2707
|
_handleSnapshotComplete(message) {
|
|
2552
2708
|
this._lastVersion = message.version;
|
|
@@ -2564,6 +2720,10 @@ var TableSubscription = class {
|
|
|
2564
2720
|
if (message.total_matches !== void 0) {
|
|
2565
2721
|
snapshot.totalMatches = message.total_matches;
|
|
2566
2722
|
}
|
|
2723
|
+
if (message.token !== void 0) {
|
|
2724
|
+
snapshot.token = message.token;
|
|
2725
|
+
this._observeToken(message.token);
|
|
2726
|
+
}
|
|
2567
2727
|
this._queue.push(snapshot);
|
|
2568
2728
|
}
|
|
2569
2729
|
async _handleGap(message) {
|
|
@@ -2589,6 +2749,10 @@ var TableSubscription = class {
|
|
|
2589
2749
|
if (message.values_skipped !== void 0) {
|
|
2590
2750
|
event.values_skipped = message.values_skipped;
|
|
2591
2751
|
}
|
|
2752
|
+
if (message.token !== void 0) {
|
|
2753
|
+
event.token = message.token;
|
|
2754
|
+
this._observeToken(message.token);
|
|
2755
|
+
}
|
|
2592
2756
|
this._onChange?.(event);
|
|
2593
2757
|
this._queue.push(event);
|
|
2594
2758
|
}
|
|
@@ -2933,11 +3097,12 @@ var TableQuery = class _TableQuery {
|
|
|
2933
3097
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2934
3098
|
* @internal Use `client.table()` to create queries.
|
|
2935
3099
|
*/
|
|
2936
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
3100
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2937
3101
|
this.transport = transport;
|
|
2938
3102
|
this.tableName = tableName;
|
|
2939
3103
|
this.database = database;
|
|
2940
3104
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
3105
|
+
this.store = store;
|
|
2941
3106
|
this.state = state ?? {
|
|
2942
3107
|
predicates: [],
|
|
2943
3108
|
groupClauses: [],
|
|
@@ -2953,6 +3118,16 @@ var TableQuery = class _TableQuery {
|
|
|
2953
3118
|
isDistinct: false
|
|
2954
3119
|
};
|
|
2955
3120
|
}
|
|
3121
|
+
withState(state) {
|
|
3122
|
+
return new _TableQuery(
|
|
3123
|
+
this.transport,
|
|
3124
|
+
this.tableName,
|
|
3125
|
+
this.database,
|
|
3126
|
+
state,
|
|
3127
|
+
this.getWebSocketTransport,
|
|
3128
|
+
this.store
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
2956
3131
|
where(column, operator, value) {
|
|
2957
3132
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2958
3133
|
return new _TableQuery(
|
|
@@ -2963,7 +3138,8 @@ var TableQuery = class _TableQuery {
|
|
|
2963
3138
|
...this.state,
|
|
2964
3139
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2965
3140
|
},
|
|
2966
|
-
this.getWebSocketTransport
|
|
3141
|
+
this.getWebSocketTransport,
|
|
3142
|
+
this.store
|
|
2967
3143
|
);
|
|
2968
3144
|
}
|
|
2969
3145
|
/**
|
|
@@ -2982,7 +3158,7 @@ var TableQuery = class _TableQuery {
|
|
|
2982
3158
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2983
3159
|
...this.state,
|
|
2984
3160
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2985
|
-
}, this.getWebSocketTransport);
|
|
3161
|
+
}, this.getWebSocketTransport, this.store);
|
|
2986
3162
|
}
|
|
2987
3163
|
/**
|
|
2988
3164
|
* Sets the primary sort column for the query.
|
|
@@ -3007,7 +3183,7 @@ var TableQuery = class _TableQuery {
|
|
|
3007
3183
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3008
3184
|
...this.state,
|
|
3009
3185
|
orderByClauses: [orderByClause]
|
|
3010
|
-
}, this.getWebSocketTransport);
|
|
3186
|
+
}, this.getWebSocketTransport, this.store);
|
|
3011
3187
|
}
|
|
3012
3188
|
/**
|
|
3013
3189
|
* Sets the primary sort column to descending order.
|
|
@@ -3053,7 +3229,7 @@ var TableQuery = class _TableQuery {
|
|
|
3053
3229
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3054
3230
|
...this.state,
|
|
3055
3231
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
3056
|
-
}, this.getWebSocketTransport);
|
|
3232
|
+
}, this.getWebSocketTransport, this.store);
|
|
3057
3233
|
}
|
|
3058
3234
|
/**
|
|
3059
3235
|
* Sets the maximum number of rows to return.
|
|
@@ -3070,7 +3246,7 @@ var TableQuery = class _TableQuery {
|
|
|
3070
3246
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3071
3247
|
...this.state,
|
|
3072
3248
|
limitValue: count
|
|
3073
|
-
}, this.getWebSocketTransport);
|
|
3249
|
+
}, this.getWebSocketTransport, this.store);
|
|
3074
3250
|
}
|
|
3075
3251
|
/**
|
|
3076
3252
|
* Sets the number of rows to skip.
|
|
@@ -3087,7 +3263,7 @@ var TableQuery = class _TableQuery {
|
|
|
3087
3263
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3088
3264
|
...this.state,
|
|
3089
3265
|
offsetValue: count
|
|
3090
|
-
}, this.getWebSocketTransport);
|
|
3266
|
+
}, this.getWebSocketTransport, this.store);
|
|
3091
3267
|
}
|
|
3092
3268
|
/**
|
|
3093
3269
|
* Requests cross-partition access for this query.
|
|
@@ -3102,10 +3278,21 @@ var TableQuery = class _TableQuery {
|
|
|
3102
3278
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3103
3279
|
...this.state,
|
|
3104
3280
|
crossPartitionAccess: true
|
|
3105
|
-
}, this.getWebSocketTransport);
|
|
3281
|
+
}, this.getWebSocketTransport, this.store);
|
|
3106
3282
|
}
|
|
3107
3283
|
/**
|
|
3108
|
-
*
|
|
3284
|
+
* Pin this query at at least this C-1 token. Observes the token into the
|
|
3285
|
+
* client store (I3, sticky) and presents it on execute via `X-Aouda-Token`.
|
|
3286
|
+
*/
|
|
3287
|
+
atLeast(token) {
|
|
3288
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
3289
|
+
throw new Error("atLeast() requires a non-empty token");
|
|
3290
|
+
}
|
|
3291
|
+
this.store?.observe(this.database, token);
|
|
3292
|
+
return this.withState({ ...this.state, atLeast: token });
|
|
3293
|
+
}
|
|
3294
|
+
/**
|
|
3295
|
+
* Selects specific columns to return.
|
|
3109
3296
|
* If not called, all columns are returned.
|
|
3110
3297
|
*
|
|
3111
3298
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -3127,7 +3314,7 @@ var TableQuery = class _TableQuery {
|
|
|
3127
3314
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3128
3315
|
...this.state,
|
|
3129
3316
|
selectColumns: columns.length > 0 ? columns : null
|
|
3130
|
-
}, this.getWebSocketTransport);
|
|
3317
|
+
}, this.getWebSocketTransport, this.store);
|
|
3131
3318
|
}
|
|
3132
3319
|
/**
|
|
3133
3320
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -3157,7 +3344,7 @@ var TableQuery = class _TableQuery {
|
|
|
3157
3344
|
...this.state,
|
|
3158
3345
|
selectColumns: columns,
|
|
3159
3346
|
isDistinct: true
|
|
3160
|
-
}, this.getWebSocketTransport);
|
|
3347
|
+
}, this.getWebSocketTransport, this.store);
|
|
3161
3348
|
}
|
|
3162
3349
|
/**
|
|
3163
3350
|
* Adds server-side computed columns to the query result.
|
|
@@ -3186,7 +3373,7 @@ var TableQuery = class _TableQuery {
|
|
|
3186
3373
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3187
3374
|
...this.state,
|
|
3188
3375
|
selectExprs: projections
|
|
3189
|
-
}, this.getWebSocketTransport);
|
|
3376
|
+
}, this.getWebSocketTransport, this.store);
|
|
3190
3377
|
}
|
|
3191
3378
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
3192
3379
|
return this.addJoinClause(
|
|
@@ -3244,7 +3431,8 @@ var TableQuery = class _TableQuery {
|
|
|
3244
3431
|
}
|
|
3245
3432
|
]
|
|
3246
3433
|
},
|
|
3247
|
-
this.getWebSocketTransport
|
|
3434
|
+
this.getWebSocketTransport,
|
|
3435
|
+
this.store
|
|
3248
3436
|
);
|
|
3249
3437
|
}
|
|
3250
3438
|
/**
|
|
@@ -3280,7 +3468,8 @@ var TableQuery = class _TableQuery {
|
|
|
3280
3468
|
...this.state,
|
|
3281
3469
|
groupByColumns: [...columns]
|
|
3282
3470
|
},
|
|
3283
|
-
this.getWebSocketTransport
|
|
3471
|
+
this.getWebSocketTransport,
|
|
3472
|
+
this.store
|
|
3284
3473
|
);
|
|
3285
3474
|
}
|
|
3286
3475
|
/**
|
|
@@ -3314,8 +3503,11 @@ var TableQuery = class _TableQuery {
|
|
|
3314
3503
|
onSnapshot: options.onSnapshot,
|
|
3315
3504
|
onChange: options.onChange,
|
|
3316
3505
|
onError: options.onError,
|
|
3317
|
-
conflate: options.conflate
|
|
3318
|
-
|
|
3506
|
+
conflate: options.conflate,
|
|
3507
|
+
atLeast: options.atLeast ?? this.state.atLeast,
|
|
3508
|
+
waitMs: options.waitMs,
|
|
3509
|
+
onExceeded: options.onExceeded
|
|
3510
|
+
}, void 0, this.store, this.database);
|
|
3319
3511
|
subscription.start();
|
|
3320
3512
|
return subscription;
|
|
3321
3513
|
}
|
|
@@ -3430,7 +3622,8 @@ var TableQuery = class _TableQuery {
|
|
|
3430
3622
|
...this.state,
|
|
3431
3623
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3432
3624
|
},
|
|
3433
|
-
this.getWebSocketTransport
|
|
3625
|
+
this.getWebSocketTransport,
|
|
3626
|
+
this.store
|
|
3434
3627
|
);
|
|
3435
3628
|
}
|
|
3436
3629
|
addAggregate(op, column) {
|
|
@@ -3451,7 +3644,8 @@ var TableQuery = class _TableQuery {
|
|
|
3451
3644
|
}
|
|
3452
3645
|
]
|
|
3453
3646
|
},
|
|
3454
|
-
this.getWebSocketTransport
|
|
3647
|
+
this.getWebSocketTransport,
|
|
3648
|
+
this.store
|
|
3455
3649
|
);
|
|
3456
3650
|
}
|
|
3457
3651
|
requireWebSocketTransport() {
|
|
@@ -3481,17 +3675,23 @@ var TableQuery = class _TableQuery {
|
|
|
3481
3675
|
* ```
|
|
3482
3676
|
*/
|
|
3483
3677
|
async execute() {
|
|
3678
|
+
if (this.state.atLeast) {
|
|
3679
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3680
|
+
}
|
|
3484
3681
|
const request = this.buildRequest();
|
|
3485
3682
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3486
3683
|
const response = await this.transport.post(path4, request);
|
|
3487
3684
|
const rows = columnarToRows(response);
|
|
3488
3685
|
const stats = response.stats;
|
|
3489
|
-
return { rows, stats };
|
|
3686
|
+
return { rows, stats, token: response.token };
|
|
3490
3687
|
}
|
|
3491
3688
|
/**
|
|
3492
3689
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3493
3690
|
*/
|
|
3494
3691
|
async toColumnar() {
|
|
3692
|
+
if (this.state.atLeast) {
|
|
3693
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3694
|
+
}
|
|
3495
3695
|
const request = this.buildRequest();
|
|
3496
3696
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3497
3697
|
return this.transport.post(path4, request);
|
|
@@ -3521,8 +3721,12 @@ var TableQuery = class _TableQuery {
|
|
|
3521
3721
|
limitValue: 0,
|
|
3522
3722
|
selectColumns: []
|
|
3523
3723
|
},
|
|
3524
|
-
this.getWebSocketTransport
|
|
3724
|
+
this.getWebSocketTransport,
|
|
3725
|
+
this.store
|
|
3525
3726
|
);
|
|
3727
|
+
if (this.state.atLeast) {
|
|
3728
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3729
|
+
}
|
|
3526
3730
|
const request = countQuery.buildRequest();
|
|
3527
3731
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3528
3732
|
const response = await this.transport.post(path4, request);
|
|
@@ -3569,7 +3773,8 @@ var TableQuery = class _TableQuery {
|
|
|
3569
3773
|
const response = await this.transport.post(path4, body);
|
|
3570
3774
|
const result = {
|
|
3571
3775
|
rowsInserted: response.rowsInserted,
|
|
3572
|
-
executionMs: response.executionMs
|
|
3776
|
+
executionMs: response.executionMs,
|
|
3777
|
+
token: response.token
|
|
3573
3778
|
};
|
|
3574
3779
|
if (response.generatedValues !== void 0) {
|
|
3575
3780
|
result.generatedValues = response.generatedValues;
|
|
@@ -3619,7 +3824,8 @@ var TableQuery = class _TableQuery {
|
|
|
3619
3824
|
const response = await this.transport.post(path4, body);
|
|
3620
3825
|
const result = {
|
|
3621
3826
|
rowsInserted: response.rowsInserted,
|
|
3622
|
-
executionMs: response.executionMs
|
|
3827
|
+
executionMs: response.executionMs,
|
|
3828
|
+
token: response.token
|
|
3623
3829
|
};
|
|
3624
3830
|
if (response.generatedValues !== void 0) {
|
|
3625
3831
|
result.generatedValues = response.generatedValues;
|
|
@@ -3671,6 +3877,7 @@ var TableQuery = class _TableQuery {
|
|
|
3671
3877
|
return {
|
|
3672
3878
|
rowsAffected: response.rowsUpdated,
|
|
3673
3879
|
executionMs: response.executionMs,
|
|
3880
|
+
token: response.token,
|
|
3674
3881
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3675
3882
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3676
3883
|
};
|
|
@@ -3721,6 +3928,7 @@ var TableQuery = class _TableQuery {
|
|
|
3721
3928
|
rowsAffected: response.rowsDeleted,
|
|
3722
3929
|
executionMs: response.executionMs,
|
|
3723
3930
|
hasMore: response.hasMore,
|
|
3931
|
+
token: response.token,
|
|
3724
3932
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3725
3933
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3726
3934
|
};
|
|
@@ -3740,7 +3948,8 @@ var TableQuery = class _TableQuery {
|
|
|
3740
3948
|
return {
|
|
3741
3949
|
rowsAffected: response.rowsDeleted,
|
|
3742
3950
|
executionMs: response.executionMs,
|
|
3743
|
-
hasMore: false
|
|
3951
|
+
hasMore: false,
|
|
3952
|
+
token: response.token
|
|
3744
3953
|
};
|
|
3745
3954
|
}
|
|
3746
3955
|
/**
|
|
@@ -3753,7 +3962,14 @@ var TableQuery = class _TableQuery {
|
|
|
3753
3962
|
throw new Error("batch() requires a non-empty operations array");
|
|
3754
3963
|
}
|
|
3755
3964
|
const wireOperations = operations.map((op, index) => {
|
|
3756
|
-
const base = new _TableQuery(
|
|
3965
|
+
const base = new _TableQuery(
|
|
3966
|
+
this.transport,
|
|
3967
|
+
this.tableName,
|
|
3968
|
+
this.database,
|
|
3969
|
+
void 0,
|
|
3970
|
+
this.getWebSocketTransport,
|
|
3971
|
+
this.store
|
|
3972
|
+
);
|
|
3757
3973
|
const scoped = op.where(base);
|
|
3758
3974
|
const where = scoped.buildWhereClause();
|
|
3759
3975
|
if (!where) {
|
|
@@ -5090,12 +5306,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
5090
5306
|
continue;
|
|
5091
5307
|
}
|
|
5092
5308
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
5093
|
-
const
|
|
5309
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
5094
5310
|
sink({
|
|
5095
5311
|
code: warning.code,
|
|
5096
|
-
|
|
5312
|
+
name: warning.name,
|
|
5097
5313
|
sunsetAt: warning.sunsetAt,
|
|
5098
|
-
message: `${warning.code}:${
|
|
5314
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
5099
5315
|
});
|
|
5100
5316
|
}
|
|
5101
5317
|
}
|
|
@@ -5108,24 +5324,28 @@ function emptyStats() {
|
|
|
5108
5324
|
};
|
|
5109
5325
|
}
|
|
5110
5326
|
var NamedQueriesApi = class {
|
|
5111
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5327
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
5112
5328
|
this.transport = transport;
|
|
5113
5329
|
this.database = database;
|
|
5114
5330
|
this.onWarning = onWarning;
|
|
5115
5331
|
this.getStreamingTransport = getStreamingTransport;
|
|
5332
|
+
this.store = store;
|
|
5116
5333
|
}
|
|
5117
|
-
async execute(
|
|
5118
|
-
if (typeof
|
|
5119
|
-
throw new Error("Named query
|
|
5334
|
+
async execute(name, args, options) {
|
|
5335
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5336
|
+
throw new Error("Named query name must be a non-empty string");
|
|
5120
5337
|
}
|
|
5121
5338
|
const prefix = databasePath2(this.database);
|
|
5122
|
-
const path4 = `${prefix}/named-queries/${encodeURIComponent(
|
|
5339
|
+
const path4 = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
5123
5340
|
const body = {
|
|
5124
5341
|
args: args ?? {}
|
|
5125
5342
|
};
|
|
5126
5343
|
if (options?.orderByIndex !== void 0) {
|
|
5127
5344
|
body.orderByIndex = options.orderByIndex;
|
|
5128
5345
|
}
|
|
5346
|
+
if (options?.atLeast !== void 0) {
|
|
5347
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5348
|
+
}
|
|
5129
5349
|
const response = await this.transport.post(
|
|
5130
5350
|
path4,
|
|
5131
5351
|
body,
|
|
@@ -5137,7 +5357,8 @@ var NamedQueriesApi = class {
|
|
|
5137
5357
|
rows,
|
|
5138
5358
|
stats: response.stats,
|
|
5139
5359
|
warnings: response.warnings,
|
|
5140
|
-
totalMatches: response.totalMatches
|
|
5360
|
+
totalMatches: response.totalMatches,
|
|
5361
|
+
token: response.token
|
|
5141
5362
|
};
|
|
5142
5363
|
}
|
|
5143
5364
|
async batch(items, options) {
|
|
@@ -5155,6 +5376,9 @@ var NamedQueriesApi = class {
|
|
|
5155
5376
|
400
|
|
5156
5377
|
);
|
|
5157
5378
|
}
|
|
5379
|
+
if (options?.atLeast !== void 0) {
|
|
5380
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5381
|
+
}
|
|
5158
5382
|
const prefix = databasePath2(this.database);
|
|
5159
5383
|
const path4 = `${prefix}/named-queries/batch?format=columnar`;
|
|
5160
5384
|
const envelope = await this.transport.post(
|
|
@@ -5177,34 +5401,41 @@ var NamedQueriesApi = class {
|
|
|
5177
5401
|
rowCount: slot.rowCount ?? 0,
|
|
5178
5402
|
stats: slot.stats ?? emptyStats(),
|
|
5179
5403
|
warnings: slot.warnings,
|
|
5180
|
-
totalMatches: slot.totalMatches
|
|
5404
|
+
totalMatches: slot.totalMatches,
|
|
5405
|
+
token: slot.token
|
|
5181
5406
|
};
|
|
5182
5407
|
const result = {
|
|
5183
5408
|
rows: columnarToRows(columnar),
|
|
5184
5409
|
stats: columnar.stats,
|
|
5185
5410
|
warnings: slot.warnings,
|
|
5186
|
-
totalMatches: slot.totalMatches
|
|
5411
|
+
totalMatches: slot.totalMatches,
|
|
5412
|
+
token: slot.token
|
|
5187
5413
|
};
|
|
5188
5414
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
5189
5415
|
return { isError: false, result };
|
|
5190
5416
|
});
|
|
5191
5417
|
}
|
|
5192
|
-
subscribe(
|
|
5193
|
-
if (typeof
|
|
5194
|
-
throw new Error("Named query
|
|
5418
|
+
subscribe(name, args, options = {}) {
|
|
5419
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5420
|
+
throw new Error("Named query name must be a non-empty string");
|
|
5195
5421
|
}
|
|
5196
5422
|
const subscription = new TableSubscription(
|
|
5197
5423
|
this.getStreamingTransport(),
|
|
5198
|
-
{ kind: "named",
|
|
5424
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
5199
5425
|
{
|
|
5200
5426
|
onSnapshot: options.onSnapshot,
|
|
5201
5427
|
onChange: options.onChange,
|
|
5202
5428
|
onError: options.onError,
|
|
5203
|
-
conflate: options.conflate
|
|
5429
|
+
conflate: options.conflate,
|
|
5430
|
+
atLeast: options.atLeast,
|
|
5431
|
+
waitMs: options.waitMs,
|
|
5432
|
+
onExceeded: options.onExceeded
|
|
5204
5433
|
},
|
|
5205
5434
|
(warnings) => {
|
|
5206
5435
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
5207
|
-
}
|
|
5436
|
+
},
|
|
5437
|
+
this.store,
|
|
5438
|
+
this.database
|
|
5208
5439
|
);
|
|
5209
5440
|
subscription.start();
|
|
5210
5441
|
return subscription;
|
|
@@ -5216,12 +5447,12 @@ var NamedMutationsApi = class {
|
|
|
5216
5447
|
this.database = database;
|
|
5217
5448
|
this.onWarning = onWarning;
|
|
5218
5449
|
}
|
|
5219
|
-
async execute(
|
|
5220
|
-
if (typeof
|
|
5221
|
-
throw new Error("Named mutation
|
|
5450
|
+
async execute(name, args) {
|
|
5451
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
5452
|
+
throw new Error("Named mutation name must be a non-empty string");
|
|
5222
5453
|
}
|
|
5223
5454
|
const prefix = databasePath2(this.database);
|
|
5224
|
-
const path4 = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5455
|
+
const path4 = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
5225
5456
|
const wire = await this.transport.post(path4, {
|
|
5226
5457
|
args: args ?? {}
|
|
5227
5458
|
});
|
|
@@ -5282,6 +5513,7 @@ var WebSocketTransport = class {
|
|
|
5282
5513
|
// Serialized-send queue: each send appends to this tail.
|
|
5283
5514
|
this._sendTail = Promise.resolve();
|
|
5284
5515
|
this._lastVersion = 0;
|
|
5516
|
+
this._lastToken = null;
|
|
5285
5517
|
this._reconnectAttempt = 0;
|
|
5286
5518
|
this._disposed = false;
|
|
5287
5519
|
this._missedPings = 0;
|
|
@@ -5299,6 +5531,7 @@ var WebSocketTransport = class {
|
|
|
5299
5531
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
5300
5532
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
5301
5533
|
this._enableCompression = options.enableCompression ?? true;
|
|
5534
|
+
this._store = options.consistencyTokenStore;
|
|
5302
5535
|
this._wireMode = options.wireMode ?? "json";
|
|
5303
5536
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
5304
5537
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -5307,10 +5540,14 @@ var WebSocketTransport = class {
|
|
|
5307
5540
|
});
|
|
5308
5541
|
}
|
|
5309
5542
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
5310
|
-
/** Latest
|
|
5543
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
5311
5544
|
get lastVersion() {
|
|
5312
5545
|
return this._lastVersion;
|
|
5313
5546
|
}
|
|
5547
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5548
|
+
get lastToken() {
|
|
5549
|
+
return this._lastToken;
|
|
5550
|
+
}
|
|
5314
5551
|
/**
|
|
5315
5552
|
* Registers a handler for incoming server messages with the given channel id.
|
|
5316
5553
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5498,6 +5735,10 @@ var WebSocketTransport = class {
|
|
|
5498
5735
|
}
|
|
5499
5736
|
case "heartbeat":
|
|
5500
5737
|
this._lastVersion = msg.version;
|
|
5738
|
+
this._lastToken = msg.token ?? null;
|
|
5739
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
5740
|
+
this._store?.observe(this._database, this._lastToken);
|
|
5741
|
+
}
|
|
5501
5742
|
break;
|
|
5502
5743
|
case "pong":
|
|
5503
5744
|
this._missedPings = 0;
|
|
@@ -5663,16 +5904,21 @@ var LongPollTransport = class {
|
|
|
5663
5904
|
this._connected = false;
|
|
5664
5905
|
this._pollTask = null;
|
|
5665
5906
|
this._lastVersion = 0;
|
|
5907
|
+
this._lastToken = null;
|
|
5666
5908
|
this._serverUrl = serverUrl;
|
|
5667
5909
|
this._database = database;
|
|
5668
5910
|
this._authHandler = options.authHandler;
|
|
5669
5911
|
this._onReconnected = options.onReconnected;
|
|
5670
5912
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5671
5913
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5914
|
+
this._store = options.consistencyTokenStore;
|
|
5672
5915
|
}
|
|
5673
5916
|
get lastVersion() {
|
|
5674
5917
|
return this._lastVersion;
|
|
5675
5918
|
}
|
|
5919
|
+
get lastToken() {
|
|
5920
|
+
return this._lastToken;
|
|
5921
|
+
}
|
|
5676
5922
|
registerHandler(id, handler) {
|
|
5677
5923
|
this._handlers.set(id, handler);
|
|
5678
5924
|
}
|
|
@@ -5795,6 +6041,10 @@ var LongPollTransport = class {
|
|
|
5795
6041
|
for (const msg of payload.messages) {
|
|
5796
6042
|
if (msg.type === "heartbeat") {
|
|
5797
6043
|
this._lastVersion = msg.version;
|
|
6044
|
+
this._lastToken = msg.token ?? null;
|
|
6045
|
+
if (this._lastToken != null && this._lastToken.length > 0) {
|
|
6046
|
+
this._store?.observe(this._database, this._lastToken);
|
|
6047
|
+
}
|
|
5798
6048
|
}
|
|
5799
6049
|
const id = "id" in msg ? msg.id : void 0;
|
|
5800
6050
|
if (id !== void 0 && id !== null) {
|
|
@@ -5874,6 +6124,9 @@ var FallbackStreamingTransport = class {
|
|
|
5874
6124
|
get lastVersion() {
|
|
5875
6125
|
return this._active.lastVersion;
|
|
5876
6126
|
}
|
|
6127
|
+
get lastToken() {
|
|
6128
|
+
return this._active.lastToken;
|
|
6129
|
+
}
|
|
5877
6130
|
registerHandler(id, handler) {
|
|
5878
6131
|
this._handlers.set(id, handler);
|
|
5879
6132
|
this._active.registerHandler(id, handler);
|
|
@@ -5953,6 +6206,7 @@ var AoudaClient = class {
|
|
|
5953
6206
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5954
6207
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5955
6208
|
this.database = options.database.trim();
|
|
6209
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5956
6210
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5957
6211
|
throw new Error("timeout must be a finite positive number");
|
|
5958
6212
|
}
|
|
@@ -5987,7 +6241,9 @@ var AoudaClient = class {
|
|
|
5987
6241
|
}
|
|
5988
6242
|
const httpTransport = new HttpTransport({
|
|
5989
6243
|
baseUrl: this.baseUrl,
|
|
5990
|
-
timeout: this.timeout
|
|
6244
|
+
timeout: this.timeout,
|
|
6245
|
+
database: this.database,
|
|
6246
|
+
consistencyTokenStore: this._store
|
|
5991
6247
|
});
|
|
5992
6248
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5993
6249
|
if (activeAuth) {
|
|
@@ -6047,7 +6303,8 @@ var AoudaClient = class {
|
|
|
6047
6303
|
this.transport,
|
|
6048
6304
|
this.database,
|
|
6049
6305
|
onNamedArtifactWarning,
|
|
6050
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6306
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6307
|
+
this._store
|
|
6051
6308
|
);
|
|
6052
6309
|
this._namedMutations = new NamedMutationsApi(
|
|
6053
6310
|
this.transport,
|
|
@@ -6146,7 +6403,8 @@ var AoudaClient = class {
|
|
|
6146
6403
|
name,
|
|
6147
6404
|
this.database,
|
|
6148
6405
|
void 0,
|
|
6149
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6406
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6407
|
+
this._store
|
|
6150
6408
|
);
|
|
6151
6409
|
}
|
|
6152
6410
|
/**
|
|
@@ -6198,13 +6456,26 @@ var AoudaClient = class {
|
|
|
6198
6456
|
return this._materializedQueries;
|
|
6199
6457
|
}
|
|
6200
6458
|
/**
|
|
6201
|
-
*
|
|
6459
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
6202
6460
|
*/
|
|
6203
6461
|
get namedQueries() {
|
|
6204
6462
|
return this._namedQueries;
|
|
6205
6463
|
}
|
|
6464
|
+
observeConsistencyToken(token) {
|
|
6465
|
+
this._store.observe(this.database, token);
|
|
6466
|
+
}
|
|
6467
|
+
getObservedConsistencyToken() {
|
|
6468
|
+
return this._store.get(this.database);
|
|
6469
|
+
}
|
|
6470
|
+
async getConsistencyToken() {
|
|
6471
|
+
const body = await this.transport.get(
|
|
6472
|
+
`/api/databases/${encodeURIComponent(this.database)}/token`
|
|
6473
|
+
);
|
|
6474
|
+
this._store.observe(this.database, body.token);
|
|
6475
|
+
return this._store.get(this.database) ?? body.token;
|
|
6476
|
+
}
|
|
6206
6477
|
/**
|
|
6207
|
-
*
|
|
6478
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
6208
6479
|
*/
|
|
6209
6480
|
get namedMutations() {
|
|
6210
6481
|
return this._namedMutations;
|
|
@@ -6331,13 +6602,15 @@ var AoudaClient = class {
|
|
|
6331
6602
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
6332
6603
|
authHandler: this._authHandler,
|
|
6333
6604
|
enableCompression: this._streamingEnableCompression,
|
|
6334
|
-
wireMode: this._streamingWireMode
|
|
6605
|
+
wireMode: this._streamingWireMode,
|
|
6606
|
+
consistencyTokenStore: this._store
|
|
6335
6607
|
});
|
|
6336
6608
|
if (this._streamingEnableLongPollFallback) {
|
|
6337
6609
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
6338
6610
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
6339
6611
|
authHandler: this._authHandler,
|
|
6340
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6612
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6613
|
+
consistencyTokenStore: this._store
|
|
6341
6614
|
});
|
|
6342
6615
|
});
|
|
6343
6616
|
} else {
|
|
@@ -6363,7 +6636,7 @@ Usage:
|
|
|
6363
6636
|
npx @aouda/client schema <command> [options]
|
|
6364
6637
|
|
|
6365
6638
|
Commands:
|
|
6366
|
-
generate Fetch schema from Aouda server and output TypeScript types (tables + named query/mutation
|
|
6639
|
+
generate Fetch schema from Aouda server and output TypeScript types (tables + optional named query/mutation Args/Row)
|
|
6367
6640
|
schema Schema management (diff, apply, export, validate, history, seed)
|
|
6368
6641
|
diff Show migration plan (desired vs current)
|
|
6369
6642
|
apply Apply schema (use --allow-destructive for drops; --dry-run to preview)
|