@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/dist/index.mjs CHANGED
@@ -339,7 +339,6 @@ var WebCryptoKeyManager = class {
339
339
  if (this.keyPair) return;
340
340
  if (!this._initPromise) {
341
341
  this._initPromise = this._doInit().catch((err) => {
342
- console.error("[PollarClient:keys] WebCryptoKeyManager init failed", err);
343
342
  this._initPromise = null;
344
343
  throw err;
345
344
  });
@@ -1074,6 +1073,16 @@ function normalizeHtu(rawUrl) {
1074
1073
  return `${scheme}//${host}${portPart}${url.pathname}`;
1075
1074
  }
1076
1075
 
1076
+ // src/lib/logger.ts
1077
+ var RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
1078
+ function createLogger(level = "info", sink = console) {
1079
+ const threshold = RANK[level];
1080
+ const gate = (lvl) => (...args) => {
1081
+ if (threshold >= RANK[lvl]) sink[lvl](...args);
1082
+ };
1083
+ return { error: gate("error"), warn: gate("warn"), info: gate("info"), debug: gate("debug") };
1084
+ }
1085
+
1077
1086
  // src/storage/web.ts
1078
1087
  var LOG_PREFIX = "[PollarClient:storage]";
1079
1088
  function createMemoryAdapter() {
@@ -1097,7 +1106,7 @@ function createLocalStorageAdapter(options = {}) {
1097
1106
  function degrade(reason, error) {
1098
1107
  if (degraded) return;
1099
1108
  degraded = true;
1100
- console.warn(`${LOG_PREFIX} localStorage unavailable (${reason}); degrading to in-memory storage`);
1109
+ (options.logger ?? console).warn(`${LOG_PREFIX} localStorage unavailable (${reason}); degrading to in-memory storage`);
1101
1110
  options.onDegrade?.(reason, error);
1102
1111
  }
1103
1112
  return {
@@ -1162,7 +1171,7 @@ function defaultStorage(options = {}) {
1162
1171
  }
1163
1172
 
1164
1173
  // src/version.ts
1165
- var POLLAR_CORE_VERSION = "0.9.0-rc.0" ;
1174
+ var POLLAR_CORE_VERSION = "0.9.0-rc.2" ;
1166
1175
 
1167
1176
  // src/visibility/noop.ts
1168
1177
  function createNoopVisibilityProvider() {
@@ -1334,7 +1343,10 @@ function openAlbedoPopup(url) {
1334
1343
  }
1335
1344
  function waitForAlbedoPopup() {
1336
1345
  return new Promise((resolve, reject) => {
1337
- const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
1346
+ const timeout = setTimeout(() => {
1347
+ window.removeEventListener("message", handler);
1348
+ reject(new Error("Albedo response timeout"));
1349
+ }, 2 * 60 * 1e3);
1338
1350
  function handler(event) {
1339
1351
  if (event.origin !== window.location.origin || event.data?.type !== "ALBEDO_RESULT") return;
1340
1352
  clearTimeout(timeout);
@@ -1344,24 +1356,6 @@ function waitForAlbedoPopup() {
1344
1356
  window.addEventListener("message", handler);
1345
1357
  });
1346
1358
  }
1347
- function waitForAlbedoResult() {
1348
- return new Promise((resolve, reject) => {
1349
- const timeout = setTimeout(() => reject(new Error("Albedo response timeout")), 2 * 60 * 1e3);
1350
- const parseResult = () => {
1351
- const params = new URLSearchParams(window.location.search);
1352
- if (!params.has("pubkey") && !params.has("signed_envelope_xdr") && !params.has("signed_xdr")) return;
1353
- clearTimeout(timeout);
1354
- const result = {};
1355
- params.forEach((value, key) => {
1356
- result[key] = value;
1357
- });
1358
- window.history.replaceState({}, document.title, window.location.pathname);
1359
- resolve(result);
1360
- };
1361
- parseResult();
1362
- window.addEventListener("popstate", parseResult);
1363
- });
1364
- }
1365
1359
  var AlbedoAdapter = class {
1366
1360
  /**
1367
1361
  * Network used for `connect` and `signAuthEntry` (which carry no per-call
@@ -1403,10 +1397,10 @@ var AlbedoAdapter = class {
1403
1397
  url.searchParams.set("xdr", xdr);
1404
1398
  url.searchParams.set("app_name", "Pollar");
1405
1399
  url.searchParams.set("network", albedoNetwork(options, this.network));
1406
- url.searchParams.set("callback", window.location.href);
1400
+ url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
1407
1401
  url.searchParams.set("origin", window.location.origin);
1408
- window.location.href = url.toString();
1409
- const result = await waitForAlbedoResult();
1402
+ openAlbedoPopup(url.toString());
1403
+ const result = await waitForAlbedoPopup();
1410
1404
  if (!result.signed_envelope_xdr) throw new Error("Albedo signing rejected");
1411
1405
  return { signedTxXdr: result.signed_envelope_xdr };
1412
1406
  }
@@ -1416,10 +1410,10 @@ var AlbedoAdapter = class {
1416
1410
  url.searchParams.set("xdr", entryXdr);
1417
1411
  url.searchParams.set("app_name", "Pollar");
1418
1412
  url.searchParams.set("network", this.network);
1419
- url.searchParams.set("callback", window.location.href);
1413
+ url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
1420
1414
  url.searchParams.set("origin", window.location.origin);
1421
- window.location.href = url.toString();
1422
- const result = await waitForAlbedoResult();
1415
+ openAlbedoPopup(url.toString());
1416
+ const result = await waitForAlbedoPopup();
1423
1417
  if (!result.signed_xdr) throw new Error("Albedo auth entry signing rejected");
1424
1418
  return { signedAuthEntry: result.signed_xdr };
1425
1419
  }
@@ -1446,85 +1440,85 @@ function isBoundedString(v, max, allowEmpty = false) {
1446
1440
  if (!allowEmpty && v.length === 0) return false;
1447
1441
  return v.length <= max;
1448
1442
  }
1449
- function isValidSession(value) {
1443
+ function isValidSession(value, logger = console) {
1450
1444
  if (typeof value !== "object" || value === null) {
1451
- console.warn("[PollarClient:session] Invalid session \u2014 value is not an object");
1445
+ logger.debug("[PollarClient:session] Invalid session \u2014 value is not an object");
1452
1446
  return false;
1453
1447
  }
1454
1448
  const s = value;
1455
1449
  if (!isBoundedString(s["clientSessionId"], MAX_CLIENT_SESSION_ID)) {
1456
- console.warn("[PollarClient:session] Invalid session \u2014 clientSessionId missing/empty/too long");
1450
+ logger.debug("[PollarClient:session] Invalid session \u2014 clientSessionId missing/empty/too long");
1457
1451
  return false;
1458
1452
  }
1459
1453
  if (s["userId"] !== null && !isBoundedString(s["userId"], MAX_USER_ID)) {
1460
- console.warn("[PollarClient:session] Invalid session \u2014 userId must be string|null");
1454
+ logger.debug("[PollarClient:session] Invalid session \u2014 userId must be string|null");
1461
1455
  return false;
1462
1456
  }
1463
1457
  if (!isBoundedString(s["status"], MAX_STATUS)) {
1464
- console.warn("[PollarClient:session] Invalid session \u2014 status must be string");
1458
+ logger.debug("[PollarClient:session] Invalid session \u2014 status must be string");
1465
1459
  return false;
1466
1460
  }
1467
1461
  const token = s["token"];
1468
1462
  if (typeof token !== "object" || token === null) {
1469
- console.warn("[PollarClient:session] Invalid session \u2014 token missing or not an object");
1463
+ logger.debug("[PollarClient:session] Invalid session \u2014 token missing or not an object");
1470
1464
  return false;
1471
1465
  }
1472
1466
  const t = token;
1473
1467
  if (!isBoundedString(t["accessToken"], MAX_ACCESS_TOKEN)) {
1474
- console.warn("[PollarClient:session] Invalid session \u2014 token.accessToken missing/empty/too long");
1468
+ logger.debug("[PollarClient:session] Invalid session \u2014 token.accessToken missing/empty/too long");
1475
1469
  return false;
1476
1470
  }
1477
1471
  if (!isBoundedString(t["refreshToken"], MAX_REFRESH_TOKEN)) {
1478
- console.warn("[PollarClient:session] Invalid session \u2014 token.refreshToken missing/empty/too long");
1472
+ logger.debug("[PollarClient:session] Invalid session \u2014 token.refreshToken missing/empty/too long");
1479
1473
  return false;
1480
1474
  }
1481
1475
  if (typeof t["expiresAt"] !== "number" || !Number.isFinite(t["expiresAt"])) {
1482
- console.warn("[PollarClient:session] Invalid session \u2014 token.expiresAt must be a finite number");
1476
+ logger.debug("[PollarClient:session] Invalid session \u2014 token.expiresAt must be a finite number");
1483
1477
  return false;
1484
1478
  }
1485
1479
  const user = s["user"];
1486
1480
  if (typeof user !== "object" || user === null) {
1487
- console.warn("[PollarClient:session] Invalid session \u2014 user missing or not an object");
1481
+ logger.debug("[PollarClient:session] Invalid session \u2014 user missing or not an object");
1488
1482
  return false;
1489
1483
  }
1490
1484
  const u = user;
1491
1485
  if (u["id"] !== void 0 && !isBoundedString(u["id"], MAX_USER_ID)) {
1492
- console.warn("[PollarClient:session] Invalid session \u2014 user.id must be string if present");
1486
+ logger.debug("[PollarClient:session] Invalid session \u2014 user.id must be string if present");
1493
1487
  return false;
1494
1488
  }
1495
1489
  if (typeof u["ready"] !== "boolean") {
1496
- console.warn("[PollarClient:session] Invalid session \u2014 user.ready must be boolean");
1490
+ logger.debug("[PollarClient:session] Invalid session \u2014 user.ready must be boolean");
1497
1491
  return false;
1498
1492
  }
1499
1493
  const wallet = s["wallet"];
1500
1494
  if (typeof wallet !== "object" || wallet === null) {
1501
- console.warn("[PollarClient:session] Invalid session \u2014 wallet missing or not an object");
1495
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet missing or not an object");
1502
1496
  return false;
1503
1497
  }
1504
1498
  const w = wallet;
1505
- if (w["type"] !== "custodial" && w["type"] !== "smart" && w["type"] !== "external") {
1506
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.type must be custodial|smart|external");
1499
+ if (w["type"] !== "internal" && w["type"] !== "smart" && w["type"] !== "external") {
1500
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet.type must be internal|smart|external");
1507
1501
  return false;
1508
1502
  }
1509
1503
  if (w["address"] !== null && !isBoundedString(w["address"], MAX_WALLET_PUBLIC_KEY)) {
1510
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.address must be string|null");
1504
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet.address must be string|null");
1511
1505
  return false;
1512
1506
  }
1513
1507
  if (w["existsOnStellar"] !== void 0 && typeof w["existsOnStellar"] !== "boolean") {
1514
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.existsOnStellar must be boolean if present");
1508
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet.existsOnStellar must be boolean if present");
1515
1509
  return false;
1516
1510
  }
1517
1511
  if (w["createdAt"] !== void 0 && (typeof w["createdAt"] !== "number" || !Number.isFinite(w["createdAt"]))) {
1518
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.createdAt must be a finite number if present");
1512
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet.createdAt must be a finite number if present");
1519
1513
  return false;
1520
1514
  }
1521
1515
  if (w["linkedAt"] !== void 0 && (typeof w["linkedAt"] !== "number" || !Number.isFinite(w["linkedAt"]))) {
1522
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.linkedAt must be a finite number if present");
1516
+ logger.debug("[PollarClient:session] Invalid session \u2014 wallet.linkedAt must be a finite number if present");
1523
1517
  return false;
1524
1518
  }
1525
1519
  return true;
1526
1520
  }
1527
- async function readStorage(storage, apiKeyHash) {
1521
+ async function readStorage(storage, apiKeyHash, logger = console) {
1528
1522
  const raw = await storage.get(sessionStorageKey(apiKeyHash));
1529
1523
  if (!raw) return null;
1530
1524
  try {
@@ -1534,10 +1528,13 @@ async function readStorage(storage, apiKeyHash) {
1534
1528
  if (w && w["address"] == null && typeof w["publicKey"] === "string") {
1535
1529
  w["address"] = w["publicKey"];
1536
1530
  }
1531
+ if (w && w["type"] === "custodial") {
1532
+ w["type"] = "internal";
1533
+ }
1537
1534
  }
1538
- if (!isValidSession(session)) {
1535
+ if (!isValidSession(session, logger)) {
1539
1536
  await storage.remove(sessionStorageKey(apiKeyHash));
1540
- console.warn("[PollarClient:session] Stored session is invalid \u2014 clearing storage");
1537
+ logger.warn("[PollarClient:session] Stored session is invalid \u2014 clearing storage");
1541
1538
  return null;
1542
1539
  }
1543
1540
  if (session.token.expiresAt * 1e3 < Date.now()) {
@@ -1545,7 +1542,7 @@ async function readStorage(storage, apiKeyHash) {
1545
1542
  }
1546
1543
  return session;
1547
1544
  } catch (error) {
1548
- console.error("[PollarClient:session] Failed to parse session from storage", error);
1545
+ logger.error("[PollarClient:session] Failed to parse session from storage", error);
1549
1546
  await storage.remove(sessionStorageKey(apiKeyHash));
1550
1547
  return null;
1551
1548
  }
@@ -1607,7 +1604,7 @@ function abortableDelay(ms, signal) {
1607
1604
  });
1608
1605
  }
1609
1606
  var MAX_BACKOFF_MS = 5e3;
1610
- async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200, signal) {
1607
+ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200, signal, logger = console) {
1611
1608
  let backoff = retryDelayMs;
1612
1609
  const sleep = async (ms) => {
1613
1610
  if (ms <= 0) return;
@@ -1625,7 +1622,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1625
1622
  }));
1626
1623
  } catch (e) {
1627
1624
  if (e instanceof Error && e.name === "AbortError") throw e;
1628
- console.warn("[PollarClient:stream] session-status request failed; will retry", e);
1625
+ logger.debug("[PollarClient:stream] session-status request failed; will retry", e);
1629
1626
  }
1630
1627
  if (error || !data) {
1631
1628
  await sleep(backoff);
@@ -1634,16 +1631,12 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1634
1631
  }
1635
1632
  const reader = data.getReader();
1636
1633
  const decoder = new TextDecoder();
1637
- let streamDone = false;
1638
1634
  let sawAnyChunk = false;
1639
1635
  try {
1640
1636
  while (true) {
1641
1637
  throwIfAborted(signal);
1642
1638
  const { done, value } = await reader.read();
1643
- if (done) {
1644
- streamDone = true;
1645
- break;
1646
- }
1639
+ if (done) break;
1647
1640
  sawAnyChunk = true;
1648
1641
  const chunk = decoder.decode(value);
1649
1642
  for (const message of chunk.split("\n\n").filter(Boolean)) {
@@ -1665,17 +1658,16 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1665
1658
  } catch (e) {
1666
1659
  if (e instanceof Error && e.name === "AbortError") throw e;
1667
1660
  if (e instanceof SessionStatusError) throw e;
1668
- console.warn("[PollarClient:stream] session-status stream read failed; will retry", e);
1661
+ logger.debug("[PollarClient:stream] session-status stream read failed; will retry", e);
1669
1662
  } finally {
1670
1663
  reader.releaseLock();
1671
1664
  }
1672
1665
  if (sawAnyChunk) backoff = retryDelayMs;
1673
1666
  else backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
1674
- const delay = streamDone ? backoff : 0;
1675
- if (delay) await sleep(delay);
1667
+ await sleep(backoff);
1676
1668
  }
1677
1669
  }
1678
- async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal) {
1670
+ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal, logger = console) {
1679
1671
  const url = `${baseUrl}/auth/session/status/${encodeURIComponent(clientSessionId)}/poll`;
1680
1672
  let backoff = intervalMs;
1681
1673
  const sleep = async (ms) => {
@@ -1693,7 +1685,7 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
1693
1685
  envelope = await response.json().catch(() => null);
1694
1686
  } catch (e) {
1695
1687
  if (e instanceof Error && e.name === "AbortError") throw e;
1696
- console.warn("[PollarClient:stream] session-status poll failed; will retry", e);
1688
+ logger.debug("[PollarClient:stream] session-status poll failed; will retry", e);
1697
1689
  }
1698
1690
  if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
1699
1691
  throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
@@ -1710,13 +1702,13 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
1710
1702
  }
1711
1703
  }
1712
1704
  function waitForSessionReady(args) {
1713
- const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal } = args;
1714
- return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal);
1705
+ const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal, logger = console } = args;
1706
+ return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal, logger) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal, logger);
1715
1707
  }
1716
1708
 
1717
1709
  // src/client/auth/authenticate.ts
1718
1710
  async function authenticate(clientSessionId, deps, expectedWallet) {
1719
- const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
1711
+ const { api, logger, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
1720
1712
  setAuthState({ step: "authenticating" });
1721
1713
  try {
1722
1714
  await waitForSessionReady({
@@ -1725,7 +1717,8 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
1725
1717
  clientSessionId,
1726
1718
  check: (data2) => data2?.status === "READY",
1727
1719
  useStreaming,
1728
- signal
1720
+ signal,
1721
+ logger
1729
1722
  });
1730
1723
  } catch (err) {
1731
1724
  if (err instanceof SessionStatusError) {
@@ -1750,18 +1743,19 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
1750
1743
  },
1751
1744
  signal
1752
1745
  });
1753
- if (data?.code === "SDK_LOGIN_SUCCESS" && isValidSession(data?.content)) {
1754
- if (expectedWallet && data.content.data.providers.wallet?.address !== expectedWallet) {
1746
+ if (data?.code === "SDK_LOGIN_SUCCESS" && isValidSession(data?.content, logger)) {
1747
+ const sessionWallet = data.content.data?.providers?.wallet?.address;
1748
+ if (expectedWallet && sessionWallet !== expectedWallet) {
1755
1749
  setAuthState({
1756
1750
  step: "error",
1757
1751
  previousStep: "authenticating",
1758
1752
  message: "Wallet mismatch: session wallet does not match connected wallet",
1759
1753
  errorCode: AUTH_ERROR_CODES.WALLET_AUTH_FAILED
1760
1754
  });
1761
- clearSession();
1755
+ await clearSession();
1762
1756
  return;
1763
1757
  }
1764
- storeSession(data.content);
1758
+ await storeSession(data.content);
1765
1759
  } else {
1766
1760
  setAuthState({
1767
1761
  step: "error",
@@ -1769,7 +1763,7 @@ async function authenticate(clientSessionId, deps, expectedWallet) {
1769
1763
  message: "Failed to load session",
1770
1764
  errorCode: AUTH_ERROR_CODES.AUTH_FAILED
1771
1765
  });
1772
- clearSession();
1766
+ await clearSession();
1773
1767
  }
1774
1768
  }
1775
1769
 
@@ -2068,7 +2062,9 @@ var PollarClient = class {
2068
2062
  this.apiKey = config.apiKey;
2069
2063
  this.id = randomUUID();
2070
2064
  this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
2065
+ this._log = createLogger(config.logLevel ?? "info", config.logger);
2071
2066
  this._storage = config.storage ?? defaultStorage({
2067
+ logger: this._log,
2072
2068
  onDegrade: (reason, error) => {
2073
2069
  config.onStorageDegrade?.(reason, error);
2074
2070
  this._dispatchStorageDegrade(reason, error);
@@ -2083,7 +2079,7 @@ var PollarClient = class {
2083
2079
  this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
2084
2080
  this._maxIdleMs = config.maxIdleMs;
2085
2081
  this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
2086
- this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location.origin : "");
2082
+ this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location?.origin ?? "" : "");
2087
2083
  this._api = createApiClient(this.basePath);
2088
2084
  this._wireMiddlewares();
2089
2085
  this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
@@ -2092,7 +2088,7 @@ var PollarClient = class {
2092
2088
  this._initialized = Promise.resolve();
2093
2089
  return;
2094
2090
  }
2095
- console.info(
2091
+ this._log.info(
2096
2092
  `[PollarClient] Initialized v${POLLAR_CORE_VERSION} \u2014 endpoint: ${this.basePath}, network: ${this._networkState.network}`
2097
2093
  );
2098
2094
  this._initialized = this._initialize();
@@ -2119,7 +2115,7 @@ var PollarClient = class {
2119
2115
  const sessionKey = sessionStorageKey(this._apiKeyHash);
2120
2116
  const handler = (e) => {
2121
2117
  if (e.key === sessionKey) {
2122
- this._restoreSession().catch((err) => console.error("[PollarClient] Cross-tab restore failed", err));
2118
+ this._restoreSession().catch((err) => this._log.error("[PollarClient] Cross-tab restore failed", err));
2123
2119
  }
2124
2120
  };
2125
2121
  window.addEventListener("storage", handler);
@@ -2128,7 +2124,7 @@ var PollarClient = class {
2128
2124
  try {
2129
2125
  await this._keyManager.init();
2130
2126
  } catch (err) {
2131
- console.warn("[PollarClient] KeyManager init failed; DPoP unavailable for this session", err);
2127
+ this._log.warn("[PollarClient] KeyManager init failed; DPoP unavailable for this session", err);
2132
2128
  }
2133
2129
  await this._restoreSession();
2134
2130
  this._visibilityUnsubscribe = this._visibilityProvider.onChange((visible) => {
@@ -2169,7 +2165,7 @@ var PollarClient = class {
2169
2165
  try {
2170
2166
  self._requestBodyCache.set(request, await request.clone().arrayBuffer());
2171
2167
  } catch (err) {
2172
- console.warn("[PollarClient] Could not snapshot request body for retry", err);
2168
+ this._log.warn("[PollarClient] Could not snapshot request body for retry", err);
2173
2169
  }
2174
2170
  }
2175
2171
  const isRefresh = request.url.includes("/auth/refresh");
@@ -2228,7 +2224,7 @@ var PollarClient = class {
2228
2224
  this._keyManager
2229
2225
  );
2230
2226
  } catch (err) {
2231
- console.warn("[PollarClient] DPoP proof build failed", err);
2227
+ this._log.warn("[PollarClient] DPoP proof build failed", err);
2232
2228
  return null;
2233
2229
  }
2234
2230
  }
@@ -2282,7 +2278,7 @@ var PollarClient = class {
2282
2278
  async _doRefresh() {
2283
2279
  const refreshToken = this._session?.token?.refreshToken;
2284
2280
  if (!refreshToken) {
2285
- console.warn("[PollarClient] Refresh skipped: no refresh token in session");
2281
+ this._log.warn("[PollarClient] Refresh skipped: no refresh token in session");
2286
2282
  await this._clearSession();
2287
2283
  throw new Error("No refresh token available");
2288
2284
  }
@@ -2293,18 +2289,18 @@ var PollarClient = class {
2293
2289
  data = response.data;
2294
2290
  error = response.error;
2295
2291
  } catch (err) {
2296
- console.error("[PollarClient] /auth/refresh request threw", err);
2292
+ this._log.error("[PollarClient] /auth/refresh request threw", err);
2297
2293
  await this._clearSession();
2298
2294
  throw err;
2299
2295
  }
2300
2296
  if (error || !data) {
2301
- console.error("[PollarClient] /auth/refresh returned error", { error });
2297
+ this._log.error("[PollarClient] /auth/refresh returned error", { error });
2302
2298
  await this._clearSession();
2303
2299
  throw new Error("Refresh failed");
2304
2300
  }
2305
2301
  const successData = data;
2306
2302
  if (!successData.success || !successData.content?.token) {
2307
- console.error("[PollarClient] /auth/refresh response malformed", {
2303
+ this._log.error("[PollarClient] /auth/refresh response malformed", {
2308
2304
  success: successData.success,
2309
2305
  hasToken: !!successData.content?.token
2310
2306
  });
@@ -2313,7 +2309,7 @@ var PollarClient = class {
2313
2309
  }
2314
2310
  const newToken = successData.content.token;
2315
2311
  if (typeof newToken.accessToken !== "string" || typeof newToken.refreshToken !== "string" || typeof newToken.expiresAt !== "number") {
2316
- console.error("[PollarClient] /auth/refresh token shape invalid", {
2312
+ this._log.error("[PollarClient] /auth/refresh token shape invalid", {
2317
2313
  accessToken: typeof newToken.accessToken,
2318
2314
  refreshToken: typeof newToken.refreshToken,
2319
2315
  expiresAt: typeof newToken.expiresAt
@@ -2325,9 +2321,9 @@ var PollarClient = class {
2325
2321
  try {
2326
2322
  this._session = { ...this._session, token: newToken };
2327
2323
  await writeStorage(this._storage, this.apiKeyHash, this._session);
2328
- console.info("[PollarClient] Tokens refreshed");
2324
+ this._log.info("[PollarClient] Tokens refreshed");
2329
2325
  } catch (err) {
2330
- console.error("[PollarClient] Failed to persist refreshed session", err);
2326
+ this._log.error("[PollarClient] Failed to persist refreshed session", err);
2331
2327
  }
2332
2328
  this._scheduleNextRefresh();
2333
2329
  }
@@ -2381,7 +2377,7 @@ var PollarClient = class {
2381
2377
  try {
2382
2378
  await this.refresh();
2383
2379
  } catch (err) {
2384
- console.warn("[PollarClient] Proactive refresh failed; session cleared", err);
2380
+ this._log.warn("[PollarClient] Proactive refresh failed; session cleared", err);
2385
2381
  }
2386
2382
  }
2387
2383
  _clearRefreshTimer() {
@@ -2427,7 +2423,7 @@ var PollarClient = class {
2427
2423
  try {
2428
2424
  cb(reason, error);
2429
2425
  } catch (err) {
2430
- console.error("[PollarClient] onStorageDegrade listener threw", err);
2426
+ this._log.error("[PollarClient] onStorageDegrade listener threw", err);
2431
2427
  }
2432
2428
  }
2433
2429
  }
@@ -2547,20 +2543,20 @@ var PollarClient = class {
2547
2543
  warnServerSide("logout");
2548
2544
  return;
2549
2545
  }
2550
- console.info("[PollarClient] Logout requested", { everywhere: !!options.everywhere });
2546
+ this._log.info("[PollarClient] Logout requested", { everywhere: !!options.everywhere });
2551
2547
  if (this._session?.token?.accessToken) {
2552
2548
  try {
2553
2549
  await this._api.POST("/auth/logout", {
2554
2550
  body: options.everywhere ? { everywhere: true } : {}
2555
2551
  });
2556
2552
  } catch (err) {
2557
- console.warn("[PollarClient] Server logout failed (continuing with local clear)", err);
2553
+ this._log.warn("[PollarClient] Server logout failed (continuing with local clear)", err);
2558
2554
  }
2559
2555
  }
2560
2556
  try {
2561
2557
  await this._clearSession();
2562
2558
  } catch (err) {
2563
- console.warn("[PollarClient] Local logout cleanup failed", err);
2559
+ this._log.warn("[PollarClient] Local logout cleanup failed", err);
2564
2560
  }
2565
2561
  }
2566
2562
  /** Convenience: revoke every active session for this user (all devices). */
@@ -2636,6 +2632,14 @@ var PollarClient = class {
2636
2632
  getNetworkState() {
2637
2633
  return this._networkState;
2638
2634
  }
2635
+ /**
2636
+ * The client's level-gated logger (built from `logLevel` / `logger`). Exposed
2637
+ * so the runtime layer (`@pollar/react`) can route its own logs through the
2638
+ * same level and sink instead of calling `console` directly.
2639
+ */
2640
+ getLogger() {
2641
+ return this._log;
2642
+ }
2639
2643
  setNetwork(network) {
2640
2644
  this._setNetworkState({ step: "connected", network });
2641
2645
  }
@@ -2784,7 +2788,7 @@ var PollarClient = class {
2784
2788
  this._setTransactionState({ step: "error", phase: "building", ...details && { details } });
2785
2789
  return { status: "error", ...details && { details } };
2786
2790
  } catch (err) {
2787
- console.error("[PollarClient] buildTx failed", err);
2791
+ this._log.error("[PollarClient] buildTx failed", err);
2788
2792
  this._setTransactionState({ step: "error", phase: "building" });
2789
2793
  return { status: "error" };
2790
2794
  }
@@ -3297,6 +3301,7 @@ var PollarClient = class {
3297
3301
  _flowDeps(signal) {
3298
3302
  return {
3299
3303
  api: this._api,
3304
+ logger: this._log,
3300
3305
  basePath: this.basePath,
3301
3306
  // SSE status streaming works on web; React Native's `fetch` has no
3302
3307
  // readable `response.body`, so those clients poll the non-streaming
@@ -3349,12 +3354,12 @@ var PollarClient = class {
3349
3354
  }
3350
3355
  _handleFlowError(error) {
3351
3356
  if (error instanceof Error && error.name === "AbortError") {
3352
- console.info("[PollarClient] Login cancelled");
3357
+ this._log.debug("[PollarClient] Login cancelled");
3353
3358
  this._setAuthState({ step: "idle" });
3354
3359
  return;
3355
3360
  }
3356
3361
  if (error instanceof Error && error.code === AUTH_ERROR_CODES.WALLET_RESOLVER_TIMEOUT) {
3357
- console.error("[PollarClient]", error.message);
3362
+ this._log.error("[PollarClient]", error.message);
3358
3363
  this._setAuthState({
3359
3364
  step: "error",
3360
3365
  previousStep: this._authState.step,
@@ -3363,7 +3368,7 @@ var PollarClient = class {
3363
3368
  });
3364
3369
  return;
3365
3370
  }
3366
- console.error("[PollarClient] Unexpected error in auth flow", error);
3371
+ this._log.error("[PollarClient] Unexpected error in auth flow", error);
3367
3372
  this._setAuthState({
3368
3373
  step: "error",
3369
3374
  previousStep: this._authState.step,
@@ -3372,22 +3377,25 @@ var PollarClient = class {
3372
3377
  });
3373
3378
  }
3374
3379
  async _restoreSession() {
3375
- this._session = await readStorage(this._storage, this.apiKeyHash);
3380
+ this._session = await readStorage(this._storage, this.apiKeyHash, this._log);
3376
3381
  if (this._session) {
3377
3382
  const storedType = await readWalletType(this._storage, this.apiKeyHash);
3378
3383
  if (storedType) {
3379
3384
  try {
3380
3385
  this._walletAdapter = await this._resolveWalletAdapter(storedType);
3381
3386
  } catch (err) {
3382
- console.warn("[PollarClient] Could not restore wallet adapter for stored id", { id: storedType, err });
3387
+ this._log.warn("[PollarClient] Could not restore wallet adapter for stored id", { id: storedType, err });
3383
3388
  }
3384
3389
  }
3385
- console.info("[PollarClient] Session restored from storage");
3390
+ this._log.info("[PollarClient] Session restored from storage");
3386
3391
  this._setAuthState({ step: "authenticated", session: this._session, verified: false });
3387
3392
  this._scheduleNextRefresh();
3388
3393
  void this._resume();
3389
3394
  } else {
3390
- console.info("[PollarClient] No session in storage");
3395
+ this._log.info("[PollarClient] No session in storage");
3396
+ if (this._authState.step !== "idle") {
3397
+ await this._clearSession();
3398
+ }
3391
3399
  }
3392
3400
  }
3393
3401
  /**
@@ -3418,13 +3426,13 @@ var PollarClient = class {
3418
3426
  this._setAuthState({ step: "authenticated", session: this._session, verified: true });
3419
3427
  } catch (err) {
3420
3428
  if (err?.name === "AbortError") return;
3421
- console.warn("[PollarClient] resume failed (network); will retry", err);
3429
+ this._log.warn("[PollarClient] resume failed (network); will retry", err);
3422
3430
  } finally {
3423
3431
  if (this._resumeController === controller) this._resumeController = null;
3424
3432
  }
3425
3433
  }
3426
3434
  async _storeSession(session) {
3427
- console.info("[PollarClient] Session stored");
3435
+ this._log.info("[PollarClient] Session stored");
3428
3436
  const w = session.wallet;
3429
3437
  const persisted = {
3430
3438
  clientSessionId: session.clientSessionId,
@@ -3434,8 +3442,11 @@ var PollarClient = class {
3434
3442
  user: session.user,
3435
3443
  // The wire response still carries the legacy `publicKey` alias (kept for
3436
3444
  // older SDKs); the persisted session standardizes on `address` only.
3445
+ // The wire also still emits the legacy type `'custodial'` (unchanged for
3446
+ // SDKs ≤0.8.x); we remap it to `'internal'` here so the SDK surface and
3447
+ // persisted session speak one vocabulary while the wire stays compatible.
3437
3448
  wallet: {
3438
- type: w.type,
3449
+ type: w.type === "custodial" ? "internal" : w.type,
3439
3450
  address: w.address ?? w.publicKey ?? null,
3440
3451
  ...w.existsOnStellar !== void 0 ? { existsOnStellar: w.existsOnStellar } : {},
3441
3452
  ...w.createdAt !== void 0 ? { createdAt: w.createdAt } : {},
@@ -3459,7 +3470,7 @@ var PollarClient = class {
3459
3470
  this._scheduleNextRefresh();
3460
3471
  }
3461
3472
  async _clearSession() {
3462
- console.info("[PollarClient] Session cleared");
3473
+ this._log.info("[PollarClient] Session cleared");
3463
3474
  this._clearRefreshTimer();
3464
3475
  this._session = null;
3465
3476
  this._profile = null;
@@ -3468,7 +3479,7 @@ var PollarClient = class {
3468
3479
  try {
3469
3480
  await this._keyManager.reset();
3470
3481
  } catch (err) {
3471
- console.warn("[PollarClient] KeyManager reset failed during clearSession", err);
3482
+ this._log.warn("[PollarClient] KeyManager reset failed during clearSession", err);
3472
3483
  }
3473
3484
  await removeStorage(this._storage, this.apiKeyHash);
3474
3485
  this._transactionState = null;
@@ -3480,17 +3491,17 @@ var PollarClient = class {
3480
3491
  _setNetworkState(next) {
3481
3492
  this._networkState = next;
3482
3493
  const label = next.step === "connected" ? next.network : next.step;
3483
- console.info(`[PollarClient] network:${label}`);
3494
+ this._log.debug(`[PollarClient] network:${label}`);
3484
3495
  for (const cb of this._networkStateListeners) cb(next);
3485
3496
  }
3486
3497
  _setAuthState(next) {
3487
3498
  this._authState = next;
3488
- console.info(`[PollarClient] auth:${next.step}`);
3499
+ this._log.debug(`[PollarClient] auth:${next.step}`);
3489
3500
  for (const cb of this._authStateListeners) cb(next);
3490
3501
  }
3491
3502
  _setTransactionState(next) {
3492
3503
  this._transactionState = next;
3493
- console.info(`[PollarClient] transaction:${next.step}`);
3504
+ this._log.debug(`[PollarClient] transaction:${next.step}`);
3494
3505
  for (const cb of this._transactionStateListeners) cb(next);
3495
3506
  }
3496
3507
  /**
@@ -3538,6 +3549,6 @@ var StellarClient = class {
3538
3549
  // src/index.ts
3539
3550
  _setDefaultKeyManagerFactory((_storage, apiKey) => new WebCryptoKeyManager(apiKey));
3540
3551
 
3541
- export { AUTH_ERROR_CODES, AlbedoAdapter, FreighterAdapter, 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 };
3552
+ export { AUTH_ERROR_CODES, AlbedoAdapter, FreighterAdapter, 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 };
3542
3553
  //# sourceMappingURL=index.mjs.map
3543
3554
  //# sourceMappingURL=index.mjs.map