@pollar/core 0.9.0-rc.0 → 0.9.0-rc.2
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/README.md +35 -0
- package/dist/index.d.mts +56 -3
- package/dist/index.d.ts +56 -3
- package/dist/index.js +118 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +118 -107
- package/dist/index.mjs.map +1 -1
- package/dist/index.rn.d.mts +1 -1
- package/dist/index.rn.d.ts +1 -1
- package/dist/index.rn.js +118 -107
- package/dist/index.rn.js.map +1 -1
- package/dist/index.rn.mjs +118 -108
- package/dist/index.rn.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.rn.mjs
CHANGED
|
@@ -302,7 +302,6 @@ var NobleKeyManager = class {
|
|
|
302
302
|
if (this.privateKey) return;
|
|
303
303
|
if (!this._initPromise) {
|
|
304
304
|
this._initPromise = this._doInit().catch((err) => {
|
|
305
|
-
console.error("[PollarClient:keys] NobleKeyManager init failed", err);
|
|
306
305
|
this._initPromise = null;
|
|
307
306
|
throw err;
|
|
308
307
|
});
|
|
@@ -1010,6 +1009,16 @@ function normalizeHtu(rawUrl) {
|
|
|
1010
1009
|
return `${scheme}//${host}${portPart}${url.pathname}`;
|
|
1011
1010
|
}
|
|
1012
1011
|
|
|
1012
|
+
// src/lib/logger.ts
|
|
1013
|
+
var RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
|
|
1014
|
+
function createLogger(level = "info", sink = console) {
|
|
1015
|
+
const threshold = RANK[level];
|
|
1016
|
+
const gate = (lvl) => (...args) => {
|
|
1017
|
+
if (threshold >= RANK[lvl]) sink[lvl](...args);
|
|
1018
|
+
};
|
|
1019
|
+
return { error: gate("error"), warn: gate("warn"), info: gate("info"), debug: gate("debug") };
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1013
1022
|
// src/storage/web.ts
|
|
1014
1023
|
var LOG_PREFIX = "[PollarClient:storage]";
|
|
1015
1024
|
function createMemoryAdapter() {
|
|
@@ -1033,7 +1042,7 @@ function createLocalStorageAdapter(options = {}) {
|
|
|
1033
1042
|
function degrade(reason, error) {
|
|
1034
1043
|
if (degraded) return;
|
|
1035
1044
|
degraded = true;
|
|
1036
|
-
console.warn(`${LOG_PREFIX} localStorage unavailable (${reason}); degrading to in-memory storage`);
|
|
1045
|
+
(options.logger ?? console).warn(`${LOG_PREFIX} localStorage unavailable (${reason}); degrading to in-memory storage`);
|
|
1037
1046
|
options.onDegrade?.(reason, error);
|
|
1038
1047
|
}
|
|
1039
1048
|
return {
|
|
@@ -1098,7 +1107,7 @@ function defaultStorage(options = {}) {
|
|
|
1098
1107
|
}
|
|
1099
1108
|
|
|
1100
1109
|
// src/version.ts
|
|
1101
|
-
var POLLAR_CORE_VERSION = "0.9.0-rc.
|
|
1110
|
+
var POLLAR_CORE_VERSION = "0.9.0-rc.2" ;
|
|
1102
1111
|
|
|
1103
1112
|
// src/visibility/noop.ts
|
|
1104
1113
|
function createNoopVisibilityProvider() {
|
|
@@ -1270,7 +1279,10 @@ function openAlbedoPopup(url) {
|
|
|
1270
1279
|
}
|
|
1271
1280
|
function waitForAlbedoPopup() {
|
|
1272
1281
|
return new Promise((resolve, reject) => {
|
|
1273
|
-
const timeout = setTimeout(() =>
|
|
1282
|
+
const timeout = setTimeout(() => {
|
|
1283
|
+
window.removeEventListener("message", handler);
|
|
1284
|
+
reject(new Error("Albedo response timeout"));
|
|
1285
|
+
}, 2 * 60 * 1e3);
|
|
1274
1286
|
function handler(event) {
|
|
1275
1287
|
if (event.origin !== window.location.origin || event.data?.type !== "ALBEDO_RESULT") return;
|
|
1276
1288
|
clearTimeout(timeout);
|
|
@@ -1280,24 +1292,6 @@ function waitForAlbedoPopup() {
|
|
|
1280
1292
|
window.addEventListener("message", handler);
|
|
1281
1293
|
});
|
|
1282
1294
|
}
|
|
1283
|
-
function waitForAlbedoResult() {
|
|
1284
|
-
return new Promise((resolve, reject) => {
|
|
1285
|
-
const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
|
|
1286
|
-
const parseResult = () => {
|
|
1287
|
-
const params = new URLSearchParams(window.location.search);
|
|
1288
|
-
if (!params.has("pubkey") && !params.has("signed_envelope_xdr") && !params.has("signed_xdr")) return;
|
|
1289
|
-
clearTimeout(timeout);
|
|
1290
|
-
const result = {};
|
|
1291
|
-
params.forEach((value, key) => {
|
|
1292
|
-
result[key] = value;
|
|
1293
|
-
});
|
|
1294
|
-
window.history.replaceState({}, document.title, window.location.pathname);
|
|
1295
|
-
resolve(result);
|
|
1296
|
-
};
|
|
1297
|
-
parseResult();
|
|
1298
|
-
window.addEventListener("popstate", parseResult);
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
1295
|
var AlbedoAdapter = class {
|
|
1302
1296
|
/**
|
|
1303
1297
|
* Network used for `connect` and `signAuthEntry` (which carry no per-call
|
|
@@ -1339,10 +1333,10 @@ var AlbedoAdapter = class {
|
|
|
1339
1333
|
url.searchParams.set("xdr", xdr);
|
|
1340
1334
|
url.searchParams.set("app_name", "Pollar");
|
|
1341
1335
|
url.searchParams.set("network", albedoNetwork(options, this.network));
|
|
1342
|
-
url.searchParams.set("callback", window.location.
|
|
1336
|
+
url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
|
|
1343
1337
|
url.searchParams.set("origin", window.location.origin);
|
|
1344
|
-
|
|
1345
|
-
const result = await
|
|
1338
|
+
openAlbedoPopup(url.toString());
|
|
1339
|
+
const result = await waitForAlbedoPopup();
|
|
1346
1340
|
if (!result.signed_envelope_xdr) throw new Error("Albedo signing rejected");
|
|
1347
1341
|
return { signedTxXdr: result.signed_envelope_xdr };
|
|
1348
1342
|
}
|
|
@@ -1352,10 +1346,10 @@ var AlbedoAdapter = class {
|
|
|
1352
1346
|
url.searchParams.set("xdr", entryXdr);
|
|
1353
1347
|
url.searchParams.set("app_name", "Pollar");
|
|
1354
1348
|
url.searchParams.set("network", this.network);
|
|
1355
|
-
url.searchParams.set("callback", window.location.
|
|
1349
|
+
url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
|
|
1356
1350
|
url.searchParams.set("origin", window.location.origin);
|
|
1357
|
-
|
|
1358
|
-
const result = await
|
|
1351
|
+
openAlbedoPopup(url.toString());
|
|
1352
|
+
const result = await waitForAlbedoPopup();
|
|
1359
1353
|
if (!result.signed_xdr) throw new Error("Albedo auth entry signing rejected");
|
|
1360
1354
|
return { signedAuthEntry: result.signed_xdr };
|
|
1361
1355
|
}
|
|
@@ -1382,85 +1376,85 @@ function isBoundedString(v, max, allowEmpty = false) {
|
|
|
1382
1376
|
if (!allowEmpty && v.length === 0) return false;
|
|
1383
1377
|
return v.length <= max;
|
|
1384
1378
|
}
|
|
1385
|
-
function isValidSession(value) {
|
|
1379
|
+
function isValidSession(value, logger = console) {
|
|
1386
1380
|
if (typeof value !== "object" || value === null) {
|
|
1387
|
-
|
|
1381
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 value is not an object");
|
|
1388
1382
|
return false;
|
|
1389
1383
|
}
|
|
1390
1384
|
const s = value;
|
|
1391
1385
|
if (!isBoundedString(s["clientSessionId"], MAX_CLIENT_SESSION_ID)) {
|
|
1392
|
-
|
|
1386
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 clientSessionId missing/empty/too long");
|
|
1393
1387
|
return false;
|
|
1394
1388
|
}
|
|
1395
1389
|
if (s["userId"] !== null && !isBoundedString(s["userId"], MAX_USER_ID)) {
|
|
1396
|
-
|
|
1390
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 userId must be string|null");
|
|
1397
1391
|
return false;
|
|
1398
1392
|
}
|
|
1399
1393
|
if (!isBoundedString(s["status"], MAX_STATUS)) {
|
|
1400
|
-
|
|
1394
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 status must be string");
|
|
1401
1395
|
return false;
|
|
1402
1396
|
}
|
|
1403
1397
|
const token = s["token"];
|
|
1404
1398
|
if (typeof token !== "object" || token === null) {
|
|
1405
|
-
|
|
1399
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 token missing or not an object");
|
|
1406
1400
|
return false;
|
|
1407
1401
|
}
|
|
1408
1402
|
const t = token;
|
|
1409
1403
|
if (!isBoundedString(t["accessToken"], MAX_ACCESS_TOKEN)) {
|
|
1410
|
-
|
|
1404
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 token.accessToken missing/empty/too long");
|
|
1411
1405
|
return false;
|
|
1412
1406
|
}
|
|
1413
1407
|
if (!isBoundedString(t["refreshToken"], MAX_REFRESH_TOKEN)) {
|
|
1414
|
-
|
|
1408
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 token.refreshToken missing/empty/too long");
|
|
1415
1409
|
return false;
|
|
1416
1410
|
}
|
|
1417
1411
|
if (typeof t["expiresAt"] !== "number" || !Number.isFinite(t["expiresAt"])) {
|
|
1418
|
-
|
|
1412
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 token.expiresAt must be a finite number");
|
|
1419
1413
|
return false;
|
|
1420
1414
|
}
|
|
1421
1415
|
const user = s["user"];
|
|
1422
1416
|
if (typeof user !== "object" || user === null) {
|
|
1423
|
-
|
|
1417
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 user missing or not an object");
|
|
1424
1418
|
return false;
|
|
1425
1419
|
}
|
|
1426
1420
|
const u = user;
|
|
1427
1421
|
if (u["id"] !== void 0 && !isBoundedString(u["id"], MAX_USER_ID)) {
|
|
1428
|
-
|
|
1422
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 user.id must be string if present");
|
|
1429
1423
|
return false;
|
|
1430
1424
|
}
|
|
1431
1425
|
if (typeof u["ready"] !== "boolean") {
|
|
1432
|
-
|
|
1426
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 user.ready must be boolean");
|
|
1433
1427
|
return false;
|
|
1434
1428
|
}
|
|
1435
1429
|
const wallet = s["wallet"];
|
|
1436
1430
|
if (typeof wallet !== "object" || wallet === null) {
|
|
1437
|
-
|
|
1431
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet missing or not an object");
|
|
1438
1432
|
return false;
|
|
1439
1433
|
}
|
|
1440
1434
|
const w = wallet;
|
|
1441
|
-
if (w["type"] !== "
|
|
1442
|
-
|
|
1435
|
+
if (w["type"] !== "internal" && w["type"] !== "smart" && w["type"] !== "external") {
|
|
1436
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet.type must be internal|smart|external");
|
|
1443
1437
|
return false;
|
|
1444
1438
|
}
|
|
1445
1439
|
if (w["address"] !== null && !isBoundedString(w["address"], MAX_WALLET_PUBLIC_KEY)) {
|
|
1446
|
-
|
|
1440
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet.address must be string|null");
|
|
1447
1441
|
return false;
|
|
1448
1442
|
}
|
|
1449
1443
|
if (w["existsOnStellar"] !== void 0 && typeof w["existsOnStellar"] !== "boolean") {
|
|
1450
|
-
|
|
1444
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet.existsOnStellar must be boolean if present");
|
|
1451
1445
|
return false;
|
|
1452
1446
|
}
|
|
1453
1447
|
if (w["createdAt"] !== void 0 && (typeof w["createdAt"] !== "number" || !Number.isFinite(w["createdAt"]))) {
|
|
1454
|
-
|
|
1448
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet.createdAt must be a finite number if present");
|
|
1455
1449
|
return false;
|
|
1456
1450
|
}
|
|
1457
1451
|
if (w["linkedAt"] !== void 0 && (typeof w["linkedAt"] !== "number" || !Number.isFinite(w["linkedAt"]))) {
|
|
1458
|
-
|
|
1452
|
+
logger.debug("[PollarClient:session] Invalid session \u2014 wallet.linkedAt must be a finite number if present");
|
|
1459
1453
|
return false;
|
|
1460
1454
|
}
|
|
1461
1455
|
return true;
|
|
1462
1456
|
}
|
|
1463
|
-
async function readStorage(storage, apiKeyHash) {
|
|
1457
|
+
async function readStorage(storage, apiKeyHash, logger = console) {
|
|
1464
1458
|
const raw = await storage.get(sessionStorageKey(apiKeyHash));
|
|
1465
1459
|
if (!raw) return null;
|
|
1466
1460
|
try {
|
|
@@ -1470,10 +1464,13 @@ async function readStorage(storage, apiKeyHash) {
|
|
|
1470
1464
|
if (w && w["address"] == null && typeof w["publicKey"] === "string") {
|
|
1471
1465
|
w["address"] = w["publicKey"];
|
|
1472
1466
|
}
|
|
1467
|
+
if (w && w["type"] === "custodial") {
|
|
1468
|
+
w["type"] = "internal";
|
|
1469
|
+
}
|
|
1473
1470
|
}
|
|
1474
|
-
if (!isValidSession(session)) {
|
|
1471
|
+
if (!isValidSession(session, logger)) {
|
|
1475
1472
|
await storage.remove(sessionStorageKey(apiKeyHash));
|
|
1476
|
-
|
|
1473
|
+
logger.warn("[PollarClient:session] Stored session is invalid \u2014 clearing storage");
|
|
1477
1474
|
return null;
|
|
1478
1475
|
}
|
|
1479
1476
|
if (session.token.expiresAt * 1e3 < Date.now()) {
|
|
@@ -1481,7 +1478,7 @@ async function readStorage(storage, apiKeyHash) {
|
|
|
1481
1478
|
}
|
|
1482
1479
|
return session;
|
|
1483
1480
|
} catch (error) {
|
|
1484
|
-
|
|
1481
|
+
logger.error("[PollarClient:session] Failed to parse session from storage", error);
|
|
1485
1482
|
await storage.remove(sessionStorageKey(apiKeyHash));
|
|
1486
1483
|
return null;
|
|
1487
1484
|
}
|
|
@@ -1543,7 +1540,7 @@ function abortableDelay(ms, signal) {
|
|
|
1543
1540
|
});
|
|
1544
1541
|
}
|
|
1545
1542
|
var MAX_BACKOFF_MS = 5e3;
|
|
1546
|
-
async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200, signal) {
|
|
1543
|
+
async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200, signal, logger = console) {
|
|
1547
1544
|
let backoff = retryDelayMs;
|
|
1548
1545
|
const sleep = async (ms) => {
|
|
1549
1546
|
if (ms <= 0) return;
|
|
@@ -1561,7 +1558,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1561
1558
|
}));
|
|
1562
1559
|
} catch (e) {
|
|
1563
1560
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1564
|
-
|
|
1561
|
+
logger.debug("[PollarClient:stream] session-status request failed; will retry", e);
|
|
1565
1562
|
}
|
|
1566
1563
|
if (error || !data) {
|
|
1567
1564
|
await sleep(backoff);
|
|
@@ -1570,16 +1567,12 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1570
1567
|
}
|
|
1571
1568
|
const reader = data.getReader();
|
|
1572
1569
|
const decoder = new TextDecoder();
|
|
1573
|
-
let streamDone = false;
|
|
1574
1570
|
let sawAnyChunk = false;
|
|
1575
1571
|
try {
|
|
1576
1572
|
while (true) {
|
|
1577
1573
|
throwIfAborted(signal);
|
|
1578
1574
|
const { done, value } = await reader.read();
|
|
1579
|
-
if (done)
|
|
1580
|
-
streamDone = true;
|
|
1581
|
-
break;
|
|
1582
|
-
}
|
|
1575
|
+
if (done) break;
|
|
1583
1576
|
sawAnyChunk = true;
|
|
1584
1577
|
const chunk = decoder.decode(value);
|
|
1585
1578
|
for (const message of chunk.split("\n\n").filter(Boolean)) {
|
|
@@ -1601,17 +1594,16 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1601
1594
|
} catch (e) {
|
|
1602
1595
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1603
1596
|
if (e instanceof SessionStatusError) throw e;
|
|
1604
|
-
|
|
1597
|
+
logger.debug("[PollarClient:stream] session-status stream read failed; will retry", e);
|
|
1605
1598
|
} finally {
|
|
1606
1599
|
reader.releaseLock();
|
|
1607
1600
|
}
|
|
1608
1601
|
if (sawAnyChunk) backoff = retryDelayMs;
|
|
1609
1602
|
else backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
1610
|
-
|
|
1611
|
-
if (delay) await sleep(delay);
|
|
1603
|
+
await sleep(backoff);
|
|
1612
1604
|
}
|
|
1613
1605
|
}
|
|
1614
|
-
async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal) {
|
|
1606
|
+
async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal, logger = console) {
|
|
1615
1607
|
const url = `${baseUrl}/auth/session/status/${encodeURIComponent(clientSessionId)}/poll`;
|
|
1616
1608
|
let backoff = intervalMs;
|
|
1617
1609
|
const sleep = async (ms) => {
|
|
@@ -1629,7 +1621,7 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
|
|
|
1629
1621
|
envelope = await response.json().catch(() => null);
|
|
1630
1622
|
} catch (e) {
|
|
1631
1623
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1632
|
-
|
|
1624
|
+
logger.debug("[PollarClient:stream] session-status poll failed; will retry", e);
|
|
1633
1625
|
}
|
|
1634
1626
|
if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
|
|
1635
1627
|
throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
|
|
@@ -1646,13 +1638,13 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
|
|
|
1646
1638
|
}
|
|
1647
1639
|
}
|
|
1648
1640
|
function waitForSessionReady(args) {
|
|
1649
|
-
const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal } = args;
|
|
1650
|
-
return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal);
|
|
1641
|
+
const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal, logger = console } = args;
|
|
1642
|
+
return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal, logger) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal, logger);
|
|
1651
1643
|
}
|
|
1652
1644
|
|
|
1653
1645
|
// src/client/auth/authenticate.ts
|
|
1654
1646
|
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
1655
|
-
const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1647
|
+
const { api, logger, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1656
1648
|
setAuthState({ step: "authenticating" });
|
|
1657
1649
|
try {
|
|
1658
1650
|
await waitForSessionReady({
|
|
@@ -1661,7 +1653,8 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
|
1661
1653
|
clientSessionId,
|
|
1662
1654
|
check: (data2) => data2?.status === "READY",
|
|
1663
1655
|
useStreaming,
|
|
1664
|
-
signal
|
|
1656
|
+
signal,
|
|
1657
|
+
logger
|
|
1665
1658
|
});
|
|
1666
1659
|
} catch (err) {
|
|
1667
1660
|
if (err instanceof SessionStatusError) {
|
|
@@ -1686,18 +1679,19 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
|
1686
1679
|
},
|
|
1687
1680
|
signal
|
|
1688
1681
|
});
|
|
1689
|
-
if (data?.code === "SDK_LOGIN_SUCCESS" && isValidSession(data?.content)) {
|
|
1690
|
-
|
|
1682
|
+
if (data?.code === "SDK_LOGIN_SUCCESS" && isValidSession(data?.content, logger)) {
|
|
1683
|
+
const sessionWallet = data.content.data?.providers?.wallet?.address;
|
|
1684
|
+
if (expectedWallet && sessionWallet !== expectedWallet) {
|
|
1691
1685
|
setAuthState({
|
|
1692
1686
|
step: "error",
|
|
1693
1687
|
previousStep: "authenticating",
|
|
1694
1688
|
message: "Wallet mismatch: session wallet does not match connected wallet",
|
|
1695
1689
|
errorCode: AUTH_ERROR_CODES.WALLET_AUTH_FAILED
|
|
1696
1690
|
});
|
|
1697
|
-
clearSession();
|
|
1691
|
+
await clearSession();
|
|
1698
1692
|
return;
|
|
1699
1693
|
}
|
|
1700
|
-
storeSession(data.content);
|
|
1694
|
+
await storeSession(data.content);
|
|
1701
1695
|
} else {
|
|
1702
1696
|
setAuthState({
|
|
1703
1697
|
step: "error",
|
|
@@ -1705,7 +1699,7 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
|
1705
1699
|
message: "Failed to load session",
|
|
1706
1700
|
errorCode: AUTH_ERROR_CODES.AUTH_FAILED
|
|
1707
1701
|
});
|
|
1708
|
-
clearSession();
|
|
1702
|
+
await clearSession();
|
|
1709
1703
|
}
|
|
1710
1704
|
}
|
|
1711
1705
|
|
|
@@ -2004,7 +1998,9 @@ var PollarClient = class {
|
|
|
2004
1998
|
this.apiKey = config.apiKey;
|
|
2005
1999
|
this.id = randomUUID();
|
|
2006
2000
|
this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
|
|
2001
|
+
this._log = createLogger(config.logLevel ?? "info", config.logger);
|
|
2007
2002
|
this._storage = config.storage ?? defaultStorage({
|
|
2003
|
+
logger: this._log,
|
|
2008
2004
|
onDegrade: (reason, error) => {
|
|
2009
2005
|
config.onStorageDegrade?.(reason, error);
|
|
2010
2006
|
this._dispatchStorageDegrade(reason, error);
|
|
@@ -2019,7 +2015,7 @@ var PollarClient = class {
|
|
|
2019
2015
|
this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
|
|
2020
2016
|
this._maxIdleMs = config.maxIdleMs;
|
|
2021
2017
|
this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
|
|
2022
|
-
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location
|
|
2018
|
+
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location?.origin ?? "" : "");
|
|
2023
2019
|
this._api = createApiClient(this.basePath);
|
|
2024
2020
|
this._wireMiddlewares();
|
|
2025
2021
|
this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
|
|
@@ -2028,7 +2024,7 @@ var PollarClient = class {
|
|
|
2028
2024
|
this._initialized = Promise.resolve();
|
|
2029
2025
|
return;
|
|
2030
2026
|
}
|
|
2031
|
-
|
|
2027
|
+
this._log.info(
|
|
2032
2028
|
`[PollarClient] Initialized v${POLLAR_CORE_VERSION} \u2014 endpoint: ${this.basePath}, network: ${this._networkState.network}`
|
|
2033
2029
|
);
|
|
2034
2030
|
this._initialized = this._initialize();
|
|
@@ -2055,7 +2051,7 @@ var PollarClient = class {
|
|
|
2055
2051
|
const sessionKey = sessionStorageKey(this._apiKeyHash);
|
|
2056
2052
|
const handler = (e) => {
|
|
2057
2053
|
if (e.key === sessionKey) {
|
|
2058
|
-
this._restoreSession().catch((err) =>
|
|
2054
|
+
this._restoreSession().catch((err) => this._log.error("[PollarClient] Cross-tab restore failed", err));
|
|
2059
2055
|
}
|
|
2060
2056
|
};
|
|
2061
2057
|
window.addEventListener("storage", handler);
|
|
@@ -2064,7 +2060,7 @@ var PollarClient = class {
|
|
|
2064
2060
|
try {
|
|
2065
2061
|
await this._keyManager.init();
|
|
2066
2062
|
} catch (err) {
|
|
2067
|
-
|
|
2063
|
+
this._log.warn("[PollarClient] KeyManager init failed; DPoP unavailable for this session", err);
|
|
2068
2064
|
}
|
|
2069
2065
|
await this._restoreSession();
|
|
2070
2066
|
this._visibilityUnsubscribe = this._visibilityProvider.onChange((visible) => {
|
|
@@ -2105,7 +2101,7 @@ var PollarClient = class {
|
|
|
2105
2101
|
try {
|
|
2106
2102
|
self._requestBodyCache.set(request, await request.clone().arrayBuffer());
|
|
2107
2103
|
} catch (err) {
|
|
2108
|
-
|
|
2104
|
+
this._log.warn("[PollarClient] Could not snapshot request body for retry", err);
|
|
2109
2105
|
}
|
|
2110
2106
|
}
|
|
2111
2107
|
const isRefresh = request.url.includes("/auth/refresh");
|
|
@@ -2164,7 +2160,7 @@ var PollarClient = class {
|
|
|
2164
2160
|
this._keyManager
|
|
2165
2161
|
);
|
|
2166
2162
|
} catch (err) {
|
|
2167
|
-
|
|
2163
|
+
this._log.warn("[PollarClient] DPoP proof build failed", err);
|
|
2168
2164
|
return null;
|
|
2169
2165
|
}
|
|
2170
2166
|
}
|
|
@@ -2218,7 +2214,7 @@ var PollarClient = class {
|
|
|
2218
2214
|
async _doRefresh() {
|
|
2219
2215
|
const refreshToken = this._session?.token?.refreshToken;
|
|
2220
2216
|
if (!refreshToken) {
|
|
2221
|
-
|
|
2217
|
+
this._log.warn("[PollarClient] Refresh skipped: no refresh token in session");
|
|
2222
2218
|
await this._clearSession();
|
|
2223
2219
|
throw new Error("No refresh token available");
|
|
2224
2220
|
}
|
|
@@ -2229,18 +2225,18 @@ var PollarClient = class {
|
|
|
2229
2225
|
data = response.data;
|
|
2230
2226
|
error = response.error;
|
|
2231
2227
|
} catch (err) {
|
|
2232
|
-
|
|
2228
|
+
this._log.error("[PollarClient] /auth/refresh request threw", err);
|
|
2233
2229
|
await this._clearSession();
|
|
2234
2230
|
throw err;
|
|
2235
2231
|
}
|
|
2236
2232
|
if (error || !data) {
|
|
2237
|
-
|
|
2233
|
+
this._log.error("[PollarClient] /auth/refresh returned error", { error });
|
|
2238
2234
|
await this._clearSession();
|
|
2239
2235
|
throw new Error("Refresh failed");
|
|
2240
2236
|
}
|
|
2241
2237
|
const successData = data;
|
|
2242
2238
|
if (!successData.success || !successData.content?.token) {
|
|
2243
|
-
|
|
2239
|
+
this._log.error("[PollarClient] /auth/refresh response malformed", {
|
|
2244
2240
|
success: successData.success,
|
|
2245
2241
|
hasToken: !!successData.content?.token
|
|
2246
2242
|
});
|
|
@@ -2249,7 +2245,7 @@ var PollarClient = class {
|
|
|
2249
2245
|
}
|
|
2250
2246
|
const newToken = successData.content.token;
|
|
2251
2247
|
if (typeof newToken.accessToken !== "string" || typeof newToken.refreshToken !== "string" || typeof newToken.expiresAt !== "number") {
|
|
2252
|
-
|
|
2248
|
+
this._log.error("[PollarClient] /auth/refresh token shape invalid", {
|
|
2253
2249
|
accessToken: typeof newToken.accessToken,
|
|
2254
2250
|
refreshToken: typeof newToken.refreshToken,
|
|
2255
2251
|
expiresAt: typeof newToken.expiresAt
|
|
@@ -2261,9 +2257,9 @@ var PollarClient = class {
|
|
|
2261
2257
|
try {
|
|
2262
2258
|
this._session = { ...this._session, token: newToken };
|
|
2263
2259
|
await writeStorage(this._storage, this.apiKeyHash, this._session);
|
|
2264
|
-
|
|
2260
|
+
this._log.info("[PollarClient] Tokens refreshed");
|
|
2265
2261
|
} catch (err) {
|
|
2266
|
-
|
|
2262
|
+
this._log.error("[PollarClient] Failed to persist refreshed session", err);
|
|
2267
2263
|
}
|
|
2268
2264
|
this._scheduleNextRefresh();
|
|
2269
2265
|
}
|
|
@@ -2317,7 +2313,7 @@ var PollarClient = class {
|
|
|
2317
2313
|
try {
|
|
2318
2314
|
await this.refresh();
|
|
2319
2315
|
} catch (err) {
|
|
2320
|
-
|
|
2316
|
+
this._log.warn("[PollarClient] Proactive refresh failed; session cleared", err);
|
|
2321
2317
|
}
|
|
2322
2318
|
}
|
|
2323
2319
|
_clearRefreshTimer() {
|
|
@@ -2363,7 +2359,7 @@ var PollarClient = class {
|
|
|
2363
2359
|
try {
|
|
2364
2360
|
cb(reason, error);
|
|
2365
2361
|
} catch (err) {
|
|
2366
|
-
|
|
2362
|
+
this._log.error("[PollarClient] onStorageDegrade listener threw", err);
|
|
2367
2363
|
}
|
|
2368
2364
|
}
|
|
2369
2365
|
}
|
|
@@ -2483,20 +2479,20 @@ var PollarClient = class {
|
|
|
2483
2479
|
warnServerSide("logout");
|
|
2484
2480
|
return;
|
|
2485
2481
|
}
|
|
2486
|
-
|
|
2482
|
+
this._log.info("[PollarClient] Logout requested", { everywhere: !!options.everywhere });
|
|
2487
2483
|
if (this._session?.token?.accessToken) {
|
|
2488
2484
|
try {
|
|
2489
2485
|
await this._api.POST("/auth/logout", {
|
|
2490
2486
|
body: options.everywhere ? { everywhere: true } : {}
|
|
2491
2487
|
});
|
|
2492
2488
|
} catch (err) {
|
|
2493
|
-
|
|
2489
|
+
this._log.warn("[PollarClient] Server logout failed (continuing with local clear)", err);
|
|
2494
2490
|
}
|
|
2495
2491
|
}
|
|
2496
2492
|
try {
|
|
2497
2493
|
await this._clearSession();
|
|
2498
2494
|
} catch (err) {
|
|
2499
|
-
|
|
2495
|
+
this._log.warn("[PollarClient] Local logout cleanup failed", err);
|
|
2500
2496
|
}
|
|
2501
2497
|
}
|
|
2502
2498
|
/** Convenience: revoke every active session for this user (all devices). */
|
|
@@ -2572,6 +2568,14 @@ var PollarClient = class {
|
|
|
2572
2568
|
getNetworkState() {
|
|
2573
2569
|
return this._networkState;
|
|
2574
2570
|
}
|
|
2571
|
+
/**
|
|
2572
|
+
* The client's level-gated logger (built from `logLevel` / `logger`). Exposed
|
|
2573
|
+
* so the runtime layer (`@pollar/react`) can route its own logs through the
|
|
2574
|
+
* same level and sink instead of calling `console` directly.
|
|
2575
|
+
*/
|
|
2576
|
+
getLogger() {
|
|
2577
|
+
return this._log;
|
|
2578
|
+
}
|
|
2575
2579
|
setNetwork(network) {
|
|
2576
2580
|
this._setNetworkState({ step: "connected", network });
|
|
2577
2581
|
}
|
|
@@ -2720,7 +2724,7 @@ var PollarClient = class {
|
|
|
2720
2724
|
this._setTransactionState({ step: "error", phase: "building", ...details && { details } });
|
|
2721
2725
|
return { status: "error", ...details && { details } };
|
|
2722
2726
|
} catch (err) {
|
|
2723
|
-
|
|
2727
|
+
this._log.error("[PollarClient] buildTx failed", err);
|
|
2724
2728
|
this._setTransactionState({ step: "error", phase: "building" });
|
|
2725
2729
|
return { status: "error" };
|
|
2726
2730
|
}
|
|
@@ -3233,6 +3237,7 @@ var PollarClient = class {
|
|
|
3233
3237
|
_flowDeps(signal) {
|
|
3234
3238
|
return {
|
|
3235
3239
|
api: this._api,
|
|
3240
|
+
logger: this._log,
|
|
3236
3241
|
basePath: this.basePath,
|
|
3237
3242
|
// SSE status streaming works on web; React Native's `fetch` has no
|
|
3238
3243
|
// readable `response.body`, so those clients poll the non-streaming
|
|
@@ -3285,12 +3290,12 @@ var PollarClient = class {
|
|
|
3285
3290
|
}
|
|
3286
3291
|
_handleFlowError(error) {
|
|
3287
3292
|
if (error instanceof Error && error.name === "AbortError") {
|
|
3288
|
-
|
|
3293
|
+
this._log.debug("[PollarClient] Login cancelled");
|
|
3289
3294
|
this._setAuthState({ step: "idle" });
|
|
3290
3295
|
return;
|
|
3291
3296
|
}
|
|
3292
3297
|
if (error instanceof Error && error.code === AUTH_ERROR_CODES.WALLET_RESOLVER_TIMEOUT) {
|
|
3293
|
-
|
|
3298
|
+
this._log.error("[PollarClient]", error.message);
|
|
3294
3299
|
this._setAuthState({
|
|
3295
3300
|
step: "error",
|
|
3296
3301
|
previousStep: this._authState.step,
|
|
@@ -3299,7 +3304,7 @@ var PollarClient = class {
|
|
|
3299
3304
|
});
|
|
3300
3305
|
return;
|
|
3301
3306
|
}
|
|
3302
|
-
|
|
3307
|
+
this._log.error("[PollarClient] Unexpected error in auth flow", error);
|
|
3303
3308
|
this._setAuthState({
|
|
3304
3309
|
step: "error",
|
|
3305
3310
|
previousStep: this._authState.step,
|
|
@@ -3308,22 +3313,25 @@ var PollarClient = class {
|
|
|
3308
3313
|
});
|
|
3309
3314
|
}
|
|
3310
3315
|
async _restoreSession() {
|
|
3311
|
-
this._session = await readStorage(this._storage, this.apiKeyHash);
|
|
3316
|
+
this._session = await readStorage(this._storage, this.apiKeyHash, this._log);
|
|
3312
3317
|
if (this._session) {
|
|
3313
3318
|
const storedType = await readWalletType(this._storage, this.apiKeyHash);
|
|
3314
3319
|
if (storedType) {
|
|
3315
3320
|
try {
|
|
3316
3321
|
this._walletAdapter = await this._resolveWalletAdapter(storedType);
|
|
3317
3322
|
} catch (err) {
|
|
3318
|
-
|
|
3323
|
+
this._log.warn("[PollarClient] Could not restore wallet adapter for stored id", { id: storedType, err });
|
|
3319
3324
|
}
|
|
3320
3325
|
}
|
|
3321
|
-
|
|
3326
|
+
this._log.info("[PollarClient] Session restored from storage");
|
|
3322
3327
|
this._setAuthState({ step: "authenticated", session: this._session, verified: false });
|
|
3323
3328
|
this._scheduleNextRefresh();
|
|
3324
3329
|
void this._resume();
|
|
3325
3330
|
} else {
|
|
3326
|
-
|
|
3331
|
+
this._log.info("[PollarClient] No session in storage");
|
|
3332
|
+
if (this._authState.step !== "idle") {
|
|
3333
|
+
await this._clearSession();
|
|
3334
|
+
}
|
|
3327
3335
|
}
|
|
3328
3336
|
}
|
|
3329
3337
|
/**
|
|
@@ -3354,13 +3362,13 @@ var PollarClient = class {
|
|
|
3354
3362
|
this._setAuthState({ step: "authenticated", session: this._session, verified: true });
|
|
3355
3363
|
} catch (err) {
|
|
3356
3364
|
if (err?.name === "AbortError") return;
|
|
3357
|
-
|
|
3365
|
+
this._log.warn("[PollarClient] resume failed (network); will retry", err);
|
|
3358
3366
|
} finally {
|
|
3359
3367
|
if (this._resumeController === controller) this._resumeController = null;
|
|
3360
3368
|
}
|
|
3361
3369
|
}
|
|
3362
3370
|
async _storeSession(session) {
|
|
3363
|
-
|
|
3371
|
+
this._log.info("[PollarClient] Session stored");
|
|
3364
3372
|
const w = session.wallet;
|
|
3365
3373
|
const persisted = {
|
|
3366
3374
|
clientSessionId: session.clientSessionId,
|
|
@@ -3370,8 +3378,11 @@ var PollarClient = class {
|
|
|
3370
3378
|
user: session.user,
|
|
3371
3379
|
// The wire response still carries the legacy `publicKey` alias (kept for
|
|
3372
3380
|
// older SDKs); the persisted session standardizes on `address` only.
|
|
3381
|
+
// The wire also still emits the legacy type `'custodial'` (unchanged for
|
|
3382
|
+
// SDKs ≤0.8.x); we remap it to `'internal'` here so the SDK surface and
|
|
3383
|
+
// persisted session speak one vocabulary while the wire stays compatible.
|
|
3373
3384
|
wallet: {
|
|
3374
|
-
type: w.type,
|
|
3385
|
+
type: w.type === "custodial" ? "internal" : w.type,
|
|
3375
3386
|
address: w.address ?? w.publicKey ?? null,
|
|
3376
3387
|
...w.existsOnStellar !== void 0 ? { existsOnStellar: w.existsOnStellar } : {},
|
|
3377
3388
|
...w.createdAt !== void 0 ? { createdAt: w.createdAt } : {},
|
|
@@ -3395,7 +3406,7 @@ var PollarClient = class {
|
|
|
3395
3406
|
this._scheduleNextRefresh();
|
|
3396
3407
|
}
|
|
3397
3408
|
async _clearSession() {
|
|
3398
|
-
|
|
3409
|
+
this._log.info("[PollarClient] Session cleared");
|
|
3399
3410
|
this._clearRefreshTimer();
|
|
3400
3411
|
this._session = null;
|
|
3401
3412
|
this._profile = null;
|
|
@@ -3404,7 +3415,7 @@ var PollarClient = class {
|
|
|
3404
3415
|
try {
|
|
3405
3416
|
await this._keyManager.reset();
|
|
3406
3417
|
} catch (err) {
|
|
3407
|
-
|
|
3418
|
+
this._log.warn("[PollarClient] KeyManager reset failed during clearSession", err);
|
|
3408
3419
|
}
|
|
3409
3420
|
await removeStorage(this._storage, this.apiKeyHash);
|
|
3410
3421
|
this._transactionState = null;
|
|
@@ -3416,17 +3427,17 @@ var PollarClient = class {
|
|
|
3416
3427
|
_setNetworkState(next) {
|
|
3417
3428
|
this._networkState = next;
|
|
3418
3429
|
const label = next.step === "connected" ? next.network : next.step;
|
|
3419
|
-
|
|
3430
|
+
this._log.debug(`[PollarClient] network:${label}`);
|
|
3420
3431
|
for (const cb of this._networkStateListeners) cb(next);
|
|
3421
3432
|
}
|
|
3422
3433
|
_setAuthState(next) {
|
|
3423
3434
|
this._authState = next;
|
|
3424
|
-
|
|
3435
|
+
this._log.debug(`[PollarClient] auth:${next.step}`);
|
|
3425
3436
|
for (const cb of this._authStateListeners) cb(next);
|
|
3426
3437
|
}
|
|
3427
3438
|
_setTransactionState(next) {
|
|
3428
3439
|
this._transactionState = next;
|
|
3429
|
-
|
|
3440
|
+
this._log.debug(`[PollarClient] transaction:${next.step}`);
|
|
3430
3441
|
for (const cb of this._transactionStateListeners) cb(next);
|
|
3431
3442
|
}
|
|
3432
3443
|
/**
|
|
@@ -3530,7 +3541,6 @@ var WebCryptoKeyManager = class {
|
|
|
3530
3541
|
if (this.keyPair) return;
|
|
3531
3542
|
if (!this._initPromise) {
|
|
3532
3543
|
this._initPromise = this._doInit().catch((err) => {
|
|
3533
|
-
console.error("[PollarClient:keys] WebCryptoKeyManager init failed", err);
|
|
3534
3544
|
this._initPromise = null;
|
|
3535
3545
|
throw err;
|
|
3536
3546
|
});
|
|
@@ -3666,6 +3676,6 @@ _setDefaultKeyManagerFactory((storage, apiKey) => {
|
|
|
3666
3676
|
return new NobleKeyManager(storage, apiKey);
|
|
3667
3677
|
});
|
|
3668
3678
|
|
|
3669
|
-
export { AUTH_ERROR_CODES, AlbedoAdapter, FreighterAdapter, NobleKeyManager, POLLAR_CORE_VERSION, PollarClient, StellarClient, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, resolveKyc, startKyc };
|
|
3679
|
+
export { AUTH_ERROR_CODES, AlbedoAdapter, FreighterAdapter, NobleKeyManager, POLLAR_CORE_VERSION, PollarClient, StellarClient, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createLogger, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, resolveKyc, startKyc };
|
|
3670
3680
|
//# sourceMappingURL=index.rn.mjs.map
|
|
3671
3681
|
//# sourceMappingURL=index.rn.mjs.map
|