@layers/amba-web 4.0.8 → 4.0.9
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/index.browser.d.ts +89 -9
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +287 -53
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +89 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +286 -41
- package/dist/index.js.map +1 -1
- package/dist-rn/index.d.ts +89 -9
- package/dist-rn/index.js +286 -41
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2,28 +2,46 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Browser localStorage adapter for SDK identity persistence.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* (eventual) identity cache.
|
|
5
|
+
* Browsers can deny or throw on localStorage access (privacy mode, sandboxed
|
|
6
|
+
* iframes, quota exhaustion). Persistence is best-effort: storage failures
|
|
7
|
+
* must never turn a successful auth/network operation into an SDK failure.
|
|
9
8
|
*/
|
|
10
9
|
var LocalStoragePersistence = class {
|
|
11
10
|
constructor(prefix) {
|
|
12
11
|
this.prefix = prefix;
|
|
13
12
|
}
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
get storage() {
|
|
14
|
+
try {
|
|
15
|
+
return globalThis.localStorage ?? null;
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
get available() {
|
|
21
|
+
return this.storage !== null;
|
|
22
|
+
}
|
|
16
23
|
read(key) {
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
const storage = this.storage;
|
|
25
|
+
if (!storage) return null;
|
|
26
|
+
try {
|
|
27
|
+
return storage.getItem(`${this.prefix}:${key}`);
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
19
31
|
}
|
|
20
32
|
write(key, value) {
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
const storage = this.storage;
|
|
34
|
+
if (!storage) return;
|
|
35
|
+
try {
|
|
36
|
+
storage.setItem(`${this.prefix}:${key}`, value);
|
|
37
|
+
} catch {}
|
|
23
38
|
}
|
|
24
39
|
delete(key) {
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
const storage = this.storage;
|
|
41
|
+
if (!storage) return;
|
|
42
|
+
try {
|
|
43
|
+
storage.removeItem(`${this.prefix}:${key}`);
|
|
44
|
+
} catch {}
|
|
27
45
|
}
|
|
28
46
|
};
|
|
29
47
|
|
|
@@ -1340,11 +1358,10 @@ const DEFAULT_API_URL = "https://api.amba.dev";
|
|
|
1340
1358
|
/**
|
|
1341
1359
|
* Default host that serves deployed functions. `Amba.functions.invoke(name)`
|
|
1342
1360
|
* targets `https://<projectId>.<DEFAULT_FUNCTIONS_HOST>/<name>` unless a
|
|
1343
|
-
* `functionsBaseUrl` override is configured.
|
|
1344
|
-
* server-resolved id (from `diagnostics.ping`), which the function router
|
|
1345
|
-
* accepts directly.
|
|
1361
|
+
* `functionsBaseUrl` override is configured.
|
|
1346
1362
|
*/
|
|
1347
1363
|
const DEFAULT_FUNCTIONS_HOST = "fn.amba.host";
|
|
1364
|
+
const PROJECT_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1348
1365
|
/**
|
|
1349
1366
|
* Internal state — one instance per page. Created lazily by `Amba.configure()`.
|
|
1350
1367
|
*/
|
|
@@ -1366,15 +1383,73 @@ let _configuredProjectId = null;
|
|
|
1366
1383
|
let _configuredApiUrl = DEFAULT_API_URL;
|
|
1367
1384
|
let _configuredClientKey = null;
|
|
1368
1385
|
let _currentSessionToken = null;
|
|
1386
|
+
let _currentRefreshToken = null;
|
|
1387
|
+
let _currentSessionExpiresAt = null;
|
|
1388
|
+
let _currentUser = null;
|
|
1389
|
+
const BROWSER_IDENTITY_VERSION = 1;
|
|
1390
|
+
const DEFAULT_SESSION_TTL_MS = 3600 * 1e3;
|
|
1391
|
+
function identityStorageKey(projectId) {
|
|
1392
|
+
return `identity:v${BROWSER_IDENTITY_VERSION}:project:${encodeURIComponent(projectId)}`;
|
|
1393
|
+
}
|
|
1394
|
+
function isNonEmptyString(value) {
|
|
1395
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1396
|
+
}
|
|
1397
|
+
function containsControlCharacter(value) {
|
|
1398
|
+
return Array.from(value).some((char) => {
|
|
1399
|
+
const code = char.charCodeAt(0);
|
|
1400
|
+
return code <= 31 || code === 127;
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
/** Read + validate a project-bound identity snapshot. Corrupt or cross-project
|
|
1404
|
+
* data is removed instead of being handed to the core. */
|
|
1405
|
+
function readPersistedIdentity(persistence, projectId) {
|
|
1406
|
+
const key = identityStorageKey(projectId);
|
|
1407
|
+
const raw = persistence.read(key);
|
|
1408
|
+
if (!raw) return null;
|
|
1409
|
+
try {
|
|
1410
|
+
const value = JSON.parse(raw);
|
|
1411
|
+
const hasTokens = value.session_token != null || value.refresh_token != null;
|
|
1412
|
+
if (value.version !== BROWSER_IDENTITY_VERSION || value.project_id !== projectId || !isNonEmptyString(value.anonymous_id) || hasTokens && !isNonEmptyString(value.app_user_id) || value.session_token != null && !isNonEmptyString(value.refresh_token) || value.session_token != null && !isNonEmptyString(value.session_token) || value.refresh_token != null && !isNonEmptyString(value.refresh_token) || value.expires_at != null && (!isNonEmptyString(value.expires_at) || !Number.isFinite(Date.parse(value.expires_at)))) throw new Error("invalid identity snapshot");
|
|
1413
|
+
const expiresAt = isNonEmptyString(value.expires_at) ? Date.parse(value.expires_at) : NaN;
|
|
1414
|
+
const sessionExpired = value.session_token != null && Number.isFinite(expiresAt) && expiresAt <= Date.now();
|
|
1415
|
+
return {
|
|
1416
|
+
version: BROWSER_IDENTITY_VERSION,
|
|
1417
|
+
project_id: projectId,
|
|
1418
|
+
anonymous_id: value.anonymous_id,
|
|
1419
|
+
app_user_id: isNonEmptyString(value.app_user_id) ? value.app_user_id : null,
|
|
1420
|
+
session_token: sessionExpired ? null : value.session_token ?? null,
|
|
1421
|
+
refresh_token: value.refresh_token ?? null,
|
|
1422
|
+
expires_at: sessionExpired ? null : value.expires_at ?? null,
|
|
1423
|
+
user: value.user && typeof value.user === "object" && isNonEmptyString(value.user.id) ? value.user : null
|
|
1424
|
+
};
|
|
1425
|
+
} catch {
|
|
1426
|
+
persistence.delete(key);
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
function writeIdentitySnapshot() {
|
|
1431
|
+
if (!_persistence?.available || !_configuredProjectId || !coreInstance) return;
|
|
1432
|
+
const snapshot = {
|
|
1433
|
+
version: BROWSER_IDENTITY_VERSION,
|
|
1434
|
+
project_id: _configuredProjectId,
|
|
1435
|
+
anonymous_id: coreInstance.anonymousId(),
|
|
1436
|
+
app_user_id: coreInstance.appUserId() ?? null,
|
|
1437
|
+
session_token: _currentSessionToken,
|
|
1438
|
+
refresh_token: _currentRefreshToken,
|
|
1439
|
+
expires_at: _currentSessionExpiresAt,
|
|
1440
|
+
user: _currentUser
|
|
1441
|
+
};
|
|
1442
|
+
_persistence.write(identityStorageKey(_configuredProjectId), JSON.stringify(snapshot));
|
|
1443
|
+
}
|
|
1369
1444
|
/**
|
|
1370
1445
|
* Functions invocation state. `_configuredFunctionsBaseUrl` is the optional
|
|
1371
|
-
* override from `Amba.configure({ functionsBaseUrl })`.
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
* round-trip. Both reset on every `configure()`.
|
|
1446
|
+
* override from `Amba.configure({ functionsBaseUrl })`. The default-host path
|
|
1447
|
+
* caches its resolved project id and shares an in-flight diagnostics fallback
|
|
1448
|
+
* across concurrent invokes. All three reset on every `configure()`.
|
|
1375
1449
|
*/
|
|
1376
1450
|
let _configuredFunctionsBaseUrl = null;
|
|
1377
1451
|
let _resolvedFunctionsProjectId = null;
|
|
1452
|
+
let _functionsProjectIdInflight = null;
|
|
1378
1453
|
/**
|
|
1379
1454
|
* Offline-resilience state. `_persistence` is the localStorage-backed store
|
|
1380
1455
|
* captured at configure-time; `_offlineQueue` is lazily built the first time
|
|
@@ -1442,7 +1517,7 @@ async function replayOutboxOp(op) {
|
|
|
1442
1517
|
switch (op.kind) {
|
|
1443
1518
|
case "collection.insert":
|
|
1444
1519
|
await coreCall((c) => c.collectionsInsert(op.collection, encodeJson({
|
|
1445
|
-
...op.payload
|
|
1520
|
+
...op.payload,
|
|
1446
1521
|
idempotency_key: op.idempotencyKey
|
|
1447
1522
|
})));
|
|
1448
1523
|
return;
|
|
@@ -1563,12 +1638,12 @@ function toWireTransactionOp(op) {
|
|
|
1563
1638
|
return wire;
|
|
1564
1639
|
}
|
|
1565
1640
|
function snapshotSession(user) {
|
|
1566
|
-
if (!user) return null;
|
|
1641
|
+
if (!user || !_currentSessionToken) return null;
|
|
1567
1642
|
return {
|
|
1568
|
-
sessionToken:
|
|
1569
|
-
refreshToken: "",
|
|
1643
|
+
sessionToken: _currentSessionToken,
|
|
1644
|
+
refreshToken: _currentRefreshToken ?? "",
|
|
1570
1645
|
user,
|
|
1571
|
-
expiresAt: ""
|
|
1646
|
+
expiresAt: _currentSessionExpiresAt ?? ""
|
|
1572
1647
|
};
|
|
1573
1648
|
}
|
|
1574
1649
|
function notifyAuthSubscribers(session) {
|
|
@@ -1579,7 +1654,11 @@ function notifyAuthSubscribers(session) {
|
|
|
1579
1654
|
}
|
|
1580
1655
|
}
|
|
1581
1656
|
async function notifyFromAuthResult(result) {
|
|
1582
|
-
|
|
1657
|
+
_currentSessionToken = result.session_token;
|
|
1658
|
+
_currentRefreshToken = result.refresh_token;
|
|
1659
|
+
_currentSessionExpiresAt = result.expires_at && Number.isFinite(Date.parse(result.expires_at)) ? result.expires_at : new Date(Date.now() + DEFAULT_SESSION_TTL_MS).toISOString();
|
|
1660
|
+
_currentUser = result.user;
|
|
1661
|
+
writeIdentitySnapshot();
|
|
1583
1662
|
notifyAuthSubscribers(snapshotSession(result.user));
|
|
1584
1663
|
}
|
|
1585
1664
|
/**
|
|
@@ -1626,22 +1705,156 @@ function buildAiStreamRequest(path, request) {
|
|
|
1626
1705
|
/**
|
|
1627
1706
|
* Resolve the full invocation URL for a deployed function.
|
|
1628
1707
|
*
|
|
1629
|
-
*
|
|
1630
|
-
*
|
|
1631
|
-
*
|
|
1632
|
-
*
|
|
1633
|
-
* project id as the host label directly.
|
|
1708
|
+
* Resolution checks `functionsBaseUrl` first, then uses a UUID-shaped
|
|
1709
|
+
* configured project id directly, and finally falls back to a deduped
|
|
1710
|
+
* `diagnostics.ping` for the authoritative server-side project id. The
|
|
1711
|
+
* resolved default-host id is cached for subsequent invokes.
|
|
1634
1712
|
*/
|
|
1635
1713
|
async function resolveFunctionUrl(name) {
|
|
1636
1714
|
if (_configuredFunctionsBaseUrl) return `${_configuredFunctionsBaseUrl.replace(/\/$/, "")}/${encodeURIComponent(name)}`;
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1715
|
+
return `https://${await resolveFunctionsProjectId()}.${DEFAULT_FUNCTIONS_HOST}/${encodeURIComponent(name)}`;
|
|
1716
|
+
}
|
|
1717
|
+
async function resolveFunctionsProjectId() {
|
|
1718
|
+
if (_resolvedFunctionsProjectId) return _resolvedFunctionsProjectId;
|
|
1719
|
+
if (_configuredProjectId && PROJECT_ID_PATTERN.test(_configuredProjectId)) {
|
|
1720
|
+
_resolvedFunctionsProjectId = _configuredProjectId.toLowerCase();
|
|
1721
|
+
return _resolvedFunctionsProjectId;
|
|
1641
1722
|
}
|
|
1642
|
-
|
|
1723
|
+
if (!_functionsProjectIdInflight) {
|
|
1724
|
+
const configuredProjectId = _configuredProjectId;
|
|
1725
|
+
const resolution = (async () => {
|
|
1726
|
+
const ping = await Amba.diagnostics.ping();
|
|
1727
|
+
if (!ping.ok || !ping.server_project_id) throw new AmbaApiError("FUNCTIONS_HOST_UNRESOLVED", "Could not resolve the functions host for this project. Pass `functionsBaseUrl` to Amba.configure() to invoke functions explicitly.", ping);
|
|
1728
|
+
if (_configuredProjectId === configuredProjectId && !_configuredFunctionsBaseUrl) _resolvedFunctionsProjectId = ping.server_project_id;
|
|
1729
|
+
return ping.server_project_id;
|
|
1730
|
+
})();
|
|
1731
|
+
_functionsProjectIdInflight = resolution;
|
|
1732
|
+
resolution.then(() => {
|
|
1733
|
+
if (_functionsProjectIdInflight === resolution) _functionsProjectIdInflight = null;
|
|
1734
|
+
}, () => {
|
|
1735
|
+
if (_functionsProjectIdInflight === resolution) _functionsProjectIdInflight = null;
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
return _functionsProjectIdInflight;
|
|
1643
1739
|
}
|
|
1644
1740
|
/**
|
|
1741
|
+
* Immutable browser collection scope for a server-verified group context.
|
|
1742
|
+
* Each method carries its own `groupId` into the Rust request path; no mutable
|
|
1743
|
+
* global header state is used, so parallel group A/group B calls cannot leak.
|
|
1744
|
+
*
|
|
1745
|
+
* Group-scoped writes deliberately bypass the global offline outbox. Replaying
|
|
1746
|
+
* a queued group mutation without its membership context would be unsafe;
|
|
1747
|
+
* callers receive the real network outcome and can retry in the same scope.
|
|
1748
|
+
*/
|
|
1749
|
+
var AmbaGroupScopedClient = class AmbaGroupScopedClient {
|
|
1750
|
+
groupId;
|
|
1751
|
+
constructor(groupId) {
|
|
1752
|
+
const normalized = groupId.trim();
|
|
1753
|
+
if (!normalized || containsControlCharacter(normalized)) throw new AmbaApiError("VALIDATION_ERROR", "Amba.asGroup: groupId must be non-empty and contain no control characters");
|
|
1754
|
+
this.groupId = normalized;
|
|
1755
|
+
}
|
|
1756
|
+
asGroup(groupId) {
|
|
1757
|
+
return new AmbaGroupScopedClient(groupId);
|
|
1758
|
+
}
|
|
1759
|
+
inGroup(groupId) {
|
|
1760
|
+
return this.asGroup(groupId);
|
|
1761
|
+
}
|
|
1762
|
+
collection(name) {
|
|
1763
|
+
const groupId = this.groupId;
|
|
1764
|
+
return new CollectionSubscription({
|
|
1765
|
+
baseUrl: _configuredApiUrl,
|
|
1766
|
+
authHeaders: () => {
|
|
1767
|
+
const headers = realtimeAuthHeaders();
|
|
1768
|
+
return headers ? {
|
|
1769
|
+
...headers,
|
|
1770
|
+
"X-Group-Context": groupId
|
|
1771
|
+
} : null;
|
|
1772
|
+
}
|
|
1773
|
+
}, name);
|
|
1774
|
+
}
|
|
1775
|
+
collections = {
|
|
1776
|
+
find: async (name, options = {}) => await coreCall((c) => c.collectionsFind(name, encodeJson(options), this.groupId)),
|
|
1777
|
+
findOne: async (name, id) => await coreCall((c) => c.collectionsFindOne(name, id, this.groupId)),
|
|
1778
|
+
insert: async (name, row) => await coreCall((c) => c.collectionsInsert(name, encodeJson(row), this.groupId)),
|
|
1779
|
+
update: async (name, id, set) => await coreCall((c) => c.collectionsUpdate(name, id, encodeJson(set), this.groupId)),
|
|
1780
|
+
delete: async (name, id) => await coreCall((c) => c.collectionsDelete(name, id, this.groupId)),
|
|
1781
|
+
upsert: async (name, row, options) => await coreCall((c) => c.collectionsUpsert(name, encodeJson(row), encodeJson({
|
|
1782
|
+
on_conflict: options.onConflict,
|
|
1783
|
+
conflict_target: options.conflictTarget
|
|
1784
|
+
}), this.groupId)),
|
|
1785
|
+
deleteWhere: async (name, filter) => await coreCall((c) => c.collectionsDeleteWhere(name, encodeJson(filter), this.groupId)),
|
|
1786
|
+
restore: async (name, id) => await coreCall((c) => c.collectionsRestore(name, id, this.groupId)),
|
|
1787
|
+
transaction: async (operations) => {
|
|
1788
|
+
return (await coreCall((c) => c.collectionsTransaction(encodeJson(operations.map(toWireTransactionOp)), this.groupId))).data;
|
|
1789
|
+
},
|
|
1790
|
+
findNearest: async (name, options) => await coreCall((c) => c.collectionsFindNearest(name, encodeJson(options), this.groupId)),
|
|
1791
|
+
count: async (name, filter) => await coreCall((c) => c.collectionsCount(name, filter ? encodeJson(filter) : void 0, this.groupId)),
|
|
1792
|
+
optimisticInsert: async (name, row, view) => withOptimistic({
|
|
1793
|
+
apply: view.apply,
|
|
1794
|
+
mutate: () => coreCall((c) => c.collectionsInsert(name, encodeJson(row), this.groupId)),
|
|
1795
|
+
rollback: view.rollback
|
|
1796
|
+
}),
|
|
1797
|
+
optimisticUpdate: async (name, id, set, view) => withOptimistic({
|
|
1798
|
+
apply: view.apply,
|
|
1799
|
+
mutate: () => coreCall((c) => c.collectionsUpdate(name, id, encodeJson(set), this.groupId)),
|
|
1800
|
+
rollback: view.rollback
|
|
1801
|
+
}),
|
|
1802
|
+
optimisticDelete: async (name, id, view) => withOptimistic({
|
|
1803
|
+
apply: view.apply,
|
|
1804
|
+
mutate: () => coreCall((c) => c.collectionsDelete(name, id, this.groupId)),
|
|
1805
|
+
rollback: view.rollback
|
|
1806
|
+
}),
|
|
1807
|
+
where: {
|
|
1808
|
+
eq: (column, value) => ({
|
|
1809
|
+
column,
|
|
1810
|
+
op: "eq",
|
|
1811
|
+
value
|
|
1812
|
+
}),
|
|
1813
|
+
ne: (column, value) => ({
|
|
1814
|
+
column,
|
|
1815
|
+
op: "ne",
|
|
1816
|
+
value
|
|
1817
|
+
}),
|
|
1818
|
+
gt: (column, value) => ({
|
|
1819
|
+
column,
|
|
1820
|
+
op: "gt",
|
|
1821
|
+
value
|
|
1822
|
+
}),
|
|
1823
|
+
gte: (column, value) => ({
|
|
1824
|
+
column,
|
|
1825
|
+
op: "gte",
|
|
1826
|
+
value
|
|
1827
|
+
}),
|
|
1828
|
+
lt: (column, value) => ({
|
|
1829
|
+
column,
|
|
1830
|
+
op: "lt",
|
|
1831
|
+
value
|
|
1832
|
+
}),
|
|
1833
|
+
lte: (column, value) => ({
|
|
1834
|
+
column,
|
|
1835
|
+
op: "lte",
|
|
1836
|
+
value
|
|
1837
|
+
}),
|
|
1838
|
+
in: (column, values) => ({
|
|
1839
|
+
column,
|
|
1840
|
+
op: "in",
|
|
1841
|
+
value: values
|
|
1842
|
+
}),
|
|
1843
|
+
isNull: (column) => ({
|
|
1844
|
+
column,
|
|
1845
|
+
op: "is_null"
|
|
1846
|
+
}),
|
|
1847
|
+
isNotNull: (column) => ({
|
|
1848
|
+
column,
|
|
1849
|
+
op: "is_not_null"
|
|
1850
|
+
}),
|
|
1851
|
+
and: (...filters) => ({ and: filters }),
|
|
1852
|
+
or: (...filters) => ({ or: filters }),
|
|
1853
|
+
not: (filter) => ({ not: filter })
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
};
|
|
1857
|
+
/**
|
|
1645
1858
|
* Top-level SDK namespace.
|
|
1646
1859
|
*
|
|
1647
1860
|
* Stateless from the JS side — all state lives in the SDK runtime. Calling
|
|
@@ -1670,7 +1883,7 @@ const Amba = {
|
|
|
1670
1883
|
} else await initCore();
|
|
1671
1884
|
}
|
|
1672
1885
|
const persistence = new LocalStoragePersistence(config.storagePrefix ?? "amba");
|
|
1673
|
-
persistence.
|
|
1886
|
+
const restoredIdentity = readPersistedIdentity(persistence, config.projectId);
|
|
1674
1887
|
let nextCore;
|
|
1675
1888
|
try {
|
|
1676
1889
|
const { wasmClass } = await getCoreRuntime();
|
|
@@ -1683,6 +1896,13 @@ const Amba = {
|
|
|
1683
1896
|
consent_required: config.consentRequired,
|
|
1684
1897
|
debug: config.debug
|
|
1685
1898
|
}), globalThis.fetch.bind(globalThis));
|
|
1899
|
+
if (restoredIdentity) nextCore.hydrateIdentity(encodeJson({
|
|
1900
|
+
anonymous_id: restoredIdentity.anonymous_id,
|
|
1901
|
+
app_user_id: restoredIdentity.app_user_id,
|
|
1902
|
+
session_token: restoredIdentity.session_token,
|
|
1903
|
+
refresh_token: restoredIdentity.refresh_token,
|
|
1904
|
+
expires_at: restoredIdentity.expires_at
|
|
1905
|
+
}));
|
|
1686
1906
|
} catch (err) {
|
|
1687
1907
|
throw toAmbaApiError(err);
|
|
1688
1908
|
}
|
|
@@ -1692,8 +1912,15 @@ const Amba = {
|
|
|
1692
1912
|
_configuredProjectId = config.projectId;
|
|
1693
1913
|
_configuredApiUrl = config.apiUrl ?? DEFAULT_API_URL;
|
|
1694
1914
|
_configuredClientKey = config.clientKey;
|
|
1915
|
+
_currentSessionToken = nextCore.isAuthenticated() ? restoredIdentity?.session_token ?? null : null;
|
|
1916
|
+
_currentRefreshToken = restoredIdentity?.refresh_token ?? null;
|
|
1917
|
+
_currentSessionExpiresAt = nextCore.isAuthenticated() ? restoredIdentity?.expires_at ?? null : null;
|
|
1918
|
+
_currentUser = nextCore.isAuthenticated() ? restoredIdentity?.user ?? null : null;
|
|
1695
1919
|
_configuredFunctionsBaseUrl = config.functionsBaseUrl ?? null;
|
|
1696
1920
|
_resolvedFunctionsProjectId = null;
|
|
1921
|
+
_functionsProjectIdInflight = null;
|
|
1922
|
+
if (!_configuredFunctionsBaseUrl && !PROJECT_ID_PATTERN.test(config.projectId)) resolveFunctionsProjectId().catch(() => {});
|
|
1923
|
+
writeIdentitySnapshot();
|
|
1697
1924
|
},
|
|
1698
1925
|
get projectId() {
|
|
1699
1926
|
if (!_configuredProjectId) throw new AmbaApiError("NOT_INITIALIZED", "amba SDK not configured. Call Amba.configure({ projectId, clientKey }) at app start before any other API.");
|
|
@@ -1846,6 +2073,10 @@ const Amba = {
|
|
|
1846
2073
|
signOut: async (rotateAnonymousId = false) => {
|
|
1847
2074
|
await coreCall((c) => c.signOut(rotateAnonymousId));
|
|
1848
2075
|
_currentSessionToken = null;
|
|
2076
|
+
_currentRefreshToken = null;
|
|
2077
|
+
_currentSessionExpiresAt = null;
|
|
2078
|
+
_currentUser = null;
|
|
2079
|
+
writeIdentitySnapshot();
|
|
1849
2080
|
notifyAuthSubscribers(null);
|
|
1850
2081
|
},
|
|
1851
2082
|
refresh: async () => {
|
|
@@ -1854,11 +2085,17 @@ const Amba = {
|
|
|
1854
2085
|
return r;
|
|
1855
2086
|
},
|
|
1856
2087
|
me: async () => {
|
|
1857
|
-
|
|
2088
|
+
const user = await coreCall((c) => c.me());
|
|
2089
|
+
_currentUser = user;
|
|
2090
|
+
writeIdentitySnapshot();
|
|
2091
|
+
return user;
|
|
1858
2092
|
},
|
|
1859
2093
|
getSession: async () => {
|
|
1860
2094
|
if (!requireCore().isAuthenticated()) return null;
|
|
1861
|
-
|
|
2095
|
+
const user = await coreCall((c) => c.me());
|
|
2096
|
+
_currentUser = user;
|
|
2097
|
+
writeIdentitySnapshot();
|
|
2098
|
+
return snapshotSession(user);
|
|
1862
2099
|
},
|
|
1863
2100
|
getAnonymousId: async () => {
|
|
1864
2101
|
return requireCore().anonymousId();
|
|
@@ -1889,6 +2126,14 @@ const Amba = {
|
|
|
1889
2126
|
await coreCall((c) => c.sessionsRevoke(sessionId));
|
|
1890
2127
|
}
|
|
1891
2128
|
},
|
|
2129
|
+
asGroup: (groupId) => {
|
|
2130
|
+
requireCore();
|
|
2131
|
+
return new AmbaGroupScopedClient(groupId);
|
|
2132
|
+
},
|
|
2133
|
+
inGroup: (groupId) => {
|
|
2134
|
+
requireCore();
|
|
2135
|
+
return new AmbaGroupScopedClient(groupId);
|
|
2136
|
+
},
|
|
1892
2137
|
collection: (name) => new CollectionSubscription({
|
|
1893
2138
|
baseUrl: _configuredApiUrl,
|
|
1894
2139
|
authHeaders: realtimeAuthHeaders
|
|
@@ -2227,7 +2472,7 @@ const Amba = {
|
|
|
2227
2472
|
const method = options?.method ?? "POST";
|
|
2228
2473
|
const headers = {
|
|
2229
2474
|
"X-Api-Key": _configuredClientKey,
|
|
2230
|
-
...options?.headers
|
|
2475
|
+
...options?.headers
|
|
2231
2476
|
};
|
|
2232
2477
|
if (_currentSessionToken) headers["Authorization"] = `Bearer ${_currentSessionToken}`;
|
|
2233
2478
|
let requestBody;
|
|
@@ -2438,8 +2683,8 @@ function getCoreWasm() {
|
|
|
2438
2683
|
* `verify-sdk-version-coherence` GH action gates every publish on the
|
|
2439
2684
|
* pair agreeing (and matching the `web-v<X.Y.Z>` tag when tag-triggered).
|
|
2440
2685
|
*/
|
|
2441
|
-
const SDK_VERSION = "4.0.
|
|
2686
|
+
const SDK_VERSION = "4.0.9";
|
|
2442
2687
|
|
|
2443
2688
|
//#endregion
|
|
2444
|
-
export { Amba, AmbaApiError, CollectionSubscription, ConversationSubscription, GamificationSubscription, SDK_VERSION, getCoreWasm, withOptimistic };
|
|
2689
|
+
export { Amba, AmbaApiError, AmbaGroupScopedClient, CollectionSubscription, ConversationSubscription, GamificationSubscription, SDK_VERSION, getCoreWasm, withOptimistic };
|
|
2445
2690
|
//# sourceMappingURL=index.js.map
|