@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.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,10 +2633,13 @@ 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
|
}
|
|
2640
|
+
if (this._identity.orderByIndex !== void 0) {
|
|
2641
|
+
message.orderByIndex = this._identity.orderByIndex;
|
|
2642
|
+
}
|
|
2507
2643
|
} else {
|
|
2508
2644
|
message.target = this._identity.target;
|
|
2509
2645
|
if (this._identity.filter !== void 0) {
|
|
@@ -2516,8 +2652,30 @@ var TableSubscription = class {
|
|
|
2516
2652
|
if (this._conflate !== void 0) {
|
|
2517
2653
|
message.conflate = this._conflate;
|
|
2518
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
|
+
}
|
|
2519
2665
|
await this._transport.send(message);
|
|
2520
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
|
+
}
|
|
2521
2679
|
_handleMessage(message) {
|
|
2522
2680
|
if (!this._active) {
|
|
2523
2681
|
return;
|
|
@@ -2544,6 +2702,7 @@ var TableSubscription = class {
|
|
|
2544
2702
|
}
|
|
2545
2703
|
_handleSnapshotPage(message) {
|
|
2546
2704
|
this._pendingSnapshotRows.push(...message.rows);
|
|
2705
|
+
this._observeToken(message.token);
|
|
2547
2706
|
}
|
|
2548
2707
|
_handleSnapshotComplete(message) {
|
|
2549
2708
|
this._lastVersion = message.version;
|
|
@@ -2552,12 +2711,20 @@ var TableSubscription = class {
|
|
|
2552
2711
|
}
|
|
2553
2712
|
const rows = this._pendingSnapshotRows;
|
|
2554
2713
|
this._pendingSnapshotRows = [];
|
|
2555
|
-
this._onSnapshot?.(rows, message.version);
|
|
2556
|
-
|
|
2714
|
+
this._onSnapshot?.(rows, message.version, message.total_matches);
|
|
2715
|
+
const snapshot = {
|
|
2557
2716
|
type: "snapshot",
|
|
2558
2717
|
rows,
|
|
2559
2718
|
version: message.version
|
|
2560
|
-
}
|
|
2719
|
+
};
|
|
2720
|
+
if (message.total_matches !== void 0) {
|
|
2721
|
+
snapshot.totalMatches = message.total_matches;
|
|
2722
|
+
}
|
|
2723
|
+
if (message.token !== void 0) {
|
|
2724
|
+
snapshot.token = message.token;
|
|
2725
|
+
this._observeToken(message.token);
|
|
2726
|
+
}
|
|
2727
|
+
this._queue.push(snapshot);
|
|
2561
2728
|
}
|
|
2562
2729
|
async _handleGap(message) {
|
|
2563
2730
|
this._pendingSnapshotRows = [];
|
|
@@ -2582,6 +2749,10 @@ var TableSubscription = class {
|
|
|
2582
2749
|
if (message.values_skipped !== void 0) {
|
|
2583
2750
|
event.values_skipped = message.values_skipped;
|
|
2584
2751
|
}
|
|
2752
|
+
if (message.token !== void 0) {
|
|
2753
|
+
event.token = message.token;
|
|
2754
|
+
this._observeToken(message.token);
|
|
2755
|
+
}
|
|
2585
2756
|
this._onChange?.(event);
|
|
2586
2757
|
this._queue.push(event);
|
|
2587
2758
|
}
|
|
@@ -2926,11 +3097,12 @@ var TableQuery = class _TableQuery {
|
|
|
2926
3097
|
* @param state - Optional initial state (used for immutable chaining).
|
|
2927
3098
|
* @internal Use `client.table()` to create queries.
|
|
2928
3099
|
*/
|
|
2929
|
-
constructor(transport, tableName, database, state, getWebSocketTransport) {
|
|
3100
|
+
constructor(transport, tableName, database, state, getWebSocketTransport, store) {
|
|
2930
3101
|
this.transport = transport;
|
|
2931
3102
|
this.tableName = tableName;
|
|
2932
3103
|
this.database = database;
|
|
2933
3104
|
this.getWebSocketTransport = getWebSocketTransport;
|
|
3105
|
+
this.store = store;
|
|
2934
3106
|
this.state = state ?? {
|
|
2935
3107
|
predicates: [],
|
|
2936
3108
|
groupClauses: [],
|
|
@@ -2946,6 +3118,16 @@ var TableQuery = class _TableQuery {
|
|
|
2946
3118
|
isDistinct: false
|
|
2947
3119
|
};
|
|
2948
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
|
+
}
|
|
2949
3131
|
where(column, operator, value) {
|
|
2950
3132
|
const newPredicates = buildWherePredicates(column, operator, value);
|
|
2951
3133
|
return new _TableQuery(
|
|
@@ -2956,7 +3138,8 @@ var TableQuery = class _TableQuery {
|
|
|
2956
3138
|
...this.state,
|
|
2957
3139
|
predicates: [...this.state.predicates, ...newPredicates]
|
|
2958
3140
|
},
|
|
2959
|
-
this.getWebSocketTransport
|
|
3141
|
+
this.getWebSocketTransport,
|
|
3142
|
+
this.store
|
|
2960
3143
|
);
|
|
2961
3144
|
}
|
|
2962
3145
|
/**
|
|
@@ -2975,7 +3158,7 @@ var TableQuery = class _TableQuery {
|
|
|
2975
3158
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
2976
3159
|
...this.state,
|
|
2977
3160
|
groupClauses: [...this.state.groupClauses, sub]
|
|
2978
|
-
}, this.getWebSocketTransport);
|
|
3161
|
+
}, this.getWebSocketTransport, this.store);
|
|
2979
3162
|
}
|
|
2980
3163
|
/**
|
|
2981
3164
|
* Sets the primary sort column for the query.
|
|
@@ -3000,7 +3183,7 @@ var TableQuery = class _TableQuery {
|
|
|
3000
3183
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3001
3184
|
...this.state,
|
|
3002
3185
|
orderByClauses: [orderByClause]
|
|
3003
|
-
}, this.getWebSocketTransport);
|
|
3186
|
+
}, this.getWebSocketTransport, this.store);
|
|
3004
3187
|
}
|
|
3005
3188
|
/**
|
|
3006
3189
|
* Sets the primary sort column to descending order.
|
|
@@ -3046,7 +3229,7 @@ var TableQuery = class _TableQuery {
|
|
|
3046
3229
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3047
3230
|
...this.state,
|
|
3048
3231
|
orderByClauses: [...this.state.orderByClauses, orderByClause]
|
|
3049
|
-
}, this.getWebSocketTransport);
|
|
3232
|
+
}, this.getWebSocketTransport, this.store);
|
|
3050
3233
|
}
|
|
3051
3234
|
/**
|
|
3052
3235
|
* Sets the maximum number of rows to return.
|
|
@@ -3063,7 +3246,7 @@ var TableQuery = class _TableQuery {
|
|
|
3063
3246
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3064
3247
|
...this.state,
|
|
3065
3248
|
limitValue: count
|
|
3066
|
-
}, this.getWebSocketTransport);
|
|
3249
|
+
}, this.getWebSocketTransport, this.store);
|
|
3067
3250
|
}
|
|
3068
3251
|
/**
|
|
3069
3252
|
* Sets the number of rows to skip.
|
|
@@ -3080,7 +3263,7 @@ var TableQuery = class _TableQuery {
|
|
|
3080
3263
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3081
3264
|
...this.state,
|
|
3082
3265
|
offsetValue: count
|
|
3083
|
-
}, this.getWebSocketTransport);
|
|
3266
|
+
}, this.getWebSocketTransport, this.store);
|
|
3084
3267
|
}
|
|
3085
3268
|
/**
|
|
3086
3269
|
* Requests cross-partition access for this query.
|
|
@@ -3095,10 +3278,21 @@ var TableQuery = class _TableQuery {
|
|
|
3095
3278
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3096
3279
|
...this.state,
|
|
3097
3280
|
crossPartitionAccess: true
|
|
3098
|
-
}, this.getWebSocketTransport);
|
|
3281
|
+
}, this.getWebSocketTransport, this.store);
|
|
3282
|
+
}
|
|
3283
|
+
/**
|
|
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 });
|
|
3099
3293
|
}
|
|
3100
3294
|
/**
|
|
3101
|
-
*
|
|
3295
|
+
* Selects specific columns to return.
|
|
3102
3296
|
* If not called, all columns are returned.
|
|
3103
3297
|
*
|
|
3104
3298
|
* When T is a specific row type, only keys of T are accepted as column names.
|
|
@@ -3120,7 +3314,7 @@ var TableQuery = class _TableQuery {
|
|
|
3120
3314
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3121
3315
|
...this.state,
|
|
3122
3316
|
selectColumns: columns.length > 0 ? columns : null
|
|
3123
|
-
}, this.getWebSocketTransport);
|
|
3317
|
+
}, this.getWebSocketTransport, this.store);
|
|
3124
3318
|
}
|
|
3125
3319
|
/**
|
|
3126
3320
|
* Return only distinct (de-duplicated) rows for the given columns — SQL `SELECT DISTINCT`.
|
|
@@ -3150,7 +3344,7 @@ var TableQuery = class _TableQuery {
|
|
|
3150
3344
|
...this.state,
|
|
3151
3345
|
selectColumns: columns,
|
|
3152
3346
|
isDistinct: true
|
|
3153
|
-
}, this.getWebSocketTransport);
|
|
3347
|
+
}, this.getWebSocketTransport, this.store);
|
|
3154
3348
|
}
|
|
3155
3349
|
/**
|
|
3156
3350
|
* Adds server-side computed columns to the query result.
|
|
@@ -3179,7 +3373,7 @@ var TableQuery = class _TableQuery {
|
|
|
3179
3373
|
return new _TableQuery(this.transport, this.tableName, this.database, {
|
|
3180
3374
|
...this.state,
|
|
3181
3375
|
selectExprs: projections
|
|
3182
|
-
}, this.getWebSocketTransport);
|
|
3376
|
+
}, this.getWebSocketTransport, this.store);
|
|
3183
3377
|
}
|
|
3184
3378
|
join(rightTable, leftColumnOrColumns, rightColumnOrColumns) {
|
|
3185
3379
|
return this.addJoinClause(
|
|
@@ -3237,7 +3431,8 @@ var TableQuery = class _TableQuery {
|
|
|
3237
3431
|
}
|
|
3238
3432
|
]
|
|
3239
3433
|
},
|
|
3240
|
-
this.getWebSocketTransport
|
|
3434
|
+
this.getWebSocketTransport,
|
|
3435
|
+
this.store
|
|
3241
3436
|
);
|
|
3242
3437
|
}
|
|
3243
3438
|
/**
|
|
@@ -3273,7 +3468,8 @@ var TableQuery = class _TableQuery {
|
|
|
3273
3468
|
...this.state,
|
|
3274
3469
|
groupByColumns: [...columns]
|
|
3275
3470
|
},
|
|
3276
|
-
this.getWebSocketTransport
|
|
3471
|
+
this.getWebSocketTransport,
|
|
3472
|
+
this.store
|
|
3277
3473
|
);
|
|
3278
3474
|
}
|
|
3279
3475
|
/**
|
|
@@ -3307,8 +3503,11 @@ var TableQuery = class _TableQuery {
|
|
|
3307
3503
|
onSnapshot: options.onSnapshot,
|
|
3308
3504
|
onChange: options.onChange,
|
|
3309
3505
|
onError: options.onError,
|
|
3310
|
-
conflate: options.conflate
|
|
3311
|
-
|
|
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);
|
|
3312
3511
|
subscription.start();
|
|
3313
3512
|
return subscription;
|
|
3314
3513
|
}
|
|
@@ -3423,7 +3622,8 @@ var TableQuery = class _TableQuery {
|
|
|
3423
3622
|
...this.state,
|
|
3424
3623
|
joinClauses: [...this.state.joinClauses, joinClause]
|
|
3425
3624
|
},
|
|
3426
|
-
this.getWebSocketTransport
|
|
3625
|
+
this.getWebSocketTransport,
|
|
3626
|
+
this.store
|
|
3427
3627
|
);
|
|
3428
3628
|
}
|
|
3429
3629
|
addAggregate(op, column) {
|
|
@@ -3444,7 +3644,8 @@ var TableQuery = class _TableQuery {
|
|
|
3444
3644
|
}
|
|
3445
3645
|
]
|
|
3446
3646
|
},
|
|
3447
|
-
this.getWebSocketTransport
|
|
3647
|
+
this.getWebSocketTransport,
|
|
3648
|
+
this.store
|
|
3448
3649
|
);
|
|
3449
3650
|
}
|
|
3450
3651
|
requireWebSocketTransport() {
|
|
@@ -3474,17 +3675,23 @@ var TableQuery = class _TableQuery {
|
|
|
3474
3675
|
* ```
|
|
3475
3676
|
*/
|
|
3476
3677
|
async execute() {
|
|
3678
|
+
if (this.state.atLeast) {
|
|
3679
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3680
|
+
}
|
|
3477
3681
|
const request = this.buildRequest();
|
|
3478
3682
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3479
3683
|
const response = await this.transport.post(path4, request);
|
|
3480
3684
|
const rows = columnarToRows(response);
|
|
3481
3685
|
const stats = response.stats;
|
|
3482
|
-
return { rows, stats };
|
|
3686
|
+
return { rows, stats, token: response.token };
|
|
3483
3687
|
}
|
|
3484
3688
|
/**
|
|
3485
3689
|
* Executes the query and returns the raw columnar JSON payload (no row-object conversion).
|
|
3486
3690
|
*/
|
|
3487
3691
|
async toColumnar() {
|
|
3692
|
+
if (this.state.atLeast) {
|
|
3693
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3694
|
+
}
|
|
3488
3695
|
const request = this.buildRequest();
|
|
3489
3696
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3490
3697
|
return this.transport.post(path4, request);
|
|
@@ -3514,8 +3721,12 @@ var TableQuery = class _TableQuery {
|
|
|
3514
3721
|
limitValue: 0,
|
|
3515
3722
|
selectColumns: []
|
|
3516
3723
|
},
|
|
3517
|
-
this.getWebSocketTransport
|
|
3724
|
+
this.getWebSocketTransport,
|
|
3725
|
+
this.store
|
|
3518
3726
|
);
|
|
3727
|
+
if (this.state.atLeast) {
|
|
3728
|
+
this.store?.observe(this.database, this.state.atLeast);
|
|
3729
|
+
}
|
|
3519
3730
|
const request = countQuery.buildRequest();
|
|
3520
3731
|
const path4 = `${databasePath2(this.database)}/query`;
|
|
3521
3732
|
const response = await this.transport.post(path4, request);
|
|
@@ -3562,7 +3773,8 @@ var TableQuery = class _TableQuery {
|
|
|
3562
3773
|
const response = await this.transport.post(path4, body);
|
|
3563
3774
|
const result = {
|
|
3564
3775
|
rowsInserted: response.rowsInserted,
|
|
3565
|
-
executionMs: response.executionMs
|
|
3776
|
+
executionMs: response.executionMs,
|
|
3777
|
+
token: response.token
|
|
3566
3778
|
};
|
|
3567
3779
|
if (response.generatedValues !== void 0) {
|
|
3568
3780
|
result.generatedValues = response.generatedValues;
|
|
@@ -3612,7 +3824,8 @@ var TableQuery = class _TableQuery {
|
|
|
3612
3824
|
const response = await this.transport.post(path4, body);
|
|
3613
3825
|
const result = {
|
|
3614
3826
|
rowsInserted: response.rowsInserted,
|
|
3615
|
-
executionMs: response.executionMs
|
|
3827
|
+
executionMs: response.executionMs,
|
|
3828
|
+
token: response.token
|
|
3616
3829
|
};
|
|
3617
3830
|
if (response.generatedValues !== void 0) {
|
|
3618
3831
|
result.generatedValues = response.generatedValues;
|
|
@@ -3664,6 +3877,7 @@ var TableQuery = class _TableQuery {
|
|
|
3664
3877
|
return {
|
|
3665
3878
|
rowsAffected: response.rowsUpdated,
|
|
3666
3879
|
executionMs: response.executionMs,
|
|
3880
|
+
token: response.token,
|
|
3667
3881
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3668
3882
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3669
3883
|
};
|
|
@@ -3714,6 +3928,7 @@ var TableQuery = class _TableQuery {
|
|
|
3714
3928
|
rowsAffected: response.rowsDeleted,
|
|
3715
3929
|
executionMs: response.executionMs,
|
|
3716
3930
|
hasMore: response.hasMore,
|
|
3931
|
+
token: response.token,
|
|
3717
3932
|
...response.rows ? { rows: columnarToRows(response.rows) } : {},
|
|
3718
3933
|
...response.rowsTruncated ? { rowsTruncated: true } : {}
|
|
3719
3934
|
};
|
|
@@ -3733,7 +3948,8 @@ var TableQuery = class _TableQuery {
|
|
|
3733
3948
|
return {
|
|
3734
3949
|
rowsAffected: response.rowsDeleted,
|
|
3735
3950
|
executionMs: response.executionMs,
|
|
3736
|
-
hasMore: false
|
|
3951
|
+
hasMore: false,
|
|
3952
|
+
token: response.token
|
|
3737
3953
|
};
|
|
3738
3954
|
}
|
|
3739
3955
|
/**
|
|
@@ -3746,7 +3962,14 @@ var TableQuery = class _TableQuery {
|
|
|
3746
3962
|
throw new Error("batch() requires a non-empty operations array");
|
|
3747
3963
|
}
|
|
3748
3964
|
const wireOperations = operations.map((op, index) => {
|
|
3749
|
-
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
|
+
);
|
|
3750
3973
|
const scoped = op.where(base);
|
|
3751
3974
|
const where = scoped.buildWhereClause();
|
|
3752
3975
|
if (!where) {
|
|
@@ -5083,12 +5306,12 @@ function raiseDeprecationWarnings(sink, warnings) {
|
|
|
5083
5306
|
continue;
|
|
5084
5307
|
}
|
|
5085
5308
|
const sunset = warning.sunsetAt != null ? ` sunsetAt=${warning.sunsetAt}` : "";
|
|
5086
|
-
const
|
|
5309
|
+
const name = warning.name != null && warning.name.length > 0 ? ` name=${warning.name}` : "";
|
|
5087
5310
|
sink({
|
|
5088
5311
|
code: warning.code,
|
|
5089
|
-
|
|
5312
|
+
name: warning.name,
|
|
5090
5313
|
sunsetAt: warning.sunsetAt,
|
|
5091
|
-
message: `${warning.code}:${
|
|
5314
|
+
message: `${warning.code}:${name}${sunset}`.trim()
|
|
5092
5315
|
});
|
|
5093
5316
|
}
|
|
5094
5317
|
}
|
|
@@ -5101,21 +5324,31 @@ function emptyStats() {
|
|
|
5101
5324
|
};
|
|
5102
5325
|
}
|
|
5103
5326
|
var NamedQueriesApi = class {
|
|
5104
|
-
constructor(transport, database, onWarning, getStreamingTransport) {
|
|
5327
|
+
constructor(transport, database, onWarning, getStreamingTransport, store) {
|
|
5105
5328
|
this.transport = transport;
|
|
5106
5329
|
this.database = database;
|
|
5107
5330
|
this.onWarning = onWarning;
|
|
5108
5331
|
this.getStreamingTransport = getStreamingTransport;
|
|
5332
|
+
this.store = store;
|
|
5109
5333
|
}
|
|
5110
|
-
async execute(
|
|
5111
|
-
if (typeof
|
|
5112
|
-
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");
|
|
5113
5337
|
}
|
|
5114
5338
|
const prefix = databasePath2(this.database);
|
|
5115
|
-
const path4 = `${prefix}/named-queries/${encodeURIComponent(
|
|
5339
|
+
const path4 = `${prefix}/named-queries/${encodeURIComponent(name)}/query?format=columnar`;
|
|
5340
|
+
const body = {
|
|
5341
|
+
args: args ?? {}
|
|
5342
|
+
};
|
|
5343
|
+
if (options?.orderByIndex !== void 0) {
|
|
5344
|
+
body.orderByIndex = options.orderByIndex;
|
|
5345
|
+
}
|
|
5346
|
+
if (options?.atLeast !== void 0) {
|
|
5347
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5348
|
+
}
|
|
5116
5349
|
const response = await this.transport.post(
|
|
5117
5350
|
path4,
|
|
5118
|
-
|
|
5351
|
+
body,
|
|
5119
5352
|
{ signal: options?.signal }
|
|
5120
5353
|
);
|
|
5121
5354
|
const rows = columnarToRows(response);
|
|
@@ -5123,7 +5356,9 @@ var NamedQueriesApi = class {
|
|
|
5123
5356
|
return {
|
|
5124
5357
|
rows,
|
|
5125
5358
|
stats: response.stats,
|
|
5126
|
-
warnings: response.warnings
|
|
5359
|
+
warnings: response.warnings,
|
|
5360
|
+
totalMatches: response.totalMatches,
|
|
5361
|
+
token: response.token
|
|
5127
5362
|
};
|
|
5128
5363
|
}
|
|
5129
5364
|
async batch(items, options) {
|
|
@@ -5141,6 +5376,9 @@ var NamedQueriesApi = class {
|
|
|
5141
5376
|
400
|
|
5142
5377
|
);
|
|
5143
5378
|
}
|
|
5379
|
+
if (options?.atLeast !== void 0) {
|
|
5380
|
+
this.store?.observe(this.database, options.atLeast);
|
|
5381
|
+
}
|
|
5144
5382
|
const prefix = databasePath2(this.database);
|
|
5145
5383
|
const path4 = `${prefix}/named-queries/batch?format=columnar`;
|
|
5146
5384
|
const envelope = await this.transport.post(
|
|
@@ -5162,33 +5400,42 @@ var NamedQueriesApi = class {
|
|
|
5162
5400
|
data: slot.data ?? [],
|
|
5163
5401
|
rowCount: slot.rowCount ?? 0,
|
|
5164
5402
|
stats: slot.stats ?? emptyStats(),
|
|
5165
|
-
warnings: slot.warnings
|
|
5403
|
+
warnings: slot.warnings,
|
|
5404
|
+
totalMatches: slot.totalMatches,
|
|
5405
|
+
token: slot.token
|
|
5166
5406
|
};
|
|
5167
5407
|
const result = {
|
|
5168
5408
|
rows: columnarToRows(columnar),
|
|
5169
5409
|
stats: columnar.stats,
|
|
5170
|
-
warnings: slot.warnings
|
|
5410
|
+
warnings: slot.warnings,
|
|
5411
|
+
totalMatches: slot.totalMatches,
|
|
5412
|
+
token: slot.token
|
|
5171
5413
|
};
|
|
5172
5414
|
raiseDeprecationWarnings(this.onWarning, slot.warnings);
|
|
5173
5415
|
return { isError: false, result };
|
|
5174
5416
|
});
|
|
5175
5417
|
}
|
|
5176
|
-
subscribe(
|
|
5177
|
-
if (typeof
|
|
5178
|
-
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");
|
|
5179
5421
|
}
|
|
5180
5422
|
const subscription = new TableSubscription(
|
|
5181
5423
|
this.getStreamingTransport(),
|
|
5182
|
-
{ kind: "named",
|
|
5424
|
+
{ kind: "named", name, args, orderByIndex: options.orderByIndex },
|
|
5183
5425
|
{
|
|
5184
5426
|
onSnapshot: options.onSnapshot,
|
|
5185
5427
|
onChange: options.onChange,
|
|
5186
5428
|
onError: options.onError,
|
|
5187
|
-
conflate: options.conflate
|
|
5429
|
+
conflate: options.conflate,
|
|
5430
|
+
atLeast: options.atLeast,
|
|
5431
|
+
waitMs: options.waitMs,
|
|
5432
|
+
onExceeded: options.onExceeded
|
|
5188
5433
|
},
|
|
5189
5434
|
(warnings) => {
|
|
5190
5435
|
raiseDeprecationWarnings(this.onWarning, warnings);
|
|
5191
|
-
}
|
|
5436
|
+
},
|
|
5437
|
+
this.store,
|
|
5438
|
+
this.database
|
|
5192
5439
|
);
|
|
5193
5440
|
subscription.start();
|
|
5194
5441
|
return subscription;
|
|
@@ -5200,12 +5447,12 @@ var NamedMutationsApi = class {
|
|
|
5200
5447
|
this.database = database;
|
|
5201
5448
|
this.onWarning = onWarning;
|
|
5202
5449
|
}
|
|
5203
|
-
async execute(
|
|
5204
|
-
if (typeof
|
|
5205
|
-
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");
|
|
5206
5453
|
}
|
|
5207
5454
|
const prefix = databasePath2(this.database);
|
|
5208
|
-
const path4 = `${prefix}/named-mutations/${encodeURIComponent(
|
|
5455
|
+
const path4 = `${prefix}/named-mutations/${encodeURIComponent(name)}/execute`;
|
|
5209
5456
|
const wire = await this.transport.post(path4, {
|
|
5210
5457
|
args: args ?? {}
|
|
5211
5458
|
});
|
|
@@ -5266,6 +5513,7 @@ var WebSocketTransport = class {
|
|
|
5266
5513
|
// Serialized-send queue: each send appends to this tail.
|
|
5267
5514
|
this._sendTail = Promise.resolve();
|
|
5268
5515
|
this._lastVersion = 0;
|
|
5516
|
+
this._lastToken = null;
|
|
5269
5517
|
this._reconnectAttempt = 0;
|
|
5270
5518
|
this._disposed = false;
|
|
5271
5519
|
this._missedPings = 0;
|
|
@@ -5283,6 +5531,7 @@ var WebSocketTransport = class {
|
|
|
5283
5531
|
this._pingIntervalMs = options.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
5284
5532
|
this._maxMissedHeartbeats = options.maxMissedHeartbeats ?? DEFAULT_MAX_MISSED_HEARTBEATS;
|
|
5285
5533
|
this._enableCompression = options.enableCompression ?? true;
|
|
5534
|
+
this._store = options.consistencyTokenStore;
|
|
5286
5535
|
this._wireMode = options.wireMode ?? "json";
|
|
5287
5536
|
this._authHandler?.setOnAccessTokenRefreshed((token) => {
|
|
5288
5537
|
if (this._handshakeComplete && this._ws?.readyState === WS_READY_STATE_OPEN) {
|
|
@@ -5291,10 +5540,14 @@ var WebSocketTransport = class {
|
|
|
5291
5540
|
});
|
|
5292
5541
|
}
|
|
5293
5542
|
// ─── Public API ────────────────────────────────────────────────────────────
|
|
5294
|
-
/** Latest
|
|
5543
|
+
/** Latest change-event sequence from the most recent server `heartbeat` message. */
|
|
5295
5544
|
get lastVersion() {
|
|
5296
5545
|
return this._lastVersion;
|
|
5297
5546
|
}
|
|
5547
|
+
/** Consistency token from the most recent server `heartbeat` (ADR 0042 D-13). */
|
|
5548
|
+
get lastToken() {
|
|
5549
|
+
return this._lastToken;
|
|
5550
|
+
}
|
|
5298
5551
|
/**
|
|
5299
5552
|
* Registers a handler for incoming server messages with the given channel id.
|
|
5300
5553
|
* Use `"__global__"` to receive broadcast messages that carry no `id`.
|
|
@@ -5482,6 +5735,10 @@ var WebSocketTransport = class {
|
|
|
5482
5735
|
}
|
|
5483
5736
|
case "heartbeat":
|
|
5484
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
|
+
}
|
|
5485
5742
|
break;
|
|
5486
5743
|
case "pong":
|
|
5487
5744
|
this._missedPings = 0;
|
|
@@ -5647,16 +5904,21 @@ var LongPollTransport = class {
|
|
|
5647
5904
|
this._connected = false;
|
|
5648
5905
|
this._pollTask = null;
|
|
5649
5906
|
this._lastVersion = 0;
|
|
5907
|
+
this._lastToken = null;
|
|
5650
5908
|
this._serverUrl = serverUrl;
|
|
5651
5909
|
this._database = database;
|
|
5652
5910
|
this._authHandler = options.authHandler;
|
|
5653
5911
|
this._onReconnected = options.onReconnected;
|
|
5654
5912
|
this._waitMs = Math.max(1, options.waitMs ?? DEFAULT_WAIT_MS);
|
|
5655
5913
|
this._fetch = options.fetchImpl ?? localNetworkFetch;
|
|
5914
|
+
this._store = options.consistencyTokenStore;
|
|
5656
5915
|
}
|
|
5657
5916
|
get lastVersion() {
|
|
5658
5917
|
return this._lastVersion;
|
|
5659
5918
|
}
|
|
5919
|
+
get lastToken() {
|
|
5920
|
+
return this._lastToken;
|
|
5921
|
+
}
|
|
5660
5922
|
registerHandler(id, handler) {
|
|
5661
5923
|
this._handlers.set(id, handler);
|
|
5662
5924
|
}
|
|
@@ -5779,6 +6041,10 @@ var LongPollTransport = class {
|
|
|
5779
6041
|
for (const msg of payload.messages) {
|
|
5780
6042
|
if (msg.type === "heartbeat") {
|
|
5781
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
|
+
}
|
|
5782
6048
|
}
|
|
5783
6049
|
const id = "id" in msg ? msg.id : void 0;
|
|
5784
6050
|
if (id !== void 0 && id !== null) {
|
|
@@ -5858,6 +6124,9 @@ var FallbackStreamingTransport = class {
|
|
|
5858
6124
|
get lastVersion() {
|
|
5859
6125
|
return this._active.lastVersion;
|
|
5860
6126
|
}
|
|
6127
|
+
get lastToken() {
|
|
6128
|
+
return this._active.lastToken;
|
|
6129
|
+
}
|
|
5861
6130
|
registerHandler(id, handler) {
|
|
5862
6131
|
this._handlers.set(id, handler);
|
|
5863
6132
|
this._active.registerHandler(id, handler);
|
|
@@ -5937,6 +6206,7 @@ var AoudaClient = class {
|
|
|
5937
6206
|
this.baseUrl = normalizeBaseUrl(options.serverUrl);
|
|
5938
6207
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
5939
6208
|
this.database = options.database.trim();
|
|
6209
|
+
this._store = options.consistencyTokenStore ?? new MemoryConsistencyTokenStore();
|
|
5940
6210
|
if (!Number.isFinite(this.timeout) || this.timeout <= 0) {
|
|
5941
6211
|
throw new Error("timeout must be a finite positive number");
|
|
5942
6212
|
}
|
|
@@ -5971,7 +6241,9 @@ var AoudaClient = class {
|
|
|
5971
6241
|
}
|
|
5972
6242
|
const httpTransport = new HttpTransport({
|
|
5973
6243
|
baseUrl: this.baseUrl,
|
|
5974
|
-
timeout: this.timeout
|
|
6244
|
+
timeout: this.timeout,
|
|
6245
|
+
database: this.database,
|
|
6246
|
+
consistencyTokenStore: this._store
|
|
5975
6247
|
});
|
|
5976
6248
|
const activeAuth = options.serverAuth ?? options.appAuth;
|
|
5977
6249
|
if (activeAuth) {
|
|
@@ -6031,7 +6303,8 @@ var AoudaClient = class {
|
|
|
6031
6303
|
this.transport,
|
|
6032
6304
|
this.database,
|
|
6033
6305
|
onNamedArtifactWarning,
|
|
6034
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6306
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6307
|
+
this._store
|
|
6035
6308
|
);
|
|
6036
6309
|
this._namedMutations = new NamedMutationsApi(
|
|
6037
6310
|
this.transport,
|
|
@@ -6130,7 +6403,8 @@ var AoudaClient = class {
|
|
|
6130
6403
|
name,
|
|
6131
6404
|
this.database,
|
|
6132
6405
|
void 0,
|
|
6133
|
-
() => this._getOrCreateWebSocketTransport()
|
|
6406
|
+
() => this._getOrCreateWebSocketTransport(),
|
|
6407
|
+
this._store
|
|
6134
6408
|
);
|
|
6135
6409
|
}
|
|
6136
6410
|
/**
|
|
@@ -6182,13 +6456,26 @@ var AoudaClient = class {
|
|
|
6182
6456
|
return this._materializedQueries;
|
|
6183
6457
|
}
|
|
6184
6458
|
/**
|
|
6185
|
-
*
|
|
6459
|
+
* Named-query execute, read-only batch, and subscribe by unique schema name.
|
|
6186
6460
|
*/
|
|
6187
6461
|
get namedQueries() {
|
|
6188
6462
|
return this._namedQueries;
|
|
6189
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
|
+
}
|
|
6190
6477
|
/**
|
|
6191
|
-
*
|
|
6478
|
+
* Named-mutation execute by unique schema name. No batch.
|
|
6192
6479
|
*/
|
|
6193
6480
|
get namedMutations() {
|
|
6194
6481
|
return this._namedMutations;
|
|
@@ -6315,13 +6602,15 @@ var AoudaClient = class {
|
|
|
6315
6602
|
const primary = new WebSocketTransport(this.baseUrl, this.database, {
|
|
6316
6603
|
authHandler: this._authHandler,
|
|
6317
6604
|
enableCompression: this._streamingEnableCompression,
|
|
6318
|
-
wireMode: this._streamingWireMode
|
|
6605
|
+
wireMode: this._streamingWireMode,
|
|
6606
|
+
consistencyTokenStore: this._store
|
|
6319
6607
|
});
|
|
6320
6608
|
if (this._streamingEnableLongPollFallback) {
|
|
6321
6609
|
this._wsTransport = new FallbackStreamingTransport(primary, () => {
|
|
6322
6610
|
return new LongPollTransport(this.baseUrl, this.database, {
|
|
6323
6611
|
authHandler: this._authHandler,
|
|
6324
|
-
waitMs: this._streamingLongPollWaitMs
|
|
6612
|
+
waitMs: this._streamingLongPollWaitMs,
|
|
6613
|
+
consistencyTokenStore: this._store
|
|
6325
6614
|
});
|
|
6326
6615
|
});
|
|
6327
6616
|
} else {
|
|
@@ -6347,7 +6636,7 @@ Usage:
|
|
|
6347
6636
|
npx @aouda/client schema <command> [options]
|
|
6348
6637
|
|
|
6349
6638
|
Commands:
|
|
6350
|
-
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)
|
|
6351
6640
|
schema Schema management (diff, apply, export, validate, history, seed)
|
|
6352
6641
|
diff Show migration plan (desired vs current)
|
|
6353
6642
|
apply Apply schema (use --allow-destructive for drops; --dry-run to preview)
|