@pollar/core 0.8.2 → 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
@@ -186,17 +186,6 @@ function defaultKeyManager(storage, apiKey) {
186
186
  }
187
187
  return _factory(storage, apiKey);
188
188
  }
189
- async function sha256(data) {
190
- return sha2.sha256(data);
191
- }
192
-
193
- // src/lib/api-key-hash.ts
194
- async function hashApiKey(apiKey) {
195
- const digest = await sha256(new TextEncoder().encode(apiKey));
196
- let hex = "";
197
- for (let i = 0; i < 4; i++) hex += digest[i].toString(16).padStart(2, "0");
198
- return hex;
199
- }
200
189
 
201
190
  // src/lib/base64url.ts
202
191
  var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
@@ -234,6 +223,17 @@ function base64urlEncode(bytes) {
234
223
  function base64urlEncodeString(s) {
235
224
  return base64urlEncode(new TextEncoder().encode(s));
236
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
+ }
237
237
 
238
238
  // src/keys/thumbprint.ts
239
239
  async function computeJwkThumbprint(jwk) {
@@ -244,11 +244,14 @@ async function computeJwkThumbprint(jwk) {
244
244
  const digest = await sha256(new TextEncoder().encode(canonical));
245
245
  return base64urlEncode(digest);
246
246
  }
247
+ function toBase64url(value) {
248
+ return value.replace(/\+/g, "-").replace(/\//g, "_").replace(/[^A-Za-z0-9_-]/g, "");
249
+ }
247
250
  function canonicalEcJwk(jwk) {
248
251
  if (jwk.kty !== "EC" || jwk.crv !== "P-256" || typeof jwk.x !== "string" || typeof jwk.y !== "string") {
249
252
  throw new Error("[PollarClient:thumbprint] Source JWK is not an EC P-256 public key");
250
253
  }
251
- 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) };
252
255
  }
253
256
 
254
257
  // src/keys/web-crypto.ts
@@ -262,7 +265,7 @@ function openDb() {
262
265
  return;
263
266
  }
264
267
  const req = indexedDB.open(DB_NAME, DB_VERSION);
265
- req.onerror = () => reject(req.error ?? new Error("IDB open failed"));
268
+ req.onerror = () => reject(req.error ?? new Error("[PollarClient:keys] IDB open failed"));
266
269
  req.onsuccess = () => resolve(req.result);
267
270
  req.onupgradeneeded = () => {
268
271
  const db = req.result;
@@ -275,7 +278,7 @@ function openDb() {
275
278
  function awaitTx(req) {
276
279
  return new Promise((resolve, reject) => {
277
280
  req.onsuccess = () => resolve(req.result);
278
- req.onerror = () => reject(req.error ?? new Error("IDB request failed"));
281
+ req.onerror = () => reject(req.error ?? new Error("[PollarClient:keys] IDB request failed"));
279
282
  });
280
283
  }
281
284
  async function dbGet(key) {
@@ -370,10 +373,39 @@ var WebCryptoKeyManager = class {
370
373
  }
371
374
  }
372
375
  this.keyPair = pair;
373
- const exported = await globalThis.crypto.subtle.exportKey("jwk", pair.publicKey);
374
- this.publicJwk = canonicalEcJwk(exported);
376
+ this.publicJwk = await this._exportPublicJwk(pair.publicKey);
375
377
  this.thumbprint = await computeJwkThumbprint(this.publicJwk);
376
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
+ }
377
409
  async reset() {
378
410
  try {
379
411
  if (this.apiKeyHash) await dbDelete(this.apiKeyHash);
@@ -1131,6 +1163,9 @@ function defaultStorage(options = {}) {
1131
1163
  return createLocalStorageAdapter(options);
1132
1164
  }
1133
1165
 
1166
+ // src/version.ts
1167
+ var POLLAR_CORE_VERSION = "0.9.0-rc.0" ;
1168
+
1134
1169
  // src/visibility/noop.ts
1135
1170
  function createNoopVisibilityProvider() {
1136
1171
  return {
@@ -1195,6 +1230,7 @@ var AUTH_ERROR_CODES = {
1195
1230
  WALLET_CONNECT_FAILED: "WALLET_CONNECT_FAILED",
1196
1231
  WALLET_AUTH_FAILED: "WALLET_AUTH_FAILED",
1197
1232
  WALLET_RESOLVER_TIMEOUT: "WALLET_RESOLVER_TIMEOUT",
1233
+ PASSKEY_FAILED: "PASSKEY_FAILED",
1198
1234
  UNEXPECTED_ERROR: "UNEXPECTED_ERROR"
1199
1235
  };
1200
1236
  var PollarFlowError = class extends Error {
@@ -1240,7 +1276,7 @@ var FreighterAdapter = class {
1240
1276
  if (!userInfo?.publicKey) {
1241
1277
  throw new Error("Failed to get user information from Freighter");
1242
1278
  }
1243
- return { address: userInfo.publicKey, publicKey: userInfo.publicKey };
1279
+ return { address: userInfo.publicKey };
1244
1280
  }
1245
1281
  async disconnect() {
1246
1282
  }
@@ -1278,6 +1314,19 @@ var FreighterAdapter = class {
1278
1314
  };
1279
1315
 
1280
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
+ }
1281
1330
  function openAlbedoPopup(url) {
1282
1331
  const popup = window.open(url, "albedo", "width=420,height=720,resizable=yes,scrollbars=yes");
1283
1332
  if (!popup) {
@@ -1316,7 +1365,13 @@ function waitForAlbedoResult() {
1316
1365
  });
1317
1366
  }
1318
1367
  var AlbedoAdapter = class {
1319
- 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;
1320
1375
  this.type = "albedo" /* ALBEDO */;
1321
1376
  }
1322
1377
  async isAvailable() {
@@ -1326,7 +1381,7 @@ var AlbedoAdapter = class {
1326
1381
  const url = new URL("https://albedo.link");
1327
1382
  url.searchParams.set("intent", "public-key");
1328
1383
  url.searchParams.set("app_name", "Pollar");
1329
- url.searchParams.set("network", "testnet");
1384
+ url.searchParams.set("network", this.network);
1330
1385
  url.searchParams.set("callback", `${window.location.origin}/albedo-callback`);
1331
1386
  url.searchParams.set("origin", window.location.origin);
1332
1387
  openAlbedoPopup(url.toString());
@@ -1334,7 +1389,7 @@ var AlbedoAdapter = class {
1334
1389
  if (!result.pubkey) {
1335
1390
  throw new Error("Albedo connection rejected");
1336
1391
  }
1337
- return { address: result.pubkey, publicKey: result.pubkey };
1392
+ return { address: result.pubkey };
1338
1393
  }
1339
1394
  async disconnect() {
1340
1395
  }
@@ -1344,12 +1399,12 @@ var AlbedoAdapter = class {
1344
1399
  async getNetwork() {
1345
1400
  throw new Error("Albedo does not expose network");
1346
1401
  }
1347
- async signTransaction(xdr, _options) {
1402
+ async signTransaction(xdr, options) {
1348
1403
  const url = new URL("https://albedo.link");
1349
1404
  url.searchParams.set("intent", "tx");
1350
1405
  url.searchParams.set("xdr", xdr);
1351
1406
  url.searchParams.set("app_name", "Pollar");
1352
- url.searchParams.set("network", "testnet");
1407
+ url.searchParams.set("network", albedoNetwork(options, this.network));
1353
1408
  url.searchParams.set("callback", window.location.href);
1354
1409
  url.searchParams.set("origin", window.location.origin);
1355
1410
  window.location.href = url.toString();
@@ -1362,7 +1417,7 @@ var AlbedoAdapter = class {
1362
1417
  url.searchParams.set("intent", "sign-auth-entry");
1363
1418
  url.searchParams.set("xdr", entryXdr);
1364
1419
  url.searchParams.set("app_name", "Pollar");
1365
- url.searchParams.set("network", "testnet");
1420
+ url.searchParams.set("network", this.network);
1366
1421
  url.searchParams.set("callback", window.location.href);
1367
1422
  url.searchParams.set("origin", window.location.origin);
1368
1423
  window.location.href = url.toString();
@@ -1449,8 +1504,12 @@ function isValidSession(value) {
1449
1504
  return false;
1450
1505
  }
1451
1506
  const w = wallet;
1452
- if (w["publicKey"] !== null && !isBoundedString(w["publicKey"], MAX_WALLET_PUBLIC_KEY)) {
1453
- 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");
1454
1513
  return false;
1455
1514
  }
1456
1515
  if (w["existsOnStellar"] !== void 0 && typeof w["existsOnStellar"] !== "boolean") {
@@ -1461,6 +1520,10 @@ function isValidSession(value) {
1461
1520
  console.warn("[PollarClient:session] Invalid session \u2014 wallet.createdAt must be a finite number if present");
1462
1521
  return false;
1463
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
+ }
1464
1527
  return true;
1465
1528
  }
1466
1529
  async function readStorage(storage, apiKeyHash) {
@@ -1468,6 +1531,12 @@ async function readStorage(storage, apiKeyHash) {
1468
1531
  if (!raw) return null;
1469
1532
  try {
1470
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
+ }
1471
1540
  if (!isValidSession(session)) {
1472
1541
  await storage.remove(sessionStorageKey(apiKeyHash));
1473
1542
  console.warn("[PollarClient:session] Stored session is invalid \u2014 clearing storage");
@@ -1558,7 +1627,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1558
1627
  }));
1559
1628
  } catch (e) {
1560
1629
  if (e instanceof Error && e.name === "AbortError") throw e;
1561
- console.warn(e);
1630
+ console.warn("[PollarClient:stream] session-status request failed; will retry", e);
1562
1631
  }
1563
1632
  if (error || !data) {
1564
1633
  await sleep(backoff);
@@ -1598,7 +1667,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
1598
1667
  } catch (e) {
1599
1668
  if (e instanceof Error && e.name === "AbortError") throw e;
1600
1669
  if (e instanceof SessionStatusError) throw e;
1601
- console.warn(e);
1670
+ console.warn("[PollarClient:stream] session-status stream read failed; will retry", e);
1602
1671
  } finally {
1603
1672
  reader.releaseLock();
1604
1673
  }
@@ -1626,7 +1695,7 @@ async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500,
1626
1695
  envelope = await response.json().catch(() => null);
1627
1696
  } catch (e) {
1628
1697
  if (e instanceof Error && e.name === "AbortError") throw e;
1629
- console.warn(e);
1698
+ console.warn("[PollarClient:stream] session-status poll failed; will retry", e);
1630
1699
  }
1631
1700
  if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
1632
1701
  throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
@@ -1830,6 +1899,55 @@ async function loginOAuth(provider, deps) {
1830
1899
  await authenticate(clientSessionId, deps);
1831
1900
  }
1832
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
+
1833
1951
  // src/client/auth/walletFlow.ts
1834
1952
  function withSignal(promise, signal) {
1835
1953
  return Promise.race([
@@ -1856,12 +1974,12 @@ async function loginWallet(type, deps) {
1856
1974
  setAuthState({ step: "wallet_not_installed", walletType: type });
1857
1975
  return;
1858
1976
  }
1859
- const { publicKey } = await withSignal(adapter.connect(), signal);
1860
- connectedWallet = publicKey;
1977
+ const { address } = await withSignal(adapter.connect(), signal);
1978
+ connectedWallet = address;
1861
1979
  deps.storeWalletAdapter(adapter, type);
1862
1980
  setAuthState({ step: "authenticating_wallet" });
1863
1981
  const { data: walletData, error: walletError } = await api.POST("/auth/wallet", {
1864
- body: { clientSessionId, walletAddress: publicKey },
1982
+ body: { clientSessionId, walletAddress: address },
1865
1983
  signal
1866
1984
  });
1867
1985
  if (walletError || !walletData?.success) {
@@ -1926,8 +2044,12 @@ var PollarClient = class {
1926
2044
  this._transactionStateListeners = /* @__PURE__ */ new Set();
1927
2045
  this._txHistoryState = { step: "idle" };
1928
2046
  this._txHistoryStateListeners = /* @__PURE__ */ new Set();
2047
+ this._sessionsState = { step: "idle" };
2048
+ this._sessionsStateListeners = /* @__PURE__ */ new Set();
1929
2049
  this._walletBalanceState = { step: "idle" };
1930
2050
  this._walletBalanceStateListeners = /* @__PURE__ */ new Set();
2051
+ this._enabledAssetsState = { step: "idle" };
2052
+ this._enabledAssetsStateListeners = /* @__PURE__ */ new Set();
1931
2053
  this._authState = { step: "idle" };
1932
2054
  this._authStateListeners = /* @__PURE__ */ new Set();
1933
2055
  this._networkState = { step: "idle" };
@@ -1943,6 +2065,8 @@ var PollarClient = class {
1943
2065
  this._storageDegradeListeners = /* @__PURE__ */ new Set();
1944
2066
  this._walletAdapter = null;
1945
2067
  this._loginController = null;
2068
+ /** Aborts an in-flight `/auth/session/resume` on destroy() or re-trigger. */
2069
+ this._resumeController = null;
1946
2070
  this.apiKey = config.apiKey;
1947
2071
  this.id = randomUUID();
1948
2072
  this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
@@ -1955,6 +2079,8 @@ var PollarClient = class {
1955
2079
  this._keyManager = config.keyManager ?? defaultKeyManager(this._storage, config.apiKey);
1956
2080
  this._walletAdapterResolver = config.walletAdapter ?? null;
1957
2081
  this._walletResolverTimeoutMs = config.walletResolverTimeoutMs ?? 5e3;
2082
+ this._passkey = config.passkey ?? null;
2083
+ this._passkeySign = config.passkeySign ?? null;
1958
2084
  this._deviceLabel = config.deviceLabel;
1959
2085
  this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
1960
2086
  this._maxIdleMs = config.maxIdleMs;
@@ -1968,7 +2094,9 @@ var PollarClient = class {
1968
2094
  this._initialized = Promise.resolve();
1969
2095
  return;
1970
2096
  }
1971
- 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
+ );
1972
2100
  this._initialized = this._initialize();
1973
2101
  }
1974
2102
  /**
@@ -2006,7 +2134,11 @@ var PollarClient = class {
2006
2134
  }
2007
2135
  await this._restoreSession();
2008
2136
  this._visibilityUnsubscribe = this._visibilityProvider.onChange((visible) => {
2009
- 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
+ }
2010
2142
  });
2011
2143
  }
2012
2144
  /** Detach the cross-tab storage listener and abort any in-flight login. */
@@ -2017,6 +2149,8 @@ var PollarClient = class {
2017
2149
  }
2018
2150
  this._loginController?.abort();
2019
2151
  this._loginController = null;
2152
+ this._resumeController?.abort();
2153
+ this._resumeController = null;
2020
2154
  this._clearRefreshTimer();
2021
2155
  if (this._visibilityUnsubscribe) {
2022
2156
  this._visibilityUnsubscribe();
@@ -2031,7 +2165,9 @@ var PollarClient = class {
2031
2165
  request.headers.set("x-pollar-api-key", self.apiKey);
2032
2166
  self._lastRequestAt = Date.now();
2033
2167
  await self._initialized;
2034
- if (request.body !== null) {
2168
+ const cacheMethod = request.method.toUpperCase();
2169
+ const cacheBodyAllowed = cacheMethod !== "GET" && cacheMethod !== "HEAD";
2170
+ if (cacheBodyAllowed && request.body != null) {
2035
2171
  try {
2036
2172
  self._requestBodyCache.set(request, await request.clone().arrayBuffer());
2037
2173
  } catch (err) {
@@ -2118,7 +2254,9 @@ var PollarClient = class {
2118
2254
  }
2119
2255
  }
2120
2256
  }
2121
- 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;
2122
2260
  const retried = new Request(originalRequest.url, {
2123
2261
  method: originalRequest.method,
2124
2262
  headers,
@@ -2162,19 +2300,26 @@ var PollarClient = class {
2162
2300
  throw err;
2163
2301
  }
2164
2302
  if (error || !data) {
2165
- console.warn("[PollarClient] /auth/refresh returned error", { error });
2303
+ console.error("[PollarClient] /auth/refresh returned error", { error });
2166
2304
  await this._clearSession();
2167
2305
  throw new Error("Refresh failed");
2168
2306
  }
2169
2307
  const successData = data;
2170
2308
  if (!successData.success || !successData.content?.token) {
2171
- 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
+ });
2172
2313
  await this._clearSession();
2173
2314
  throw new Error("Refresh response malformed");
2174
2315
  }
2175
2316
  const newToken = successData.content.token;
2176
2317
  if (typeof newToken.accessToken !== "string" || typeof newToken.refreshToken !== "string" || typeof newToken.expiresAt !== "number") {
2177
- 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
+ });
2178
2323
  await this._clearSession();
2179
2324
  throw new Error("Refresh response token shape invalid");
2180
2325
  }
@@ -2368,6 +2513,19 @@ var PollarClient = class {
2368
2513
  const controller = this._newController();
2369
2514
  loginWallet(type, this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
2370
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
+ }
2371
2529
  // ─── Cancel ───────────────────────────────────────────────────────────────
2372
2530
  cancelLogin() {
2373
2531
  this._loginController?.abort();
@@ -2430,6 +2588,29 @@ var PollarClient = class {
2430
2588
  }
2431
2589
  return data.content.sessions;
2432
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
+ }
2433
2614
  /**
2434
2615
  * Revoke a specific refresh-token family (a single device session). Use
2435
2616
  * `listSessions` to enumerate the familyIds. Revoking the current session
@@ -2506,16 +2687,19 @@ var PollarClient = class {
2506
2687
  cb(this._walletBalanceState);
2507
2688
  return () => this._walletBalanceStateListeners.delete(cb);
2508
2689
  }
2509
- async refreshBalance(publicKey) {
2510
- const pk = publicKey ?? this._session?.wallet?.publicKey;
2511
- 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) {
2512
2697
  this._setWalletBalanceState({ step: "error", message: "No wallet connected" });
2513
2698
  return;
2514
2699
  }
2515
2700
  this._setWalletBalanceState({ step: "loading" });
2516
2701
  try {
2517
- const network = this.getNetwork();
2518
- const { data, error } = await this._api.GET("/wallet/balance", { params: { query: { publicKey: pk, network } } });
2702
+ const { data, error } = await this._api.GET("/wallet/balance");
2519
2703
  if (!error && data?.success && data.content) {
2520
2704
  this._setWalletBalanceState({ step: "loaded", data: data.content });
2521
2705
  } else {
@@ -2525,6 +2709,53 @@ var PollarClient = class {
2525
2709
  this._setWalletBalanceState({ step: "error", message: "Failed to load balance" });
2526
2710
  }
2527
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
+ }
2528
2759
  // ─── Transactions ─────────────────────────────────────────────────────────
2529
2760
  /**
2530
2761
  * Builds an unsigned XDR. Drives `_setTransactionState` for modal-style UIs
@@ -2532,14 +2763,14 @@ var PollarClient = class {
2532
2763
  * inspect the result without subscribing to state changes.
2533
2764
  */
2534
2765
  async buildTx(operation, params, options) {
2535
- if (!this._session?.wallet?.publicKey) {
2766
+ if (!this._session?.wallet?.address) {
2536
2767
  const details = "No wallet connected";
2537
2768
  this._setTransactionState({ step: "error", phase: "building", details });
2538
2769
  return { status: "error", details };
2539
2770
  }
2540
2771
  const body = {
2541
2772
  network: this.getNetwork(),
2542
- publicKey: this._session.wallet.publicKey,
2773
+ address: this._session.wallet.address,
2543
2774
  operation,
2544
2775
  params,
2545
2776
  options: options ?? {}
@@ -2580,7 +2811,7 @@ var PollarClient = class {
2580
2811
  const buildData = this._currentBuildData();
2581
2812
  this._setTransactionState({ step: "signing", ...buildData && { buildData } });
2582
2813
  if (this._walletAdapter) {
2583
- const accountToSign = this._session?.wallet?.publicKey;
2814
+ const accountToSign = this._session?.wallet?.address;
2584
2815
  const signOpts = accountToSign ? { networkPassphrase: this._networkPassphrase(), accountToSign } : { networkPassphrase: this._networkPassphrase() };
2585
2816
  try {
2586
2817
  const { signedTxXdr } = await this._walletAdapter.signTransaction(unsignedXdr, signOpts);
@@ -2601,10 +2832,10 @@ var PollarClient = class {
2601
2832
  return { status: "error", ...details && { details } };
2602
2833
  }
2603
2834
  }
2604
- const publicKey = this._session?.wallet?.publicKey ?? "";
2835
+ const address = this._session?.wallet?.address ?? "";
2605
2836
  try {
2606
2837
  const { data, error } = await this._api.POST("/tx/sign", {
2607
- body: { network: this.getNetwork(), publicKey, unsignedXdr }
2838
+ body: { network: this.getNetwork(), address, unsignedXdr }
2608
2839
  });
2609
2840
  if (!error && data?.success && data.content?.signedXdr) {
2610
2841
  const { signedXdr, idempotencyKey } = data.content;
@@ -2657,12 +2888,12 @@ var PollarClient = class {
2657
2888
  const buildData = this._currentBuildData();
2658
2889
  const outcomeExtra = buildData ? { buildData } : {};
2659
2890
  this._setTransactionState({ step: "submitting", signedXdr, ...buildData && { buildData } });
2660
- const publicKey = this._session?.wallet?.publicKey ?? "";
2891
+ const address = this._session?.wallet?.address ?? "";
2661
2892
  try {
2662
2893
  const { data, error } = await this._api.POST("/tx/submit", {
2663
2894
  body: {
2664
2895
  network: this.getNetwork(),
2665
- publicKey,
2896
+ address,
2666
2897
  signedXdr,
2667
2898
  ...opts?.submissionToken && { idempotencyKey: opts.submissionToken }
2668
2899
  }
@@ -2722,6 +2953,19 @@ var PollarClient = class {
2722
2953
  * `success` (ledger-confirmed), or `error[phase: 'signing-submitting']`.
2723
2954
  */
2724
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
+ }
2725
2969
  if (this._walletAdapter) {
2726
2970
  const signed = await this.signTx(unsignedXdr);
2727
2971
  if (signed.status === "error") {
@@ -2739,7 +2983,7 @@ var PollarClient = class {
2739
2983
  this._setTransactionState({ step: "signing-submitting", ...buildData && { buildData } });
2740
2984
  const body = {
2741
2985
  network: this.getNetwork(),
2742
- publicKey: this._session?.wallet?.publicKey ?? "",
2986
+ address: this._session?.wallet?.address ?? "",
2743
2987
  unsignedXdr
2744
2988
  };
2745
2989
  try {
@@ -2808,14 +3052,20 @@ var PollarClient = class {
2808
3052
  * `signTx`, and `submitTx` separately instead.
2809
3053
  */
2810
3054
  async buildAndSignAndSubmitTx(operation, params, options) {
3055
+ if (this._session?.wallet?.type === "smart") {
3056
+ return this._runSmartTx(operation, params, options);
3057
+ }
2811
3058
  if (this._walletAdapter) {
2812
3059
  const built = await this.buildTx(operation, params, options);
2813
3060
  if (built.status === "error") {
2814
3061
  return { status: "error", ...built.details && { details: built.details } };
2815
3062
  }
3063
+ if (!built.buildData.unsignedXdr) {
3064
+ return { status: "error", details: "build returned no unsigned transaction" };
3065
+ }
2816
3066
  return this.signAndSubmitTx(built.buildData.unsignedXdr);
2817
3067
  }
2818
- if (!this._session?.wallet?.publicKey) {
3068
+ if (!this._session?.wallet?.address) {
2819
3069
  this._setTransactionState({ step: "error", phase: "building-signing-submitting", details: "No wallet connected" });
2820
3070
  return { status: "error", details: "No wallet connected" };
2821
3071
  }
@@ -2824,7 +3074,7 @@ var PollarClient = class {
2824
3074
  const { data, error } = await this._api.POST("/tx/build-sign-submit", {
2825
3075
  body: {
2826
3076
  network: this.getNetwork(),
2827
- publicKey: this._session.wallet.publicKey,
3077
+ address: this._session.wallet.address,
2828
3078
  operation,
2829
3079
  params,
2830
3080
  options: options ?? {}
@@ -2868,6 +3118,113 @@ var PollarClient = class {
2868
3118
  async runTx(operation, params, options) {
2869
3119
  return this.buildAndSignAndSubmitTx(operation, params, options);
2870
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
+ }
2871
3228
  // ─── App config ───────────────────────────────────────────────────────────
2872
3229
  async getAppConfig() {
2873
3230
  try {
@@ -2921,10 +3278,18 @@ var PollarClient = class {
2921
3278
  this._txHistoryState = next;
2922
3279
  for (const cb of this._txHistoryStateListeners) cb(next);
2923
3280
  }
3281
+ _setSessionsState(next) {
3282
+ this._sessionsState = next;
3283
+ for (const cb of this._sessionsStateListeners) cb(next);
3284
+ }
2924
3285
  _setWalletBalanceState(next) {
2925
3286
  this._walletBalanceState = next;
2926
3287
  for (const cb of this._walletBalanceStateListeners) cb(next);
2927
3288
  }
3289
+ _setEnabledAssetsState(next) {
3290
+ this._enabledAssetsState = next;
3291
+ for (const cb of this._enabledAssetsStateListeners) cb(next);
3292
+ }
2928
3293
  // ─── Private ──────────────────────────────────────────────────────────────
2929
3294
  _newController() {
2930
3295
  this._loginController?.abort();
@@ -2949,6 +3314,7 @@ var PollarClient = class {
2949
3314
  this._walletAdapter = adapter;
2950
3315
  await writeWalletType(this._storage, this.apiKeyHash, id);
2951
3316
  },
3317
+ ...this._passkey ? { passkey: this._passkey } : {},
2952
3318
  ...this._deviceLabel ? { deviceLabel: this._deviceLabel } : {}
2953
3319
  };
2954
3320
  }
@@ -2978,7 +3344,7 @@ var PollarClient = class {
2978
3344
  }
2979
3345
  }
2980
3346
  if (id === "freighter" /* FREIGHTER */) return new FreighterAdapter();
2981
- if (id === "albedo" /* ALBEDO */) return new AlbedoAdapter();
3347
+ if (id === "albedo" /* ALBEDO */) return new AlbedoAdapter(this.getNetwork() === "mainnet" ? "public" : "testnet");
2982
3348
  throw new Error(
2983
3349
  `[PollarClient] No wallet adapter configured for "${id}". Pass a walletAdapter resolver in PollarClientConfig.`
2984
3350
  );
@@ -3019,21 +3385,66 @@ var PollarClient = class {
3019
3385
  }
3020
3386
  }
3021
3387
  console.info("[PollarClient] Session restored from storage");
3022
- this._setAuthState({ step: "authenticated", session: this._session });
3388
+ this._setAuthState({ step: "authenticated", session: this._session, verified: false });
3023
3389
  this._scheduleNextRefresh();
3390
+ void this._resume();
3024
3391
  } else {
3025
3392
  console.info("[PollarClient] No session in storage");
3026
3393
  }
3027
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
+ }
3028
3428
  async _storeSession(session) {
3029
3429
  console.info("[PollarClient] Session stored");
3430
+ const w = session.wallet;
3030
3431
  const persisted = {
3031
3432
  clientSessionId: session.clientSessionId,
3032
3433
  userId: session.userId ?? null,
3033
3434
  status: session.status,
3034
3435
  token: session.token,
3035
3436
  user: session.user,
3036
- 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
+ }
3037
3448
  };
3038
3449
  this._session = persisted;
3039
3450
  if (session.data) {
@@ -3046,7 +3457,7 @@ var PollarClient = class {
3046
3457
  };
3047
3458
  }
3048
3459
  await writeStorage(this._storage, this.apiKeyHash, persisted);
3049
- this._setAuthState({ step: "authenticated", session: persisted });
3460
+ this._setAuthState({ step: "authenticated", session: persisted, verified: true });
3050
3461
  this._scheduleNextRefresh();
3051
3462
  }
3052
3463
  async _clearSession() {
@@ -3132,6 +3543,7 @@ _setDefaultKeyManagerFactory((_storage, apiKey) => new WebCryptoKeyManager(apiKe
3132
3543
  exports.AUTH_ERROR_CODES = AUTH_ERROR_CODES;
3133
3544
  exports.AlbedoAdapter = AlbedoAdapter;
3134
3545
  exports.FreighterAdapter = FreighterAdapter;
3546
+ exports.POLLAR_CORE_VERSION = POLLAR_CORE_VERSION;
3135
3547
  exports.PollarClient = PollarClient;
3136
3548
  exports.StellarClient = StellarClient;
3137
3549
  exports.WalletType = WalletType;