@pollar/core 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -5
- package/dist/adapters/expo-secure-store.d.mts +11 -1
- package/dist/adapters/expo-secure-store.d.ts +11 -1
- package/dist/adapters/expo-secure-store.js +11 -3
- package/dist/adapters/expo-secure-store.js.map +1 -1
- package/dist/adapters/expo-secure-store.mjs +11 -4
- package/dist/adapters/expo-secure-store.mjs.map +1 -1
- package/dist/adapters/react-native-appstate.d.mts +10 -0
- package/dist/adapters/react-native-appstate.d.ts +10 -0
- package/dist/adapters/react-native-appstate.js +38 -0
- package/dist/adapters/react-native-appstate.js.map +1 -0
- package/dist/adapters/react-native-appstate.mjs +36 -0
- package/dist/adapters/react-native-appstate.mjs.map +1 -0
- package/dist/index.d.mts +194 -39
- package/dist/index.d.ts +194 -39
- package/dist/index.js +174 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +174 -60
- package/dist/index.mjs.map +1 -1
- package/dist/index.rn.d.mts +2 -1
- package/dist/index.rn.d.ts +2 -1
- package/dist/index.rn.js +177 -64
- package/dist/index.rn.js.map +1 -1
- package/dist/index.rn.mjs +174 -61
- package/dist/index.rn.mjs.map +1 -1
- package/dist/types-84G_htcn.d.mts +38 -0
- package/dist/types-84G_htcn.d.ts +38 -0
- package/package.json +12 -1
package/dist/index.rn.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { KeyManager, PublicEcJwk } from './index.mjs';
|
|
2
|
-
export { AUTH_ERROR_CODES, AdapterFn, AlbedoAdapter, AuthErrorCode, AuthState, BuildOutcome, BuildProofArgs, ConnectWalletResponse, DistributionClaimBody, DistributionClaimContent, DistributionRule, DistributionRulesState, FreighterAdapter, KycFlow, KycLevel, KycProvider, KycStartBody, KycStartResponse, KycStatus, LocalStorageAdapterOptions, NetworkState, PaymentInstructions, PollarAdapter, PollarAdapters, PollarApiClient, PollarApplicationConfigContent, PollarApplicationConfigResponse, PollarClient, PollarClientConfig, PollarFlowError, PollarLoginOptions, PollarPersistedSession, PollarUserProfile, RampDirection, RampQuote, RampTxStatus, RampsOfframpBody, RampsOfframpResponse, RampsOnrampBody, RampsOnrampResponse, RampsQuoteQuery, RampsQuoteResponse, RampsTransactionResponse, RulePeriod, SessionInfo, SignAuthEntryOptions, SignAuthEntryResponse, SignOutcome, SignTransactionOptions, SignTransactionResponse, StellarBalance, StellarClient, StellarClientConfig, StellarNetwork, SubmitOutcome, TransactionState, TxBuildBody, TxBuildContent, TxBuildResponse, TxBuildSignSubmitBody, TxBuildSignSubmitContent, TxBuildSignSubmitResponse, TxErrorPhase, TxHistoryContent, TxHistoryParams, TxHistoryRecord, TxHistoryState, TxSignAndSendBody, TxSignBody, TxSignContent, TxSignResponse, TxSignSendResponse, TxSubmitSignedBody, WalletAdapter, WalletAdapterResolver, WalletBalanceContent, WalletBalanceRecord, WalletBalanceState, WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, pollarPaths, resolveKyc, startKyc } from './index.mjs';
|
|
2
|
+
export { AUTH_ERROR_CODES, AdapterFn, AlbedoAdapter, AuthErrorCode, AuthOpenContext, AuthState, AuthUrlOpener, BuildOutcome, BuildProofArgs, ConnectWalletResponse, DistributionClaimBody, DistributionClaimContent, DistributionRule, DistributionRulesState, FreighterAdapter, KycFlow, KycLevel, KycProvider, KycStartBody, KycStartResponse, KycStatus, LocalStorageAdapterOptions, NetworkState, PaymentInstructions, PollarAdapter, PollarAdapters, PollarApiClient, PollarApplicationConfigContent, PollarApplicationConfigResponse, PollarClient, PollarClientConfig, PollarFlowError, PollarLoginOptions, PollarPersistedSession, PollarUserProfile, RampDirection, RampQuote, RampTxStatus, RampsOfframpBody, RampsOfframpResponse, RampsOnrampBody, RampsOnrampResponse, RampsQuoteQuery, RampsQuoteResponse, RampsTransactionResponse, RulePeriod, SessionInfo, SignAuthEntryOptions, SignAuthEntryResponse, SignOutcome, SignTransactionOptions, SignTransactionResponse, StellarBalance, StellarClient, StellarClientConfig, StellarNetwork, SubmitOutcome, TransactionState, TxBuildBody, TxBuildContent, TxBuildResponse, TxBuildSignSubmitBody, TxBuildSignSubmitContent, TxBuildSignSubmitResponse, TxErrorPhase, TxHistoryContent, TxHistoryParams, TxHistoryRecord, TxHistoryState, TxSignAndSendBody, TxSignBody, TxSignContent, TxSignResponse, TxSignSendResponse, TxSubmitSignedBody, WalletAdapter, WalletAdapterResolver, WalletBalanceContent, WalletBalanceRecord, WalletBalanceState, WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, pollarPaths, resolveKyc, startKyc } from './index.mjs';
|
|
3
3
|
import { S as Storage } from './types-DqgJIJBl.mjs';
|
|
4
4
|
export { O as OnStorageDegrade, a as StorageDegradeReason } from './types-DqgJIJBl.mjs';
|
|
5
|
+
import './types-84G_htcn.mjs';
|
|
5
6
|
import 'openapi-fetch';
|
|
6
7
|
|
|
7
8
|
declare class NobleKeyManager implements KeyManager {
|
package/dist/index.rn.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { KeyManager, PublicEcJwk } from './index.js';
|
|
2
|
-
export { AUTH_ERROR_CODES, AdapterFn, AlbedoAdapter, AuthErrorCode, AuthState, BuildOutcome, BuildProofArgs, ConnectWalletResponse, DistributionClaimBody, DistributionClaimContent, DistributionRule, DistributionRulesState, FreighterAdapter, KycFlow, KycLevel, KycProvider, KycStartBody, KycStartResponse, KycStatus, LocalStorageAdapterOptions, NetworkState, PaymentInstructions, PollarAdapter, PollarAdapters, PollarApiClient, PollarApplicationConfigContent, PollarApplicationConfigResponse, PollarClient, PollarClientConfig, PollarFlowError, PollarLoginOptions, PollarPersistedSession, PollarUserProfile, RampDirection, RampQuote, RampTxStatus, RampsOfframpBody, RampsOfframpResponse, RampsOnrampBody, RampsOnrampResponse, RampsQuoteQuery, RampsQuoteResponse, RampsTransactionResponse, RulePeriod, SessionInfo, SignAuthEntryOptions, SignAuthEntryResponse, SignOutcome, SignTransactionOptions, SignTransactionResponse, StellarBalance, StellarClient, StellarClientConfig, StellarNetwork, SubmitOutcome, TransactionState, TxBuildBody, TxBuildContent, TxBuildResponse, TxBuildSignSubmitBody, TxBuildSignSubmitContent, TxBuildSignSubmitResponse, TxErrorPhase, TxHistoryContent, TxHistoryParams, TxHistoryRecord, TxHistoryState, TxSignAndSendBody, TxSignBody, TxSignContent, TxSignResponse, TxSignSendResponse, TxSubmitSignedBody, WalletAdapter, WalletAdapterResolver, WalletBalanceContent, WalletBalanceRecord, WalletBalanceState, WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, pollarPaths, resolveKyc, startKyc } from './index.js';
|
|
2
|
+
export { AUTH_ERROR_CODES, AdapterFn, AlbedoAdapter, AuthErrorCode, AuthOpenContext, AuthState, AuthUrlOpener, BuildOutcome, BuildProofArgs, ConnectWalletResponse, DistributionClaimBody, DistributionClaimContent, DistributionRule, DistributionRulesState, FreighterAdapter, KycFlow, KycLevel, KycProvider, KycStartBody, KycStartResponse, KycStatus, LocalStorageAdapterOptions, NetworkState, PaymentInstructions, PollarAdapter, PollarAdapters, PollarApiClient, PollarApplicationConfigContent, PollarApplicationConfigResponse, PollarClient, PollarClientConfig, PollarFlowError, PollarLoginOptions, PollarPersistedSession, PollarUserProfile, RampDirection, RampQuote, RampTxStatus, RampsOfframpBody, RampsOfframpResponse, RampsOnrampBody, RampsOnrampResponse, RampsQuoteQuery, RampsQuoteResponse, RampsTransactionResponse, RulePeriod, SessionInfo, SignAuthEntryOptions, SignAuthEntryResponse, SignOutcome, SignTransactionOptions, SignTransactionResponse, StellarBalance, StellarClient, StellarClientConfig, StellarNetwork, SubmitOutcome, TransactionState, TxBuildBody, TxBuildContent, TxBuildResponse, TxBuildSignSubmitBody, TxBuildSignSubmitContent, TxBuildSignSubmitResponse, TxErrorPhase, TxHistoryContent, TxHistoryParams, TxHistoryRecord, TxHistoryState, TxSignAndSendBody, TxSignBody, TxSignContent, TxSignResponse, TxSignSendResponse, TxSubmitSignedBody, WalletAdapter, WalletAdapterResolver, WalletBalanceContent, WalletBalanceRecord, WalletBalanceState, WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, pollarPaths, resolveKyc, startKyc } from './index.js';
|
|
3
3
|
import { S as Storage } from './types-DqgJIJBl.js';
|
|
4
4
|
export { O as OnStorageDegrade, a as StorageDegradeReason } from './types-DqgJIJBl.js';
|
|
5
|
+
import './types-84G_htcn.js';
|
|
5
6
|
import 'openapi-fetch';
|
|
6
7
|
|
|
7
8
|
declare class NobleKeyManager implements KeyManager {
|
package/dist/index.rn.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var nist = require('@noble/curves/nist');
|
|
4
|
+
var sha2 = require('@noble/hashes/sha2');
|
|
4
5
|
|
|
5
6
|
var __create = Object.create;
|
|
6
7
|
var __defProp = Object.defineProperty;
|
|
@@ -186,11 +187,8 @@ function defaultKeyManager(storage, apiKey) {
|
|
|
186
187
|
}
|
|
187
188
|
return _factory(storage, apiKey);
|
|
188
189
|
}
|
|
189
|
-
|
|
190
|
-
// src/lib/sha256.ts
|
|
191
190
|
async function sha256(data) {
|
|
192
|
-
|
|
193
|
-
return new Uint8Array(buf);
|
|
191
|
+
return sha2.sha256(data);
|
|
194
192
|
}
|
|
195
193
|
|
|
196
194
|
// src/lib/api-key-hash.ts
|
|
@@ -325,14 +323,14 @@ var NobleKeyManager = class {
|
|
|
325
323
|
priv = null;
|
|
326
324
|
}
|
|
327
325
|
if (!priv) {
|
|
328
|
-
priv =
|
|
326
|
+
priv = nist.p256.utils.randomPrivateKey();
|
|
329
327
|
try {
|
|
330
328
|
await this.storage.set(this.storageKey, base64urlEncode(priv));
|
|
331
329
|
} catch {
|
|
332
330
|
}
|
|
333
331
|
}
|
|
334
332
|
this.privateKey = priv;
|
|
335
|
-
const pub =
|
|
333
|
+
const pub = nist.p256.getPublicKey(priv, false);
|
|
336
334
|
if (pub.length !== 65 || pub[0] !== 4) {
|
|
337
335
|
throw new Error("[PollarClient:keys] Unexpected public key format from @noble/curves");
|
|
338
336
|
}
|
|
@@ -374,7 +372,7 @@ var NobleKeyManager = class {
|
|
|
374
372
|
throw new Error("[PollarClient:keys] Keypair initialization failed; sign unavailable");
|
|
375
373
|
}
|
|
376
374
|
const digest = await sha256(payload);
|
|
377
|
-
const signature =
|
|
375
|
+
const signature = nist.p256.sign(digest, this.privateKey, { prehash: false });
|
|
378
376
|
return signature.toCompactRawBytes();
|
|
379
377
|
}
|
|
380
378
|
};
|
|
@@ -1108,6 +1106,26 @@ async function pollRampTransaction(api, txId, { intervalMs = 5e3, timeoutMs = 6e
|
|
|
1108
1106
|
throw new Error("Ramp transaction polling timed out");
|
|
1109
1107
|
}
|
|
1110
1108
|
|
|
1109
|
+
// src/lib/random-uuid.ts
|
|
1110
|
+
function randomUUID() {
|
|
1111
|
+
const c = globalThis.crypto;
|
|
1112
|
+
if (c && typeof c.randomUUID === "function") {
|
|
1113
|
+
return c.randomUUID();
|
|
1114
|
+
}
|
|
1115
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
1116
|
+
const bytes = new Uint8Array(16);
|
|
1117
|
+
c.getRandomValues(bytes);
|
|
1118
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
1119
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
1120
|
+
const hex = [];
|
|
1121
|
+
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
1122
|
+
return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
|
|
1123
|
+
}
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
"[PollarClient] No secure random source available (crypto.randomUUID / crypto.getRandomValues). DPoP requires a secure context (HTTPS) or, in React Native, the `react-native-get-random-values` polyfill."
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1111
1129
|
// src/dpop.ts
|
|
1112
1130
|
async function buildProof(args, keyManager) {
|
|
1113
1131
|
const jwk = await keyManager.getPublicJwk();
|
|
@@ -1117,7 +1135,7 @@ async function buildProof(args, keyManager) {
|
|
|
1117
1135
|
jwk
|
|
1118
1136
|
};
|
|
1119
1137
|
const payload = {
|
|
1120
|
-
jti:
|
|
1138
|
+
jti: randomUUID(),
|
|
1121
1139
|
htm: args.htm.toUpperCase(),
|
|
1122
1140
|
htu: normalizeHtu(args.htu),
|
|
1123
1141
|
iat: Math.floor(Date.now() / 1e3)
|
|
@@ -1151,24 +1169,6 @@ function normalizeHtu(rawUrl) {
|
|
|
1151
1169
|
const portPart = port ? `:${port}` : "";
|
|
1152
1170
|
return `${scheme}//${host}${portPart}${url.pathname}`;
|
|
1153
1171
|
}
|
|
1154
|
-
function generateJti() {
|
|
1155
|
-
const c = globalThis.crypto;
|
|
1156
|
-
if (c && typeof c.randomUUID === "function") {
|
|
1157
|
-
return c.randomUUID();
|
|
1158
|
-
}
|
|
1159
|
-
if (c && typeof c.getRandomValues === "function") {
|
|
1160
|
-
const bytes = new Uint8Array(16);
|
|
1161
|
-
c.getRandomValues(bytes);
|
|
1162
|
-
bytes[6] = bytes[6] & 15 | 64;
|
|
1163
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
1164
|
-
const hex = [];
|
|
1165
|
-
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
1166
|
-
return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
|
|
1167
|
-
}
|
|
1168
|
-
throw new Error(
|
|
1169
|
-
"[PollarClient:dpop] No secure random source available (crypto.randomUUID / crypto.getRandomValues). DPoP requires a secure context (HTTPS) or, in React Native, the `react-native-get-random-values` polyfill."
|
|
1170
|
-
);
|
|
1171
|
-
}
|
|
1172
1172
|
|
|
1173
1173
|
// src/storage/web.ts
|
|
1174
1174
|
var LOG_PREFIX = "[PollarClient:storage]";
|
|
@@ -1311,6 +1311,8 @@ function defaultVisibilityProvider() {
|
|
|
1311
1311
|
// src/types.ts
|
|
1312
1312
|
var AUTH_ERROR_CODES = {
|
|
1313
1313
|
SESSION_CREATE_FAILED: "SESSION_CREATE_FAILED",
|
|
1314
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
1315
|
+
SESSION_INVALID: "SESSION_INVALID",
|
|
1314
1316
|
EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED",
|
|
1315
1317
|
EMAIL_VERIFY_FAILED: "EMAIL_VERIFY_FAILED",
|
|
1316
1318
|
EMAIL_CODE_EXPIRED: "EMAIL_CODE_EXPIRED",
|
|
@@ -1624,7 +1626,32 @@ async function readWalletType(storage, apiKeyHash) {
|
|
|
1624
1626
|
return storage.get(walletTypeStorageKey(apiKeyHash));
|
|
1625
1627
|
}
|
|
1626
1628
|
|
|
1629
|
+
// src/lib/abort.ts
|
|
1630
|
+
function abortError() {
|
|
1631
|
+
if (typeof DOMException !== "undefined") {
|
|
1632
|
+
return new DOMException("Aborted", "AbortError");
|
|
1633
|
+
}
|
|
1634
|
+
const err = new Error("Aborted");
|
|
1635
|
+
err.name = "AbortError";
|
|
1636
|
+
return err;
|
|
1637
|
+
}
|
|
1638
|
+
function throwIfAborted(signal) {
|
|
1639
|
+
if (signal?.aborted) throw abortError();
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1627
1642
|
// src/client/stream.ts
|
|
1643
|
+
var SessionStatusError = class extends Error {
|
|
1644
|
+
constructor(code) {
|
|
1645
|
+
super(`[PollarClient] Session status terminal: ${code}`);
|
|
1646
|
+
this.code = code;
|
|
1647
|
+
this.name = "SessionStatusError";
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
function terminalStatusCode(parsed) {
|
|
1651
|
+
const err = parsed?.error;
|
|
1652
|
+
if (err === "INVALID_CLIENT_SESSION_ID" || err === "EXPIRED_CLIENT_ID") return err;
|
|
1653
|
+
return null;
|
|
1654
|
+
}
|
|
1628
1655
|
function abortableDelay(ms, signal) {
|
|
1629
1656
|
return new Promise((resolve, reject) => {
|
|
1630
1657
|
const t = setTimeout(resolve, ms);
|
|
@@ -1632,7 +1659,7 @@ function abortableDelay(ms, signal) {
|
|
|
1632
1659
|
"abort",
|
|
1633
1660
|
() => {
|
|
1634
1661
|
clearTimeout(t);
|
|
1635
|
-
reject(
|
|
1662
|
+
reject(abortError());
|
|
1636
1663
|
},
|
|
1637
1664
|
{ once: true }
|
|
1638
1665
|
);
|
|
@@ -1647,7 +1674,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1647
1674
|
else await new Promise((r) => setTimeout(r, ms));
|
|
1648
1675
|
};
|
|
1649
1676
|
while (true) {
|
|
1650
|
-
|
|
1677
|
+
throwIfAborted(signal);
|
|
1651
1678
|
let data, error;
|
|
1652
1679
|
try {
|
|
1653
1680
|
({ data, error } = await api.GET("/auth/session/status/{clientSessionId}", {
|
|
@@ -1670,7 +1697,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1670
1697
|
let sawAnyChunk = false;
|
|
1671
1698
|
try {
|
|
1672
1699
|
while (true) {
|
|
1673
|
-
|
|
1700
|
+
throwIfAborted(signal);
|
|
1674
1701
|
const { done, value } = await reader.read();
|
|
1675
1702
|
if (done) {
|
|
1676
1703
|
streamDone = true;
|
|
@@ -1681,17 +1708,22 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1681
1708
|
for (const message of chunk.split("\n\n").filter(Boolean)) {
|
|
1682
1709
|
const dataLine = message.split("\n").find((l) => l.startsWith("data:"));
|
|
1683
1710
|
if (!dataLine) continue;
|
|
1711
|
+
let parsed;
|
|
1684
1712
|
try {
|
|
1685
|
-
|
|
1686
|
-
if (check(parsed)) {
|
|
1687
|
-
return parsed;
|
|
1688
|
-
}
|
|
1713
|
+
parsed = JSON.parse(dataLine.slice("data:".length).trim());
|
|
1689
1714
|
} catch {
|
|
1715
|
+
continue;
|
|
1716
|
+
}
|
|
1717
|
+
const terminal = terminalStatusCode(parsed);
|
|
1718
|
+
if (terminal) throw new SessionStatusError(terminal);
|
|
1719
|
+
if (check(parsed)) {
|
|
1720
|
+
return parsed;
|
|
1690
1721
|
}
|
|
1691
1722
|
}
|
|
1692
1723
|
}
|
|
1693
1724
|
} catch (e) {
|
|
1694
1725
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1726
|
+
if (e instanceof SessionStatusError) throw e;
|
|
1695
1727
|
console.warn(e);
|
|
1696
1728
|
} finally {
|
|
1697
1729
|
reader.releaseLock();
|
|
@@ -1702,12 +1734,72 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1702
1734
|
if (delay) await sleep(delay);
|
|
1703
1735
|
}
|
|
1704
1736
|
}
|
|
1737
|
+
async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal) {
|
|
1738
|
+
const url = `${baseUrl}/auth/session/status/${encodeURIComponent(clientSessionId)}/poll`;
|
|
1739
|
+
let backoff = intervalMs;
|
|
1740
|
+
const sleep = async (ms) => {
|
|
1741
|
+
if (ms <= 0) return;
|
|
1742
|
+
if (signal) await abortableDelay(ms, signal);
|
|
1743
|
+
else await new Promise((r) => setTimeout(r, ms));
|
|
1744
|
+
};
|
|
1745
|
+
while (true) {
|
|
1746
|
+
throwIfAborted(signal);
|
|
1747
|
+
let envelope = null;
|
|
1748
|
+
let httpStatus = 0;
|
|
1749
|
+
try {
|
|
1750
|
+
const response = await fetch(url, { headers: { accept: "application/json" }, signal: signal ?? null });
|
|
1751
|
+
httpStatus = response.status;
|
|
1752
|
+
envelope = await response.json().catch(() => null);
|
|
1753
|
+
} catch (e) {
|
|
1754
|
+
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1755
|
+
console.warn(e);
|
|
1756
|
+
}
|
|
1757
|
+
if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
|
|
1758
|
+
throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
|
|
1759
|
+
}
|
|
1760
|
+
if (httpStatus === 410 || envelope?.code === "EXPIRED_CLIENT_ID") {
|
|
1761
|
+
throw new SessionStatusError("EXPIRED_CLIENT_ID");
|
|
1762
|
+
}
|
|
1763
|
+
if (envelope?.success && envelope.content && check(envelope.content)) {
|
|
1764
|
+
return envelope.content;
|
|
1765
|
+
}
|
|
1766
|
+
if (envelope) backoff = intervalMs;
|
|
1767
|
+
else backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
1768
|
+
await sleep(backoff);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function waitForSessionReady(args) {
|
|
1772
|
+
const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal } = args;
|
|
1773
|
+
return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal);
|
|
1774
|
+
}
|
|
1705
1775
|
|
|
1706
1776
|
// src/client/auth/authenticate.ts
|
|
1707
1777
|
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
1708
|
-
const { api, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1778
|
+
const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1709
1779
|
setAuthState({ step: "authenticating" });
|
|
1710
|
-
|
|
1780
|
+
try {
|
|
1781
|
+
await waitForSessionReady({
|
|
1782
|
+
api,
|
|
1783
|
+
baseUrl: basePath,
|
|
1784
|
+
clientSessionId,
|
|
1785
|
+
check: (data2) => data2?.status === "READY",
|
|
1786
|
+
useStreaming,
|
|
1787
|
+
signal
|
|
1788
|
+
});
|
|
1789
|
+
} catch (err) {
|
|
1790
|
+
if (err instanceof SessionStatusError) {
|
|
1791
|
+
const expired = err.code === "EXPIRED_CLIENT_ID";
|
|
1792
|
+
setAuthState({
|
|
1793
|
+
step: "error",
|
|
1794
|
+
previousStep: "authenticating",
|
|
1795
|
+
message: expired ? "Login session expired \u2014 please try again" : "Login session is no longer valid \u2014 please try again",
|
|
1796
|
+
errorCode: expired ? AUTH_ERROR_CODES.SESSION_EXPIRED : AUTH_ERROR_CODES.SESSION_INVALID
|
|
1797
|
+
});
|
|
1798
|
+
await clearSession();
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
throw err;
|
|
1802
|
+
}
|
|
1711
1803
|
const dpopJwk = await deps.getPublicJwk();
|
|
1712
1804
|
const { data } = await api.POST("/auth/login", {
|
|
1713
1805
|
body: {
|
|
@@ -1831,26 +1923,36 @@ function severOpener(popup) {
|
|
|
1831
1923
|
} catch {
|
|
1832
1924
|
}
|
|
1833
1925
|
}
|
|
1834
|
-
async
|
|
1835
|
-
const
|
|
1836
|
-
const popup = window.open("about:blank", "_blank");
|
|
1926
|
+
var defaultWebOAuthOpener = async ({ getUrl }) => {
|
|
1927
|
+
const popup = typeof window !== "undefined" ? window.open("about:blank", "_blank") : null;
|
|
1837
1928
|
severOpener(popup);
|
|
1838
|
-
const
|
|
1839
|
-
if (!
|
|
1929
|
+
const url = await getUrl();
|
|
1930
|
+
if (!url) {
|
|
1840
1931
|
popup?.close();
|
|
1841
1932
|
return;
|
|
1842
1933
|
}
|
|
1843
|
-
setAuthState({ step: "opening_oauth", provider });
|
|
1844
|
-
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1845
|
-
url.searchParams.set("api_key", apiKey);
|
|
1846
|
-
url.searchParams.set("client_session_id", clientSessionId);
|
|
1847
|
-
url.searchParams.set("redirect_uri", window.location.origin);
|
|
1848
1934
|
if (popup) {
|
|
1849
|
-
popup.location.href = url
|
|
1935
|
+
popup.location.href = url;
|
|
1850
1936
|
severOpener(popup);
|
|
1851
|
-
} else {
|
|
1852
|
-
window.open(url
|
|
1937
|
+
} else if (typeof window !== "undefined") {
|
|
1938
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1853
1939
|
}
|
|
1940
|
+
};
|
|
1941
|
+
async function loginOAuth(provider, deps) {
|
|
1942
|
+
const { setAuthState, basePath, apiKey, openAuthUrl, redirectUri, signal } = deps;
|
|
1943
|
+
let clientSessionId = null;
|
|
1944
|
+
const getUrl = async () => {
|
|
1945
|
+
clientSessionId = await createAuthSession(deps);
|
|
1946
|
+
if (!clientSessionId) return null;
|
|
1947
|
+
setAuthState({ step: "opening_oauth", provider });
|
|
1948
|
+
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1949
|
+
url.searchParams.set("api_key", apiKey);
|
|
1950
|
+
url.searchParams.set("client_session_id", clientSessionId);
|
|
1951
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
1952
|
+
return url.toString();
|
|
1953
|
+
};
|
|
1954
|
+
await openAuthUrl({ provider, getUrl, redirectUri, signal });
|
|
1955
|
+
if (!clientSessionId) return;
|
|
1854
1956
|
await authenticate(clientSessionId, deps);
|
|
1855
1957
|
}
|
|
1856
1958
|
|
|
@@ -1860,10 +1962,10 @@ function withSignal(promise, signal) {
|
|
|
1860
1962
|
promise,
|
|
1861
1963
|
new Promise((_, reject) => {
|
|
1862
1964
|
if (signal.aborted) {
|
|
1863
|
-
reject(
|
|
1965
|
+
reject(abortError());
|
|
1864
1966
|
return;
|
|
1865
1967
|
}
|
|
1866
|
-
signal.addEventListener("abort", () => reject(
|
|
1968
|
+
signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
1867
1969
|
})
|
|
1868
1970
|
]);
|
|
1869
1971
|
}
|
|
@@ -1911,6 +2013,8 @@ async function loginWallet(type, deps) {
|
|
|
1911
2013
|
|
|
1912
2014
|
// src/client/client.ts
|
|
1913
2015
|
var isBrowser = typeof window !== "undefined" && typeof localStorage !== "undefined";
|
|
2016
|
+
var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
2017
|
+
var isClientRuntime = isBrowser || isReactNative;
|
|
1914
2018
|
var REFRESH_SKEW_SECONDS = 60;
|
|
1915
2019
|
function warnServerSide(method) {
|
|
1916
2020
|
console.warn(
|
|
@@ -1966,7 +2070,7 @@ var PollarClient = class {
|
|
|
1966
2070
|
this._walletAdapter = null;
|
|
1967
2071
|
this._loginController = null;
|
|
1968
2072
|
this.apiKey = config.apiKey;
|
|
1969
|
-
this.id =
|
|
2073
|
+
this.id = randomUUID();
|
|
1970
2074
|
this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
|
|
1971
2075
|
this._storage = config.storage ?? defaultStorage({
|
|
1972
2076
|
onDegrade: (reason, error) => {
|
|
@@ -1980,10 +2084,12 @@ var PollarClient = class {
|
|
|
1980
2084
|
this._deviceLabel = config.deviceLabel;
|
|
1981
2085
|
this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
|
|
1982
2086
|
this._maxIdleMs = config.maxIdleMs;
|
|
2087
|
+
this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
|
|
2088
|
+
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location.origin : "");
|
|
1983
2089
|
this._api = createApiClient(this.basePath);
|
|
1984
2090
|
this._wireMiddlewares();
|
|
1985
2091
|
this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
|
|
1986
|
-
if (!
|
|
2092
|
+
if (!isClientRuntime) {
|
|
1987
2093
|
warnServerSide("constructor");
|
|
1988
2094
|
this._initialized = Promise.resolve();
|
|
1989
2095
|
return;
|
|
@@ -2009,7 +2115,7 @@ var PollarClient = class {
|
|
|
2009
2115
|
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
2010
2116
|
async _initialize() {
|
|
2011
2117
|
this._apiKeyHash = await hashApiKey(this.apiKey);
|
|
2012
|
-
if (
|
|
2118
|
+
if (isBrowser) {
|
|
2013
2119
|
const sessionKey = sessionStorageKey(this._apiKeyHash);
|
|
2014
2120
|
const handler = (e) => {
|
|
2015
2121
|
if (e.key === sessionKey) {
|
|
@@ -2031,7 +2137,7 @@ var PollarClient = class {
|
|
|
2031
2137
|
}
|
|
2032
2138
|
/** Detach the cross-tab storage listener and abort any in-flight login. */
|
|
2033
2139
|
destroy() {
|
|
2034
|
-
if (this._storageEventHandler &&
|
|
2140
|
+
if (this._storageEventHandler && isBrowser) {
|
|
2035
2141
|
window.removeEventListener("storage", this._storageEventHandler);
|
|
2036
2142
|
this._storageEventHandler = null;
|
|
2037
2143
|
}
|
|
@@ -2314,7 +2420,7 @@ var PollarClient = class {
|
|
|
2314
2420
|
}
|
|
2315
2421
|
// ─── Login (unified entry point) ─────────────────────────────────────────
|
|
2316
2422
|
login(options) {
|
|
2317
|
-
if (!
|
|
2423
|
+
if (!isClientRuntime) {
|
|
2318
2424
|
warnServerSide("login");
|
|
2319
2425
|
return;
|
|
2320
2426
|
}
|
|
@@ -2325,7 +2431,9 @@ var PollarClient = class {
|
|
|
2325
2431
|
loginOAuth(options.provider, {
|
|
2326
2432
|
...deps,
|
|
2327
2433
|
basePath: this.basePath,
|
|
2328
|
-
apiKey: this.apiKey
|
|
2434
|
+
apiKey: this.apiKey,
|
|
2435
|
+
openAuthUrl: this._openAuthUrl,
|
|
2436
|
+
redirectUri: this._oauthRedirectUri
|
|
2329
2437
|
}).catch((err) => this._handleFlowError(err));
|
|
2330
2438
|
} else if (options.provider === "email") {
|
|
2331
2439
|
const { email } = options;
|
|
@@ -2341,7 +2449,7 @@ var PollarClient = class {
|
|
|
2341
2449
|
}
|
|
2342
2450
|
// ─── Email OTP flow (3 steps) ─────────────────────────────────────────────
|
|
2343
2451
|
beginEmailLogin() {
|
|
2344
|
-
if (!
|
|
2452
|
+
if (!isClientRuntime) {
|
|
2345
2453
|
warnServerSide("beginEmailLogin");
|
|
2346
2454
|
return;
|
|
2347
2455
|
}
|
|
@@ -2349,7 +2457,7 @@ var PollarClient = class {
|
|
|
2349
2457
|
initEmailSession(this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
|
|
2350
2458
|
}
|
|
2351
2459
|
sendEmailCode(email) {
|
|
2352
|
-
if (!
|
|
2460
|
+
if (!isClientRuntime) {
|
|
2353
2461
|
warnServerSide("sendEmailCode");
|
|
2354
2462
|
return;
|
|
2355
2463
|
}
|
|
@@ -2361,7 +2469,7 @@ var PollarClient = class {
|
|
|
2361
2469
|
sendEmailCode(email, clientSessionId, this._flowDeps(signal)).catch((err) => this._handleFlowError(err));
|
|
2362
2470
|
}
|
|
2363
2471
|
verifyEmailCode(code) {
|
|
2364
|
-
if (!
|
|
2472
|
+
if (!isClientRuntime) {
|
|
2365
2473
|
warnServerSide("verifyEmailCode");
|
|
2366
2474
|
return;
|
|
2367
2475
|
}
|
|
@@ -2379,7 +2487,7 @@ var PollarClient = class {
|
|
|
2379
2487
|
}
|
|
2380
2488
|
// ─── Wallet flow (single call) ────────────────────────────────────────────
|
|
2381
2489
|
loginWallet(type) {
|
|
2382
|
-
if (!
|
|
2490
|
+
if (!isClientRuntime) {
|
|
2383
2491
|
warnServerSide("loginWallet");
|
|
2384
2492
|
return;
|
|
2385
2493
|
}
|
|
@@ -2405,7 +2513,7 @@ var PollarClient = class {
|
|
|
2405
2513
|
* across all devices.
|
|
2406
2514
|
*/
|
|
2407
2515
|
async logout(options = {}) {
|
|
2408
|
-
if (!
|
|
2516
|
+
if (!isClientRuntime) {
|
|
2409
2517
|
warnServerSide("logout");
|
|
2410
2518
|
return;
|
|
2411
2519
|
}
|
|
@@ -2435,7 +2543,7 @@ var PollarClient = class {
|
|
|
2435
2543
|
* `current` flag identifies which entry corresponds to this client.
|
|
2436
2544
|
*/
|
|
2437
2545
|
async listSessions() {
|
|
2438
|
-
if (!
|
|
2546
|
+
if (!isClientRuntime) {
|
|
2439
2547
|
warnServerSide("listSessions");
|
|
2440
2548
|
return [];
|
|
2441
2549
|
}
|
|
@@ -2454,7 +2562,7 @@ var PollarClient = class {
|
|
|
2454
2562
|
* does NOT clear local state — call `logout()` for that case.
|
|
2455
2563
|
*/
|
|
2456
2564
|
async revokeSession(familyId) {
|
|
2457
|
-
if (!
|
|
2565
|
+
if (!isClientRuntime) {
|
|
2458
2566
|
warnServerSide("revokeSession");
|
|
2459
2567
|
return;
|
|
2460
2568
|
}
|
|
@@ -2952,6 +3060,11 @@ var PollarClient = class {
|
|
|
2952
3060
|
_flowDeps(signal) {
|
|
2953
3061
|
return {
|
|
2954
3062
|
api: this._api,
|
|
3063
|
+
basePath: this.basePath,
|
|
3064
|
+
// SSE status streaming works on web; React Native's `fetch` has no
|
|
3065
|
+
// readable `response.body`, so those clients poll the non-streaming
|
|
3066
|
+
// status endpoint instead. `isBrowser` is false in RN and SSR alike.
|
|
3067
|
+
useStreaming: isBrowser,
|
|
2955
3068
|
signal,
|
|
2956
3069
|
setAuthState: this._setAuthState.bind(this),
|
|
2957
3070
|
storeSession: this._storeSession.bind(this),
|