@pollar/core 0.8.1 → 0.9.0-rc.0

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.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var sha2 = require('@noble/hashes/sha2');
4
+
3
5
  var __create = Object.create;
4
6
  var __defProp = Object.defineProperty;
5
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -185,20 +187,6 @@ function defaultKeyManager(storage, apiKey) {
185
187
  return _factory(storage, apiKey);
186
188
  }
187
189
 
188
- // src/lib/sha256.ts
189
- async function sha256(data) {
190
- const buf = await crypto.subtle.digest("SHA-256", data);
191
- return new Uint8Array(buf);
192
- }
193
-
194
- // src/lib/api-key-hash.ts
195
- async function hashApiKey(apiKey) {
196
- const digest = await sha256(new TextEncoder().encode(apiKey));
197
- let hex = "";
198
- for (let i = 0; i < 4; i++) hex += digest[i].toString(16).padStart(2, "0");
199
- return hex;
200
- }
201
-
202
190
  // src/lib/base64url.ts
203
191
  var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
204
192
  (() => {
@@ -235,6 +223,17 @@ function base64urlEncode(bytes) {
235
223
  function base64urlEncodeString(s) {
236
224
  return base64urlEncode(new TextEncoder().encode(s));
237
225
  }
226
+ async function sha256(data) {
227
+ return sha2.sha256(data);
228
+ }
229
+
230
+ // src/lib/api-key-hash.ts
231
+ async function hashApiKey(apiKey) {
232
+ const digest = await sha256(new TextEncoder().encode(apiKey));
233
+ let hex = "";
234
+ for (let i = 0; i < 4; i++) hex += digest[i].toString(16).padStart(2, "0");
235
+ return hex;
236
+ }
238
237
 
239
238
  // src/keys/thumbprint.ts
240
239
  async function computeJwkThumbprint(jwk) {
@@ -245,11 +244,14 @@ async function computeJwkThumbprint(jwk) {
245
244
  const digest = await sha256(new TextEncoder().encode(canonical));
246
245
  return base64urlEncode(digest);
247
246
  }
247
+ function toBase64url(value) {
248
+ return value.replace(/\+/g, "-").replace(/\//g, "_").replace(/[^A-Za-z0-9_-]/g, "");
249
+ }
248
250
  function canonicalEcJwk(jwk) {
249
251
  if (jwk.kty !== "EC" || jwk.crv !== "P-256" || typeof jwk.x !== "string" || typeof jwk.y !== "string") {
250
252
  throw new Error("[PollarClient:thumbprint] Source JWK is not an EC P-256 public key");
251
253
  }
252
- return { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
254
+ return { kty: "EC", crv: "P-256", x: toBase64url(jwk.x), y: toBase64url(jwk.y) };
253
255
  }
254
256
 
255
257
  // src/keys/web-crypto.ts
@@ -263,7 +265,7 @@ function openDb() {
263
265
  return;
264
266
  }
265
267
  const req = indexedDB.open(DB_NAME, DB_VERSION);
266
- req.onerror = () => reject(req.error ?? new Error("IDB open failed"));
268
+ req.onerror = () => reject(req.error ?? new Error("[PollarClient:keys] IDB open failed"));
267
269
  req.onsuccess = () => resolve(req.result);
268
270
  req.onupgradeneeded = () => {
269
271
  const db = req.result;
@@ -276,7 +278,7 @@ function openDb() {
276
278
  function awaitTx(req) {
277
279
  return new Promise((resolve, reject) => {
278
280
  req.onsuccess = () => resolve(req.result);
279
- req.onerror = () => reject(req.error ?? new Error("IDB request failed"));
281
+ req.onerror = () => reject(req.error ?? new Error("[PollarClient:keys] IDB request failed"));
280
282
  });
281
283
  }
282
284
  async function dbGet(key) {
@@ -371,10 +373,39 @@ var WebCryptoKeyManager = class {
371
373
  }
372
374
  }
373
375
  this.keyPair = pair;
374
- const exported = await globalThis.crypto.subtle.exportKey("jwk", pair.publicKey);
375
- this.publicJwk = canonicalEcJwk(exported);
376
+ this.publicJwk = await this._exportPublicJwk(pair.publicKey);
376
377
  this.thumbprint = await computeJwkThumbprint(this.publicJwk);
377
378
  }
379
+ /**
380
+ * Derive the public JWK from a `CryptoKey`. Prefers the `'raw'` export (the
381
+ * 65-byte uncompressed point `0x04 || X(32) || Y(32)`) and base64url-encodes
382
+ * the coordinates ourselves — that sidesteps polyfills whose `exportKey('jwk')`
383
+ * emits non-base64url `x`/`y` (standard base64, `=` padding, or — as seen with
384
+ * `react-native-quick-crypto` — a stray `.`). Real browsers and most polyfills
385
+ * support `'raw'` for public EC keys.
386
+ *
387
+ * Falls back to the `'jwk'` export (normalized via `canonicalEcJwk`) if `'raw'`
388
+ * is unsupported or returns an unexpected shape, so this can't regress on a
389
+ * runtime that only implements the JWK path. Both routes yield identical
390
+ * coordinate bytes, so the `cnf.jkt` thumbprint is unchanged either way.
391
+ */
392
+ async _exportPublicJwk(publicKey) {
393
+ try {
394
+ const raw = new Uint8Array(await globalThis.crypto.subtle.exportKey("raw", publicKey));
395
+ if (raw.length !== 65 || raw[0] !== 4) {
396
+ throw new Error(`[PollarClient:keys] Unexpected raw EC point (len=${raw.length}, tag=${raw[0]})`);
397
+ }
398
+ return {
399
+ kty: "EC",
400
+ crv: "P-256",
401
+ x: base64urlEncode(raw.slice(1, 33)),
402
+ y: base64urlEncode(raw.slice(33, 65))
403
+ };
404
+ } catch {
405
+ const jwk = await globalThis.crypto.subtle.exportKey("jwk", publicKey);
406
+ return canonicalEcJwk(jwk);
407
+ }
408
+ }
378
409
  async reset() {
379
410
  try {
380
411
  if (this.apiKeyHash) await dbDelete(this.apiKeyHash);
@@ -1132,6 +1163,9 @@ function defaultStorage(options = {}) {
1132
1163
  return createLocalStorageAdapter(options);
1133
1164
  }
1134
1165
 
1166
+ // src/version.ts
1167
+ var POLLAR_CORE_VERSION = "0.9.0-rc.0" ;
1168
+
1135
1169
  // src/visibility/noop.ts
1136
1170
  function createNoopVisibilityProvider() {
1137
1171
  return {
@@ -1196,6 +1230,7 @@ var AUTH_ERROR_CODES = {
1196
1230
  WALLET_CONNECT_FAILED: "WALLET_CONNECT_FAILED",
1197
1231
  WALLET_AUTH_FAILED: "WALLET_AUTH_FAILED",
1198
1232
  WALLET_RESOLVER_TIMEOUT: "WALLET_RESOLVER_TIMEOUT",
1233
+ PASSKEY_FAILED: "PASSKEY_FAILED",
1199
1234
  UNEXPECTED_ERROR: "UNEXPECTED_ERROR"
1200
1235
  };
1201
1236
  var PollarFlowError = class extends Error {
@@ -1241,7 +1276,7 @@ var FreighterAdapter = class {
1241
1276
  if (!userInfo?.publicKey) {
1242
1277
  throw new Error("Failed to get user information from Freighter");
1243
1278
  }
1244
- return { address: userInfo.publicKey, publicKey: userInfo.publicKey };
1279
+ return { address: userInfo.publicKey };
1245
1280
  }
1246
1281
  async disconnect() {
1247
1282
  }
@@ -1279,6 +1314,19 @@ var FreighterAdapter = class {
1279
1314
  };
1280
1315
 
1281
1316
  // src/wallets/AlbedoAdapter.ts
1317
+ var PUBLIC_PASSPHRASE = "Public Global Stellar Network ; September 2015";
1318
+ var TESTNET_PASSPHRASE = "Test SDF Network ; September 2015";
1319
+ function albedoNetwork(options, fallback) {
1320
+ switch (options?.networkPassphrase) {
1321
+ case PUBLIC_PASSPHRASE:
1322
+ return "public";
1323
+ case TESTNET_PASSPHRASE:
1324
+ return "testnet";
1325
+ }
1326
+ if (options?.network === "public" || options?.network === "mainnet") return "public";
1327
+ if (options?.network === "testnet") return "testnet";
1328
+ return fallback;
1329
+ }
1282
1330
  function openAlbedoPopup(url) {
1283
1331
  const popup = window.open(url, "albedo", "width=420,height=720,resizable=yes,scrollbars=yes");
1284
1332
  if (!popup) {
@@ -1317,7 +1365,13 @@ function waitForAlbedoResult() {
1317
1365
  });
1318
1366
  }
1319
1367
  var AlbedoAdapter = class {
1320
- constructor() {
1368
+ /**
1369
+ * Network used for `connect` and `signAuthEntry` (which carry no per-call
1370
+ * network) and as the fallback for `signTransaction`. Defaults to `'testnet'`
1371
+ * to preserve the previous behavior when constructed with no argument.
1372
+ */
1373
+ constructor(network = "testnet") {
1374
+ this.network = network;
1321
1375
  this.type = "albedo" /* ALBEDO */;
1322
1376
  }
1323
1377
  async isAvailable() {
@@ -1327,7 +1381,7 @@ var AlbedoAdapter = class {
1327
1381
  const url = new URL("https://albedo.link");
1328
1382
  url.searchParams.set("intent", "public-key");
1329
1383
  url.searchParams.set("app_name", "Pollar");
1330
- url.searchParams.set("network", "testnet");
1384
+ url.searchParams.set("network", this.network);
1331
1385
  url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
1332
1386
  url.searchParams.set("origin", window.location.origin);
1333
1387
  openAlbedoPopup(url.toString());
@@ -1335,7 +1389,7 @@ var AlbedoAdapter = class {
1335
1389
  if (!result.pubkey) {
1336
1390
  throw new Error("Albedo connection rejected");
1337
1391
  }
1338
- return { address: result.pubkey, publicKey: result.pubkey };
1392
+ return { address: result.pubkey };
1339
1393
  }
1340
1394
  async disconnect() {
1341
1395
  }
@@ -1345,12 +1399,12 @@ var AlbedoAdapter = class {
1345
1399
  async getNetwork() {
1346
1400
  throw new Error("Albedo does not expose network");
1347
1401
  }
1348
- async signTransaction(xdr, _options) {
1402
+ async signTransaction(xdr, options) {
1349
1403
  const url = new URL("https://albedo.link");
1350
1404
  url.searchParams.set("intent", "tx");
1351
1405
  url.searchParams.set("xdr", xdr);
1352
1406
  url.searchParams.set("app_name", "Pollar");
1353
- url.searchParams.set("network", "testnet");
1407
+ url.searchParams.set("network", albedoNetwork(options, this.network));
1354
1408
  url.searchParams.set("callback", window.location.href);
1355
1409
  url.searchParams.set("origin", window.location.origin);
1356
1410
  window.location.href = url.toString();
@@ -1363,7 +1417,7 @@ var AlbedoAdapter = class {
1363
1417
  url.searchParams.set("intent", "sign-auth-entry");
1364
1418
  url.searchParams.set("xdr", entryXdr);
1365
1419
  url.searchParams.set("app_name", "Pollar");
1366
- url.searchParams.set("network", "testnet");
1420
+ url.searchParams.set("network", this.network);
1367
1421
  url.searchParams.set("callback", window.location.href);
1368
1422
  url.searchParams.set("origin", window.location.origin);
1369
1423
  window.location.href = url.toString();
@@ -1450,8 +1504,12 @@ function isValidSession(value) {
1450
1504
  return false;
1451
1505
  }
1452
1506
  const w = wallet;
1453
- if (w["publicKey"] !== null && !isBoundedString(w["publicKey"], MAX_WALLET_PUBLIC_KEY)) {
1454
- console.warn("[PollarClient:session] Invalid session \u2014 wallet.publicKey must be string|null");
1507
+ if (w["type"] !== "custodial" && w["type"] !== "smart" && w["type"] !== "external") {
1508
+ console.warn("[PollarClient:session] Invalid session \u2014 wallet.type must be custodial|smart|external");
1509
+ return false;
1510
+ }
1511
+ if (w["address"] !== null && !isBoundedString(w["address"], MAX_WALLET_PUBLIC_KEY)) {
1512
+ console.warn("[PollarClient:session] Invalid session \u2014 wallet.address must be string|null");
1455
1513
  return false;
1456
1514
  }
1457
1515
  if (w["existsOnStellar"] !== void 0 && typeof w["existsOnStellar"] !== "boolean") {
@@ -1462,6 +1520,10 @@ function isValidSession(value) {
1462
1520
  console.warn("[PollarClient:session] Invalid session \u2014 wallet.createdAt must be a finite number if present");
1463
1521
  return false;
1464
1522
  }
1523
+ if (w["linkedAt"] !== void 0 && (typeof w["linkedAt"] !== "number" || !Number.isFinite(w["linkedAt"]))) {
1524
+ console.warn("[PollarClient:session] Invalid session \u2014 wallet.linkedAt must be a finite number if present");
1525
+ return false;
1526
+ }
1465
1527
  return true;
1466
1528
  }
1467
1529
  async function readStorage(storage, apiKeyHash) {
@@ -1469,6 +1531,12 @@ async function readStorage(storage, apiKeyHash) {
1469
1531
  if (!raw) return null;
1470
1532
  try {
1471
1533
  const session = JSON.parse(raw);
1534
+ if (typeof session === "object" && session !== null) {
1535
+ const w = session.wallet;
1536
+ if (w && w["address"] == null && typeof w["publicKey"] === "string") {
1537
+ w["address"] = w["publicKey"];
1538
+ }
1539
+ }
1472
1540
  if (!isValidSession(session)) {
1473
1541
  await storage.remove(sessionStorageKey(apiKeyHash));
1474
1542
  console.warn("[PollarClient:session] Stored session is invalid \u2014 clearing storage");
@@ -1559,7 +1627,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1559
1627
  }));
1560
1628
  } catch (e) {
1561
1629
  if (e instanceof Error && e.name === "AbortError") throw e;
1562
- console.warn(e);
1630
+ console.warn("[PollarClient:stream] session-status request failed; will retry", e);
1563
1631
  }
1564
1632
  if (error || !data) {
1565
1633
  await sleep(backoff);
@@ -1599,7 +1667,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1599
1667
  } catch (e) {
1600
1668
  if (e instanceof Error && e.name === "AbortError") throw e;
1601
1669
  if (e instanceof SessionStatusError) throw e;
1602
- console.warn(e);
1670
+ console.warn("[PollarClient:stream] session-status stream read failed; will retry", e);
1603
1671
  } finally {
1604
1672
  reader.releaseLock();
1605
1673
  }
@@ -1627,7 +1695,7 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
1627
1695
  envelope = await response.json().catch(() => null);
1628
1696
  } catch (e) {
1629
1697
  if (e instanceof Error && e.name === "AbortError") throw e;
1630
- console.warn(e);
1698
+ console.warn("[PollarClient:stream] session-status poll failed; will retry", e);
1631
1699
  }
1632
1700
  if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
1633
1701
  throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
@@ -1831,6 +1899,55 @@ async function loginOAuth(provider, deps) {
1831
1899
  await authenticate(clientSessionId, deps);
1832
1900
  }
1833
1901
 
1902
+ // src/client/auth/passkeyFlow.ts
1903
+ async function loginSmartWallet(deps) {
1904
+ const { api, signal, setAuthState, passkey } = deps;
1905
+ if (!passkey) {
1906
+ setAuthState({
1907
+ step: "error",
1908
+ previousStep: "creating_session",
1909
+ message: "Passkey support is not configured",
1910
+ errorCode: AUTH_ERROR_CODES.PASSKEY_FAILED
1911
+ });
1912
+ return;
1913
+ }
1914
+ const clientSessionId = await createAuthSession(deps);
1915
+ if (!clientSessionId) return;
1916
+ try {
1917
+ const { data: challengeData } = await api.POST("/auth/passkey/challenge", {
1918
+ body: { clientSessionId },
1919
+ signal
1920
+ });
1921
+ const challenge = challengeData?.content?.challenge;
1922
+ if (!challengeData?.success || !challenge) {
1923
+ return failPasskey(setAuthState, "Failed to start passkey");
1924
+ }
1925
+ setAuthState({ step: "creating_passkey" });
1926
+ const ceremony = await passkey({ challenge });
1927
+ const response = ceremony.response;
1928
+ if (ceremony.kind === "register") {
1929
+ setAuthState({ step: "deploying_smart_account" });
1930
+ const { data } = await api.POST("/auth/passkey/register", {
1931
+ body: { clientSessionId, response },
1932
+ signal
1933
+ });
1934
+ if (!data?.success) return failPasskey(setAuthState, "Passkey registration failed");
1935
+ } else {
1936
+ const { data } = await api.POST("/auth/passkey/login", {
1937
+ body: { clientSessionId, response },
1938
+ signal
1939
+ });
1940
+ if (!data?.success) return failPasskey(setAuthState, "Passkey authentication failed");
1941
+ }
1942
+ } catch {
1943
+ return failPasskey(setAuthState, "Passkey login failed");
1944
+ }
1945
+ await authenticate(clientSessionId, deps);
1946
+ }
1947
+ function failPasskey(setAuthState, message) {
1948
+ setAuthState({ step: "error", previousStep: "creating_passkey", message, errorCode: AUTH_ERROR_CODES.PASSKEY_FAILED });
1949
+ }
1950
+
1834
1951
  // src/client/auth/walletFlow.ts
1835
1952
  function withSignal(promise, signal) {
1836
1953
  return Promise.race([
@@ -1857,12 +1974,12 @@ async function loginWallet(type, deps) {
1857
1974
  setAuthState({ step: "wallet_not_installed", walletType: type });
1858
1975
  return;
1859
1976
  }
1860
- const { publicKey } = await withSignal(adapter.connect(), signal);
1861
- connectedWallet = publicKey;
1977
+ const { address } = await withSignal(adapter.connect(), signal);
1978
+ connectedWallet = address;
1862
1979
  deps.storeWalletAdapter(adapter, type);
1863
1980
  setAuthState({ step: "authenticating_wallet" });
1864
1981
  const { data: walletData, error: walletError } = await api.POST("/auth/wallet", {
1865
- body: { clientSessionId, walletAddress: publicKey },
1982
+ body: { clientSessionId, walletAddress: address },
1866
1983
  signal
1867
1984
  });
1868
1985
  if (walletError || !walletData?.success) {
@@ -1927,8 +2044,12 @@ var PollarClient = class {
1927
2044
  this._transactionStateListeners = /* @__PURE__ */ new Set();
1928
2045
  this._txHistoryState = { step: "idle" };
1929
2046
  this._txHistoryStateListeners = /* @__PURE__ */ new Set();
2047
+ this._sessionsState = { step: "idle" };
2048
+ this._sessionsStateListeners = /* @__PURE__ */ new Set();
1930
2049
  this._walletBalanceState = { step: "idle" };
1931
2050
  this._walletBalanceStateListeners = /* @__PURE__ */ new Set();
2051
+ this._enabledAssetsState = { step: "idle" };
2052
+ this._enabledAssetsStateListeners = /* @__PURE__ */ new Set();
1932
2053
  this._authState = { step: "idle" };
1933
2054
  this._authStateListeners = /* @__PURE__ */ new Set();
1934
2055
  this._networkState = { step: "idle" };
@@ -1944,6 +2065,8 @@ var PollarClient = class {
1944
2065
  this._storageDegradeListeners = /* @__PURE__ */ new Set();
1945
2066
  this._walletAdapter = null;
1946
2067
  this._loginController = null;
2068
+ /** Aborts an in-flight `/auth/session/resume` on destroy() or re-trigger. */
2069
+ this._resumeController = null;
1947
2070
  this.apiKey = config.apiKey;
1948
2071
  this.id = randomUUID();
1949
2072
  this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
@@ -1956,6 +2079,8 @@ var PollarClient = class {
1956
2079
  this._keyManager = config.keyManager ?? defaultKeyManager(this._storage, config.apiKey);
1957
2080
  this._walletAdapterResolver = config.walletAdapter ?? null;
1958
2081
  this._walletResolverTimeoutMs = config.walletResolverTimeoutMs ?? 5e3;
2082
+ this._passkey = config.passkey ?? null;
2083
+ this._passkeySign = config.passkeySign ?? null;
1959
2084
  this._deviceLabel = config.deviceLabel;
1960
2085
  this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
1961
2086
  this._maxIdleMs = config.maxIdleMs;
@@ -1969,7 +2094,9 @@ var PollarClient = class {
1969
2094
  this._initialized = Promise.resolve();
1970
2095
  return;
1971
2096
  }
1972
- console.info(`[PollarClient] Initialized \u2014 endpoint: ${this.basePath}, network: ${this._networkState.network}`);
2097
+ console.info(
2098
+ `[PollarClient] Initialized v${POLLAR_CORE_VERSION} \u2014 endpoint: ${this.basePath}, network: ${this._networkState.network}`
2099
+ );
1973
2100
  this._initialized = this._initialize();
1974
2101
  }
1975
2102
  /**
@@ -2007,7 +2134,11 @@ var PollarClient = class {
2007
2134
  }
2008
2135
  await this._restoreSession();
2009
2136
  this._visibilityUnsubscribe = this._visibilityProvider.onChange((visible) => {
2010
- if (visible) void this._maybeProactiveRefresh();
2137
+ if (!visible) return;
2138
+ void this._maybeProactiveRefresh();
2139
+ if (this._authState.step === "authenticated" && !this._authState.verified) {
2140
+ void this._resume();
2141
+ }
2011
2142
  });
2012
2143
  }
2013
2144
  /** Detach the cross-tab storage listener and abort any in-flight login. */
@@ -2018,6 +2149,8 @@ var PollarClient = class {
2018
2149
  }
2019
2150
  this._loginController?.abort();
2020
2151
  this._loginController = null;
2152
+ this._resumeController?.abort();
2153
+ this._resumeController = null;
2021
2154
  this._clearRefreshTimer();
2022
2155
  if (this._visibilityUnsubscribe) {
2023
2156
  this._visibilityUnsubscribe();
@@ -2032,7 +2165,9 @@ var PollarClient = class {
2032
2165
  request.headers.set("x-pollar-api-key", self.apiKey);
2033
2166
  self._lastRequestAt = Date.now();
2034
2167
  await self._initialized;
2035
- if (request.body !== null) {
2168
+ const cacheMethod = request.method.toUpperCase();
2169
+ const cacheBodyAllowed = cacheMethod !== "GET" && cacheMethod !== "HEAD";
2170
+ if (cacheBodyAllowed && request.body != null) {
2036
2171
  try {
2037
2172
  self._requestBodyCache.set(request, await request.clone().arrayBuffer());
2038
2173
  } catch (err) {
@@ -2119,7 +2254,9 @@ var PollarClient = class {
2119
2254
  }
2120
2255
  }
2121
2256
  }
2122
- const cachedBody = this._requestBodyCache.get(originalRequest);
2257
+ const retryMethod = originalRequest.method.toUpperCase();
2258
+ const retryBodyAllowed = retryMethod !== "GET" && retryMethod !== "HEAD";
2259
+ const cachedBody = retryBodyAllowed ? this._requestBodyCache.get(originalRequest) : void 0;
2123
2260
  const retried = new Request(originalRequest.url, {
2124
2261
  method: originalRequest.method,
2125
2262
  headers,
@@ -2163,19 +2300,26 @@ var PollarClient = class {
2163
2300
  throw err;
2164
2301
  }
2165
2302
  if (error || !data) {
2166
- console.warn("[PollarClient] /auth/refresh returned error", { error });
2303
+ console.error("[PollarClient] /auth/refresh returned error", { error });
2167
2304
  await this._clearSession();
2168
2305
  throw new Error("Refresh failed");
2169
2306
  }
2170
2307
  const successData = data;
2171
2308
  if (!successData.success || !successData.content?.token) {
2172
- console.warn("[PollarClient] /auth/refresh response malformed", successData);
2309
+ console.error("[PollarClient] /auth/refresh response malformed", {
2310
+ success: successData.success,
2311
+ hasToken: !!successData.content?.token
2312
+ });
2173
2313
  await this._clearSession();
2174
2314
  throw new Error("Refresh response malformed");
2175
2315
  }
2176
2316
  const newToken = successData.content.token;
2177
2317
  if (typeof newToken.accessToken !== "string" || typeof newToken.refreshToken !== "string" || typeof newToken.expiresAt !== "number") {
2178
- console.warn("[PollarClient] /auth/refresh token shape invalid", newToken);
2318
+ console.error("[PollarClient] /auth/refresh token shape invalid", {
2319
+ accessToken: typeof newToken.accessToken,
2320
+ refreshToken: typeof newToken.refreshToken,
2321
+ expiresAt: typeof newToken.expiresAt
2322
+ });
2179
2323
  await this._clearSession();
2180
2324
  throw new Error("Refresh response token shape invalid");
2181
2325
  }
@@ -2369,6 +2513,19 @@ var PollarClient = class {
2369
2513
  const controller = this._newController();
2370
2514
  loginWallet(type, this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
2371
2515
  }
2516
+ /**
2517
+ * "Smart Wallet" login: runs the passkey (WebAuthn) ceremony and, for a new
2518
+ * user, creates a sponsored smart-account C-address. Requires the `passkey`
2519
+ * ceremony to be configured (e.g. via `@pollar/react`).
2520
+ */
2521
+ loginSmartWallet() {
2522
+ if (!isClientRuntime) {
2523
+ warnServerSide("loginSmartWallet");
2524
+ return;
2525
+ }
2526
+ const controller = this._newController();
2527
+ loginSmartWallet(this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
2528
+ }
2372
2529
  // ─── Cancel ───────────────────────────────────────────────────────────────
2373
2530
  cancelLogin() {
2374
2531
  this._loginController?.abort();
@@ -2431,6 +2588,29 @@ var PollarClient = class {
2431
2588
  }
2432
2589
  return data.content.sessions;
2433
2590
  }
2591
+ getSessionsState() {
2592
+ return this._sessionsState;
2593
+ }
2594
+ onSessionsStateChange(cb) {
2595
+ this._sessionsStateListeners.add(cb);
2596
+ cb(this._sessionsState);
2597
+ return () => this._sessionsStateListeners.delete(cb);
2598
+ }
2599
+ /**
2600
+ * Fire-and-forget variant of {@link listSessions} that drives the observable
2601
+ * `SessionsState` store instead of returning the array. UI layers subscribe
2602
+ * via `onSessionsStateChange` and stay pure readers — mirrors `fetchTxHistory`.
2603
+ */
2604
+ async fetchSessions() {
2605
+ this._setSessionsState({ step: "loading" });
2606
+ try {
2607
+ const sessions = await this.listSessions();
2608
+ this._setSessionsState({ step: "loaded", sessions });
2609
+ } catch (err) {
2610
+ const message = err instanceof Error ? err.message : "Failed to load sessions";
2611
+ this._setSessionsState({ step: "error", message });
2612
+ }
2613
+ }
2434
2614
  /**
2435
2615
  * Revoke a specific refresh-token family (a single device session). Use
2436
2616
  * `listSessions` to enumerate the familyIds. Revoking the current session
@@ -2507,16 +2687,19 @@ var PollarClient = class {
2507
2687
  cb(this._walletBalanceState);
2508
2688
  return () => this._walletBalanceStateListeners.delete(cb);
2509
2689
  }
2510
- async refreshBalance(publicKey) {
2511
- const pk = publicKey ?? this._session?.wallet?.publicKey;
2512
- if (!pk) {
2690
+ /**
2691
+ * Refreshes the balances of the authenticated user's OWN wallet. The wallet
2692
+ * and network are resolved server-side from the session — no arguments. Drives
2693
+ * `walletBalanceState`. For an arbitrary wallet, use {@link getWalletBalance}.
2694
+ */
2695
+ async refreshBalance() {
2696
+ if (!this._session?.wallet?.address) {
2513
2697
  this._setWalletBalanceState({ step: "error", message: "No wallet connected" });
2514
2698
  return;
2515
2699
  }
2516
2700
  this._setWalletBalanceState({ step: "loading" });
2517
2701
  try {
2518
- const network = this.getNetwork();
2519
- const { data, error } = await this._api.GET("/wallet/balance", { params: { query: { publicKey: pk, network } } });
2702
+ const { data, error } = await this._api.GET("/wallet/balance");
2520
2703
  if (!error && data?.success && data.content) {
2521
2704
  this._setWalletBalanceState({ step: "loaded", data: data.content });
2522
2705
  } else {
@@ -2526,6 +2709,53 @@ var PollarClient = class {
2526
2709
  this._setWalletBalanceState({ step: "error", message: "Failed to load balance" });
2527
2710
  }
2528
2711
  }
2712
+ /**
2713
+ * General-purpose balance lookup for ANY wallet on ANY network — not scoped
2714
+ * to this application. Enumerates the account's real on-chain holdings via
2715
+ * Horizon (server-side) and returns the data directly (no reactive state).
2716
+ * `network` defaults to the client's current network.
2717
+ */
2718
+ async getWalletBalance(publicKey, network) {
2719
+ const { data, error } = await this._api.GET("/wallet/{publicKey}/balance", {
2720
+ params: { path: { publicKey }, query: { network: network ?? this.getNetwork() } }
2721
+ });
2722
+ if (error || !data?.success || !data.content) {
2723
+ throw new Error("[PollarClient] Failed to load wallet balance");
2724
+ }
2725
+ return data.content;
2726
+ }
2727
+ // ─── Enabled assets ───────────────────────────────────────────────────────
2728
+ getEnabledAssetsState() {
2729
+ return this._enabledAssetsState;
2730
+ }
2731
+ onEnabledAssetsStateChange(cb) {
2732
+ this._enabledAssetsStateListeners.add(cb);
2733
+ cb(this._enabledAssetsState);
2734
+ return () => this._enabledAssetsStateListeners.delete(cb);
2735
+ }
2736
+ /**
2737
+ * Loads the application's enabled assets paired with the authenticated
2738
+ * wallet's on-chain trustline state — so the SDK knows which trustlines still
2739
+ * need to be added. Wallet and network are resolved server-side from the
2740
+ * session. Drives `enabledAssetsState`; mirrors {@link refreshBalance}.
2741
+ */
2742
+ async refreshAssets() {
2743
+ if (!this._session?.wallet?.address) {
2744
+ this._setEnabledAssetsState({ step: "error", message: "No wallet connected" });
2745
+ return;
2746
+ }
2747
+ this._setEnabledAssetsState({ step: "loading" });
2748
+ try {
2749
+ const { data, error } = await this._api.GET("/wallet/assets");
2750
+ if (!error && data?.success && data.content) {
2751
+ this._setEnabledAssetsState({ step: "loaded", data: data.content });
2752
+ } else {
2753
+ this._setEnabledAssetsState({ step: "error", message: "Failed to load assets" });
2754
+ }
2755
+ } catch {
2756
+ this._setEnabledAssetsState({ step: "error", message: "Failed to load assets" });
2757
+ }
2758
+ }
2529
2759
  // ─── Transactions ─────────────────────────────────────────────────────────
2530
2760
  /**
2531
2761
  * Builds an unsigned XDR. Drives `_setTransactionState` for modal-style UIs
@@ -2533,14 +2763,14 @@ var PollarClient = class {
2533
2763
  * inspect the result without subscribing to state changes.
2534
2764
  */
2535
2765
  async buildTx(operation, params, options) {
2536
- if (!this._session?.wallet?.publicKey) {
2766
+ if (!this._session?.wallet?.address) {
2537
2767
  const details = "No wallet connected";
2538
2768
  this._setTransactionState({ step: "error", phase: "building", details });
2539
2769
  return { status: "error", details };
2540
2770
  }
2541
2771
  const body = {
2542
2772
  network: this.getNetwork(),
2543
- publicKey: this._session.wallet.publicKey,
2773
+ address: this._session.wallet.address,
2544
2774
  operation,
2545
2775
  params,
2546
2776
  options: options ?? {}
@@ -2581,7 +2811,7 @@ var PollarClient = class {
2581
2811
  const buildData = this._currentBuildData();
2582
2812
  this._setTransactionState({ step: "signing", ...buildData && { buildData } });
2583
2813
  if (this._walletAdapter) {
2584
- const accountToSign = this._session?.wallet?.publicKey;
2814
+ const accountToSign = this._session?.wallet?.address;
2585
2815
  const signOpts = accountToSign ? { networkPassphrase: this._networkPassphrase(), accountToSign } : { networkPassphrase: this._networkPassphrase() };
2586
2816
  try {
2587
2817
  const { signedTxXdr } = await this._walletAdapter.signTransaction(unsignedXdr, signOpts);
@@ -2602,10 +2832,10 @@ var PollarClient = class {
2602
2832
  return { status: "error", ...details && { details } };
2603
2833
  }
2604
2834
  }
2605
- const publicKey = this._session?.wallet?.publicKey ?? "";
2835
+ const address = this._session?.wallet?.address ?? "";
2606
2836
  try {
2607
2837
  const { data, error } = await this._api.POST("/tx/sign", {
2608
- body: { network: this.getNetwork(), publicKey, unsignedXdr }
2838
+ body: { network: this.getNetwork(), address, unsignedXdr }
2609
2839
  });
2610
2840
  if (!error && data?.success && data.content?.signedXdr) {
2611
2841
  const { signedXdr, idempotencyKey } = data.content;
@@ -2658,12 +2888,12 @@ var PollarClient = class {
2658
2888
  const buildData = this._currentBuildData();
2659
2889
  const outcomeExtra = buildData ? { buildData } : {};
2660
2890
  this._setTransactionState({ step: "submitting", signedXdr, ...buildData && { buildData } });
2661
- const publicKey = this._session?.wallet?.publicKey ?? "";
2891
+ const address = this._session?.wallet?.address ?? "";
2662
2892
  try {
2663
2893
  const { data, error } = await this._api.POST("/tx/submit", {
2664
2894
  body: {
2665
2895
  network: this.getNetwork(),
2666
- publicKey,
2896
+ address,
2667
2897
  signedXdr,
2668
2898
  ...opts?.submissionToken && { idempotencyKey: opts.submissionToken }
2669
2899
  }
@@ -2723,6 +2953,19 @@ var PollarClient = class {
2723
2953
  * `success` (ledger-confirmed), or `error[phase: 'signing-submitting']`.
2724
2954
  */
2725
2955
  async signAndSubmitTx(unsignedXdr) {
2956
+ if (this._session?.wallet?.type === "smart") {
2957
+ const buildData2 = this._currentBuildData();
2958
+ if (!buildData2?.smart) {
2959
+ const details = "no prepared smart transaction; call buildTx first";
2960
+ this._setTransactionState({ step: "error", phase: "signing", details });
2961
+ return { status: "error", details };
2962
+ }
2963
+ return this._signSubmitSmart(buildData2);
2964
+ }
2965
+ if (!unsignedXdr) {
2966
+ this._setTransactionState({ step: "error", phase: "signing", details: "missing unsigned transaction" });
2967
+ return { status: "error", details: "missing unsigned transaction" };
2968
+ }
2726
2969
  if (this._walletAdapter) {
2727
2970
  const signed = await this.signTx(unsignedXdr);
2728
2971
  if (signed.status === "error") {
@@ -2740,7 +2983,7 @@ var PollarClient = class {
2740
2983
  this._setTransactionState({ step: "signing-submitting", ...buildData && { buildData } });
2741
2984
  const body = {
2742
2985
  network: this.getNetwork(),
2743
- publicKey: this._session?.wallet?.publicKey ?? "",
2986
+ address: this._session?.wallet?.address ?? "",
2744
2987
  unsignedXdr
2745
2988
  };
2746
2989
  try {
@@ -2809,14 +3052,20 @@ var PollarClient = class {
2809
3052
  * `signTx`, and `submitTx` separately instead.
2810
3053
  */
2811
3054
  async buildAndSignAndSubmitTx(operation, params, options) {
3055
+ if (this._session?.wallet?.type === "smart") {
3056
+ return this._runSmartTx(operation, params, options);
3057
+ }
2812
3058
  if (this._walletAdapter) {
2813
3059
  const built = await this.buildTx(operation, params, options);
2814
3060
  if (built.status === "error") {
2815
3061
  return { status: "error", ...built.details && { details: built.details } };
2816
3062
  }
3063
+ if (!built.buildData.unsignedXdr) {
3064
+ return { status: "error", details: "build returned no unsigned transaction" };
3065
+ }
2817
3066
  return this.signAndSubmitTx(built.buildData.unsignedXdr);
2818
3067
  }
2819
- if (!this._session?.wallet?.publicKey) {
3068
+ if (!this._session?.wallet?.address) {
2820
3069
  this._setTransactionState({ step: "error", phase: "building-signing-submitting", details: "No wallet connected" });
2821
3070
  return { status: "error", details: "No wallet connected" };
2822
3071
  }
@@ -2825,7 +3074,7 @@ var PollarClient = class {
2825
3074
  const { data, error } = await this._api.POST("/tx/build-sign-submit", {
2826
3075
  body: {
2827
3076
  network: this.getNetwork(),
2828
- publicKey: this._session.wallet.publicKey,
3077
+ address: this._session.wallet.address,
2829
3078
  operation,
2830
3079
  params,
2831
3080
  options: options ?? {}
@@ -2869,6 +3118,113 @@ var PollarClient = class {
2869
3118
  async runTx(operation, params, options) {
2870
3119
  return this.buildAndSignAndSubmitTx(operation, params, options);
2871
3120
  }
3121
+ /**
3122
+ * Smart-wallet (passkey / C-address) transaction: build (server prepares the
3123
+ * SAC transfer + returns the auth digest) → sign the digest with the passkey
3124
+ * → submit (server assembles the signed auth entry and broadcasts; the
3125
+ * sponsor pays the fee). State machine: building → built → signing →
3126
+ * submitting → success.
3127
+ */
3128
+ async _runSmartTx(operation, params, options) {
3129
+ const address = this._session?.wallet?.address;
3130
+ if (!address) {
3131
+ this._setTransactionState({ step: "error", phase: "building", details: "No wallet connected" });
3132
+ return { status: "error", details: "No wallet connected" };
3133
+ }
3134
+ if (!this._passkeySign) {
3135
+ const details = "Passkey signer not configured";
3136
+ this._setTransactionState({ step: "error", phase: "signing", details });
3137
+ return { status: "error", details };
3138
+ }
3139
+ this._setTransactionState({ step: "building" });
3140
+ let buildData;
3141
+ try {
3142
+ const body = {
3143
+ network: this.getNetwork(),
3144
+ address,
3145
+ operation,
3146
+ params,
3147
+ options: options ?? {}
3148
+ };
3149
+ const { data, error } = await this._api.POST("/tx/build", { body });
3150
+ if (error || !data?.success || !data.content?.smart) {
3151
+ const details = error?.details ?? "Failed to build transaction";
3152
+ this._setTransactionState({ step: "error", phase: "building", details });
3153
+ return { status: "error", details };
3154
+ }
3155
+ buildData = data.content;
3156
+ } catch (err) {
3157
+ const details = err instanceof Error ? err.message : void 0;
3158
+ this._setTransactionState({ step: "error", phase: "building", ...details && { details } });
3159
+ return { status: "error", ...details && { details } };
3160
+ }
3161
+ this._setTransactionState({ step: "built", buildData });
3162
+ return this._signSubmitSmart(buildData);
3163
+ }
3164
+ /**
3165
+ * Steps 2–3 of the smart-wallet flow: sign the prepared auth digest with the
3166
+ * passkey, then submit. Shared by `_runSmartTx` (atomic) and `signAndSubmitTx`
3167
+ * (split flow, when a smart build is already on the state machine).
3168
+ */
3169
+ async _signSubmitSmart(buildData) {
3170
+ const address = this._session?.wallet?.address;
3171
+ const smart = buildData.smart;
3172
+ if (!address || !smart) {
3173
+ const details = "no prepared smart transaction";
3174
+ this._setTransactionState({ step: "error", phase: "signing", buildData, details });
3175
+ return { status: "error", buildData, details };
3176
+ }
3177
+ if (!this._passkeySign) {
3178
+ const details = "Passkey signer not configured";
3179
+ this._setTransactionState({ step: "error", phase: "signing", buildData, details });
3180
+ return { status: "error", buildData, details };
3181
+ }
3182
+ this._setTransactionState({ step: "signing", buildData });
3183
+ let assertion;
3184
+ try {
3185
+ assertion = await this._passkeySign({ credentialId: smart.credentialId, challenge: smart.digest });
3186
+ } catch (err) {
3187
+ const details = err instanceof Error ? err.message : void 0;
3188
+ this._setTransactionState({ step: "error", phase: "signing", buildData, ...details && { details } });
3189
+ return { status: "error", buildData, ...details && { details } };
3190
+ }
3191
+ this._setTransactionState({ step: "submitting", buildData });
3192
+ const outcomeExtra = { buildData };
3193
+ try {
3194
+ const { data, error } = await this._api.POST("/tx/submit", {
3195
+ body: {
3196
+ network: this.getNetwork(),
3197
+ address,
3198
+ smart: { entryXdr: smart.entryXdr, funcXdr: smart.funcXdr, assertion }
3199
+ }
3200
+ });
3201
+ if (!error && data?.success && data.content) {
3202
+ const { hash, status: backendStatus, resultCode } = data.content;
3203
+ if (backendStatus === "SUCCESS") {
3204
+ this._setTransactionState({ step: "success", hash, buildData });
3205
+ return { status: "success", hash, ...outcomeExtra };
3206
+ }
3207
+ if (backendStatus === "PENDING") {
3208
+ this._setTransactionState({ step: "submitted", hash, buildData });
3209
+ return { status: "pending", hash, ...outcomeExtra };
3210
+ }
3211
+ this._setTransactionState({
3212
+ step: "error",
3213
+ phase: "submitting",
3214
+ buildData,
3215
+ ...resultCode && { details: resultCode }
3216
+ });
3217
+ return { status: "error", hash, ...outcomeExtra, ...resultCode && { details: resultCode, resultCode } };
3218
+ }
3219
+ const details = error?.details;
3220
+ this._setTransactionState({ step: "error", phase: "submitting", buildData, ...details && { details } });
3221
+ return { status: "error", ...outcomeExtra, ...details && { details } };
3222
+ } catch (err) {
3223
+ const details = err instanceof Error ? err.message : void 0;
3224
+ this._setTransactionState({ step: "error", phase: "submitting", buildData, ...details && { details } });
3225
+ return { status: "error", ...outcomeExtra, ...details && { details } };
3226
+ }
3227
+ }
2872
3228
  // ─── App config ───────────────────────────────────────────────────────────
2873
3229
  async getAppConfig() {
2874
3230
  try {
@@ -2922,10 +3278,18 @@ var PollarClient = class {
2922
3278
  this._txHistoryState = next;
2923
3279
  for (const cb of this._txHistoryStateListeners) cb(next);
2924
3280
  }
3281
+ _setSessionsState(next) {
3282
+ this._sessionsState = next;
3283
+ for (const cb of this._sessionsStateListeners) cb(next);
3284
+ }
2925
3285
  _setWalletBalanceState(next) {
2926
3286
  this._walletBalanceState = next;
2927
3287
  for (const cb of this._walletBalanceStateListeners) cb(next);
2928
3288
  }
3289
+ _setEnabledAssetsState(next) {
3290
+ this._enabledAssetsState = next;
3291
+ for (const cb of this._enabledAssetsStateListeners) cb(next);
3292
+ }
2929
3293
  // ─── Private ──────────────────────────────────────────────────────────────
2930
3294
  _newController() {
2931
3295
  this._loginController?.abort();
@@ -2950,6 +3314,7 @@ var PollarClient = class {
2950
3314
  this._walletAdapter = adapter;
2951
3315
  await writeWalletType(this._storage, this.apiKeyHash, id);
2952
3316
  },
3317
+ ...this._passkey ? { passkey: this._passkey } : {},
2953
3318
  ...this._deviceLabel ? { deviceLabel: this._deviceLabel } : {}
2954
3319
  };
2955
3320
  }
@@ -2979,7 +3344,7 @@ var PollarClient = class {
2979
3344
  }
2980
3345
  }
2981
3346
  if (id === "freighter" /* FREIGHTER */) return new FreighterAdapter();
2982
- if (id === "albedo" /* ALBEDO */) return new AlbedoAdapter();
3347
+ if (id === "albedo" /* ALBEDO */) return new AlbedoAdapter(this.getNetwork() === "mainnet" ? "public" : "testnet");
2983
3348
  throw new Error(
2984
3349
  `[PollarClient] No wallet adapter configured for "${id}". Pass a walletAdapter resolver in PollarClientConfig.`
2985
3350
  );
@@ -3020,21 +3385,66 @@ var PollarClient = class {
3020
3385
  }
3021
3386
  }
3022
3387
  console.info("[PollarClient] Session restored from storage");
3023
- this._setAuthState({ step: "authenticated", session: this._session });
3388
+ this._setAuthState({ step: "authenticated", session: this._session, verified: false });
3024
3389
  this._scheduleNextRefresh();
3390
+ void this._resume();
3025
3391
  } else {
3026
3392
  console.info("[PollarClient] No session in storage");
3027
3393
  }
3028
3394
  }
3395
+ /**
3396
+ * Validate the restored session against the server and repopulate the
3397
+ * in-memory profile (PII is never persisted, so it's null after a cold
3398
+ * reload). Goes through the normal authed client, so it coalesces with any
3399
+ * in-flight refresh (onRequest awaits `_refreshPromise`) and, being a GET,
3400
+ * is auto-retried after a 401-triggered refresh.
3401
+ *
3402
+ * - 200 → store profile, mark the session `verified`.
3403
+ * - 401 → the refresh-on-401 path already ran; if the family was
3404
+ * revoked, refresh failed and `_clearSession()` took us to
3405
+ * idle. Nothing to do here — don't double-handle.
3406
+ * - network error → stay optimistic (do NOT log out); revalidated later on
3407
+ * `visibilitychange` or first use.
3408
+ */
3409
+ async _resume() {
3410
+ if (!this._session) return;
3411
+ this._resumeController?.abort();
3412
+ const controller = new AbortController();
3413
+ this._resumeController = controller;
3414
+ try {
3415
+ const { data, error } = await this._api.GET("/auth/session/resume", { signal: controller.signal });
3416
+ if (error || !data) return;
3417
+ const content = data.content;
3418
+ if (!content || !this._session) return;
3419
+ this._profile = { ...content };
3420
+ this._setAuthState({ step: "authenticated", session: this._session, verified: true });
3421
+ } catch (err) {
3422
+ if (err?.name === "AbortError") return;
3423
+ console.warn("[PollarClient] resume failed (network); will retry", err);
3424
+ } finally {
3425
+ if (this._resumeController === controller) this._resumeController = null;
3426
+ }
3427
+ }
3029
3428
  async _storeSession(session) {
3030
3429
  console.info("[PollarClient] Session stored");
3430
+ const w = session.wallet;
3031
3431
  const persisted = {
3032
3432
  clientSessionId: session.clientSessionId,
3033
3433
  userId: session.userId ?? null,
3034
3434
  status: session.status,
3035
3435
  token: session.token,
3036
3436
  user: session.user,
3037
- wallet: session.wallet
3437
+ // The wire response still carries the legacy `publicKey` alias (kept for
3438
+ // older SDKs); the persisted session standardizes on `address` only.
3439
+ wallet: {
3440
+ type: w.type,
3441
+ address: w.address ?? w.publicKey ?? null,
3442
+ ...w.existsOnStellar !== void 0 ? { existsOnStellar: w.existsOnStellar } : {},
3443
+ ...w.createdAt !== void 0 ? { createdAt: w.createdAt } : {},
3444
+ ...w.linkedAt !== void 0 ? { linkedAt: w.linkedAt } : {},
3445
+ ...w.network !== void 0 ? { network: w.network } : {},
3446
+ ...w.deployTxHash !== void 0 ? { deployTxHash: w.deployTxHash } : {}
3447
+ }
3038
3448
  };
3039
3449
  this._session = persisted;
3040
3450
  if (session.data) {
@@ -3047,7 +3457,7 @@ var PollarClient = class {
3047
3457
  };
3048
3458
  }
3049
3459
  await writeStorage(this._storage, this.apiKeyHash, persisted);
3050
- this._setAuthState({ step: "authenticated", session: persisted });
3460
+ this._setAuthState({ step: "authenticated", session: persisted, verified: true });
3051
3461
  this._scheduleNextRefresh();
3052
3462
  }
3053
3463
  async _clearSession() {
@@ -3133,6 +3543,7 @@ _setDefaultKeyManagerFactory((_storage, apiKey) => new WebCryptoKeyManager(apiKe
3133
3543
  exports.AUTH_ERROR_CODES = AUTH_ERROR_CODES;
3134
3544
  exports.AlbedoAdapter = AlbedoAdapter;
3135
3545
  exports.FreighterAdapter = FreighterAdapter;
3546
+ exports.POLLAR_CORE_VERSION = POLLAR_CORE_VERSION;
3136
3547
  exports.PollarClient = PollarClient;
3137
3548
  exports.StellarClient = StellarClient;
3138
3549
  exports.WalletType = WalletType;