@pollar/core 0.8.0 → 0.8.1
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 +118 -6
- 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 +171 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +171 -56
- 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 +171 -56
- package/dist/index.rn.js.map +1 -1
- package/dist/index.rn.mjs +171 -56
- 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 +11 -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
|
@@ -1108,6 +1108,26 @@ async function pollRampTransaction(api, txId, { intervalMs = 5e3, timeoutMs = 6e
|
|
|
1108
1108
|
throw new Error("Ramp transaction polling timed out");
|
|
1109
1109
|
}
|
|
1110
1110
|
|
|
1111
|
+
// src/lib/random-uuid.ts
|
|
1112
|
+
function randomUUID() {
|
|
1113
|
+
const c = globalThis.crypto;
|
|
1114
|
+
if (c && typeof c.randomUUID === "function") {
|
|
1115
|
+
return c.randomUUID();
|
|
1116
|
+
}
|
|
1117
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
1118
|
+
const bytes = new Uint8Array(16);
|
|
1119
|
+
c.getRandomValues(bytes);
|
|
1120
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
1121
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
1122
|
+
const hex = [];
|
|
1123
|
+
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
1124
|
+
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("")}`;
|
|
1125
|
+
}
|
|
1126
|
+
throw new Error(
|
|
1127
|
+
"[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."
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1111
1131
|
// src/dpop.ts
|
|
1112
1132
|
async function buildProof(args, keyManager) {
|
|
1113
1133
|
const jwk = await keyManager.getPublicJwk();
|
|
@@ -1117,7 +1137,7 @@ async function buildProof(args, keyManager) {
|
|
|
1117
1137
|
jwk
|
|
1118
1138
|
};
|
|
1119
1139
|
const payload = {
|
|
1120
|
-
jti:
|
|
1140
|
+
jti: randomUUID(),
|
|
1121
1141
|
htm: args.htm.toUpperCase(),
|
|
1122
1142
|
htu: normalizeHtu(args.htu),
|
|
1123
1143
|
iat: Math.floor(Date.now() / 1e3)
|
|
@@ -1151,24 +1171,6 @@ function normalizeHtu(rawUrl) {
|
|
|
1151
1171
|
const portPart = port ? `:${port}` : "";
|
|
1152
1172
|
return `${scheme}//${host}${portPart}${url.pathname}`;
|
|
1153
1173
|
}
|
|
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
1174
|
|
|
1173
1175
|
// src/storage/web.ts
|
|
1174
1176
|
var LOG_PREFIX = "[PollarClient:storage]";
|
|
@@ -1311,6 +1313,8 @@ function defaultVisibilityProvider() {
|
|
|
1311
1313
|
// src/types.ts
|
|
1312
1314
|
var AUTH_ERROR_CODES = {
|
|
1313
1315
|
SESSION_CREATE_FAILED: "SESSION_CREATE_FAILED",
|
|
1316
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
1317
|
+
SESSION_INVALID: "SESSION_INVALID",
|
|
1314
1318
|
EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED",
|
|
1315
1319
|
EMAIL_VERIFY_FAILED: "EMAIL_VERIFY_FAILED",
|
|
1316
1320
|
EMAIL_CODE_EXPIRED: "EMAIL_CODE_EXPIRED",
|
|
@@ -1624,7 +1628,32 @@ async function readWalletType(storage, apiKeyHash) {
|
|
|
1624
1628
|
return storage.get(walletTypeStorageKey(apiKeyHash));
|
|
1625
1629
|
}
|
|
1626
1630
|
|
|
1631
|
+
// src/lib/abort.ts
|
|
1632
|
+
function abortError() {
|
|
1633
|
+
if (typeof DOMException !== "undefined") {
|
|
1634
|
+
return new DOMException("Aborted", "AbortError");
|
|
1635
|
+
}
|
|
1636
|
+
const err = new Error("Aborted");
|
|
1637
|
+
err.name = "AbortError";
|
|
1638
|
+
return err;
|
|
1639
|
+
}
|
|
1640
|
+
function throwIfAborted(signal) {
|
|
1641
|
+
if (signal?.aborted) throw abortError();
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1627
1644
|
// src/client/stream.ts
|
|
1645
|
+
var SessionStatusError = class extends Error {
|
|
1646
|
+
constructor(code) {
|
|
1647
|
+
super(`[PollarClient] Session status terminal: ${code}`);
|
|
1648
|
+
this.code = code;
|
|
1649
|
+
this.name = "SessionStatusError";
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
function terminalStatusCode(parsed) {
|
|
1653
|
+
const err = parsed?.error;
|
|
1654
|
+
if (err === "INVALID_CLIENT_SESSION_ID" || err === "EXPIRED_CLIENT_ID") return err;
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1628
1657
|
function abortableDelay(ms, signal) {
|
|
1629
1658
|
return new Promise((resolve, reject) => {
|
|
1630
1659
|
const t = setTimeout(resolve, ms);
|
|
@@ -1632,7 +1661,7 @@ function abortableDelay(ms, signal) {
|
|
|
1632
1661
|
"abort",
|
|
1633
1662
|
() => {
|
|
1634
1663
|
clearTimeout(t);
|
|
1635
|
-
reject(
|
|
1664
|
+
reject(abortError());
|
|
1636
1665
|
},
|
|
1637
1666
|
{ once: true }
|
|
1638
1667
|
);
|
|
@@ -1647,7 +1676,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1647
1676
|
else await new Promise((r) => setTimeout(r, ms));
|
|
1648
1677
|
};
|
|
1649
1678
|
while (true) {
|
|
1650
|
-
|
|
1679
|
+
throwIfAborted(signal);
|
|
1651
1680
|
let data, error;
|
|
1652
1681
|
try {
|
|
1653
1682
|
({ data, error } = await api.GET("/auth/session/status/{clientSessionId}", {
|
|
@@ -1670,7 +1699,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1670
1699
|
let sawAnyChunk = false;
|
|
1671
1700
|
try {
|
|
1672
1701
|
while (true) {
|
|
1673
|
-
|
|
1702
|
+
throwIfAborted(signal);
|
|
1674
1703
|
const { done, value } = await reader.read();
|
|
1675
1704
|
if (done) {
|
|
1676
1705
|
streamDone = true;
|
|
@@ -1681,17 +1710,22 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1681
1710
|
for (const message of chunk.split("\n\n").filter(Boolean)) {
|
|
1682
1711
|
const dataLine = message.split("\n").find((l) => l.startsWith("data:"));
|
|
1683
1712
|
if (!dataLine) continue;
|
|
1713
|
+
let parsed;
|
|
1684
1714
|
try {
|
|
1685
|
-
|
|
1686
|
-
if (check(parsed)) {
|
|
1687
|
-
return parsed;
|
|
1688
|
-
}
|
|
1715
|
+
parsed = JSON.parse(dataLine.slice("data:".length).trim());
|
|
1689
1716
|
} catch {
|
|
1717
|
+
continue;
|
|
1718
|
+
}
|
|
1719
|
+
const terminal = terminalStatusCode(parsed);
|
|
1720
|
+
if (terminal) throw new SessionStatusError(terminal);
|
|
1721
|
+
if (check(parsed)) {
|
|
1722
|
+
return parsed;
|
|
1690
1723
|
}
|
|
1691
1724
|
}
|
|
1692
1725
|
}
|
|
1693
1726
|
} catch (e) {
|
|
1694
1727
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1728
|
+
if (e instanceof SessionStatusError) throw e;
|
|
1695
1729
|
console.warn(e);
|
|
1696
1730
|
} finally {
|
|
1697
1731
|
reader.releaseLock();
|
|
@@ -1702,12 +1736,72 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1702
1736
|
if (delay) await sleep(delay);
|
|
1703
1737
|
}
|
|
1704
1738
|
}
|
|
1739
|
+
async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal) {
|
|
1740
|
+
const url = `${baseUrl}/auth/session/status/${encodeURIComponent(clientSessionId)}/poll`;
|
|
1741
|
+
let backoff = intervalMs;
|
|
1742
|
+
const sleep = async (ms) => {
|
|
1743
|
+
if (ms <= 0) return;
|
|
1744
|
+
if (signal) await abortableDelay(ms, signal);
|
|
1745
|
+
else await new Promise((r) => setTimeout(r, ms));
|
|
1746
|
+
};
|
|
1747
|
+
while (true) {
|
|
1748
|
+
throwIfAborted(signal);
|
|
1749
|
+
let envelope = null;
|
|
1750
|
+
let httpStatus = 0;
|
|
1751
|
+
try {
|
|
1752
|
+
const response = await fetch(url, { headers: { accept: "application/json" }, signal: signal ?? null });
|
|
1753
|
+
httpStatus = response.status;
|
|
1754
|
+
envelope = await response.json().catch(() => null);
|
|
1755
|
+
} catch (e) {
|
|
1756
|
+
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1757
|
+
console.warn(e);
|
|
1758
|
+
}
|
|
1759
|
+
if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
|
|
1760
|
+
throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
|
|
1761
|
+
}
|
|
1762
|
+
if (httpStatus === 410 || envelope?.code === "EXPIRED_CLIENT_ID") {
|
|
1763
|
+
throw new SessionStatusError("EXPIRED_CLIENT_ID");
|
|
1764
|
+
}
|
|
1765
|
+
if (envelope?.success && envelope.content && check(envelope.content)) {
|
|
1766
|
+
return envelope.content;
|
|
1767
|
+
}
|
|
1768
|
+
if (envelope) backoff = intervalMs;
|
|
1769
|
+
else backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
1770
|
+
await sleep(backoff);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
function waitForSessionReady(args) {
|
|
1774
|
+
const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal } = args;
|
|
1775
|
+
return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal);
|
|
1776
|
+
}
|
|
1705
1777
|
|
|
1706
1778
|
// src/client/auth/authenticate.ts
|
|
1707
1779
|
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
1708
|
-
const { api, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1780
|
+
const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1709
1781
|
setAuthState({ step: "authenticating" });
|
|
1710
|
-
|
|
1782
|
+
try {
|
|
1783
|
+
await waitForSessionReady({
|
|
1784
|
+
api,
|
|
1785
|
+
baseUrl: basePath,
|
|
1786
|
+
clientSessionId,
|
|
1787
|
+
check: (data2) => data2?.status === "READY",
|
|
1788
|
+
useStreaming,
|
|
1789
|
+
signal
|
|
1790
|
+
});
|
|
1791
|
+
} catch (err) {
|
|
1792
|
+
if (err instanceof SessionStatusError) {
|
|
1793
|
+
const expired = err.code === "EXPIRED_CLIENT_ID";
|
|
1794
|
+
setAuthState({
|
|
1795
|
+
step: "error",
|
|
1796
|
+
previousStep: "authenticating",
|
|
1797
|
+
message: expired ? "Login session expired \u2014 please try again" : "Login session is no longer valid \u2014 please try again",
|
|
1798
|
+
errorCode: expired ? AUTH_ERROR_CODES.SESSION_EXPIRED : AUTH_ERROR_CODES.SESSION_INVALID
|
|
1799
|
+
});
|
|
1800
|
+
await clearSession();
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
throw err;
|
|
1804
|
+
}
|
|
1711
1805
|
const dpopJwk = await deps.getPublicJwk();
|
|
1712
1806
|
const { data } = await api.POST("/auth/login", {
|
|
1713
1807
|
body: {
|
|
@@ -1831,26 +1925,36 @@ function severOpener(popup) {
|
|
|
1831
1925
|
} catch {
|
|
1832
1926
|
}
|
|
1833
1927
|
}
|
|
1834
|
-
async
|
|
1835
|
-
const
|
|
1836
|
-
const popup = window.open("about:blank", "_blank");
|
|
1928
|
+
var defaultWebOAuthOpener = async ({ getUrl }) => {
|
|
1929
|
+
const popup = typeof window !== "undefined" ? window.open("about:blank", "_blank") : null;
|
|
1837
1930
|
severOpener(popup);
|
|
1838
|
-
const
|
|
1839
|
-
if (!
|
|
1931
|
+
const url = await getUrl();
|
|
1932
|
+
if (!url) {
|
|
1840
1933
|
popup?.close();
|
|
1841
1934
|
return;
|
|
1842
1935
|
}
|
|
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
1936
|
if (popup) {
|
|
1849
|
-
popup.location.href = url
|
|
1937
|
+
popup.location.href = url;
|
|
1850
1938
|
severOpener(popup);
|
|
1851
|
-
} else {
|
|
1852
|
-
window.open(url
|
|
1939
|
+
} else if (typeof window !== "undefined") {
|
|
1940
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1853
1941
|
}
|
|
1942
|
+
};
|
|
1943
|
+
async function loginOAuth(provider, deps) {
|
|
1944
|
+
const { setAuthState, basePath, apiKey, openAuthUrl, redirectUri, signal } = deps;
|
|
1945
|
+
let clientSessionId = null;
|
|
1946
|
+
const getUrl = async () => {
|
|
1947
|
+
clientSessionId = await createAuthSession(deps);
|
|
1948
|
+
if (!clientSessionId) return null;
|
|
1949
|
+
setAuthState({ step: "opening_oauth", provider });
|
|
1950
|
+
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1951
|
+
url.searchParams.set("api_key", apiKey);
|
|
1952
|
+
url.searchParams.set("client_session_id", clientSessionId);
|
|
1953
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
1954
|
+
return url.toString();
|
|
1955
|
+
};
|
|
1956
|
+
await openAuthUrl({ provider, getUrl, redirectUri, signal });
|
|
1957
|
+
if (!clientSessionId) return;
|
|
1854
1958
|
await authenticate(clientSessionId, deps);
|
|
1855
1959
|
}
|
|
1856
1960
|
|
|
@@ -1860,10 +1964,10 @@ function withSignal(promise, signal) {
|
|
|
1860
1964
|
promise,
|
|
1861
1965
|
new Promise((_, reject) => {
|
|
1862
1966
|
if (signal.aborted) {
|
|
1863
|
-
reject(
|
|
1967
|
+
reject(abortError());
|
|
1864
1968
|
return;
|
|
1865
1969
|
}
|
|
1866
|
-
signal.addEventListener("abort", () => reject(
|
|
1970
|
+
signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
1867
1971
|
})
|
|
1868
1972
|
]);
|
|
1869
1973
|
}
|
|
@@ -1911,6 +2015,8 @@ async function loginWallet(type, deps) {
|
|
|
1911
2015
|
|
|
1912
2016
|
// src/client/client.ts
|
|
1913
2017
|
var isBrowser = typeof window !== "undefined" && typeof localStorage !== "undefined";
|
|
2018
|
+
var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
2019
|
+
var isClientRuntime = isBrowser || isReactNative;
|
|
1914
2020
|
var REFRESH_SKEW_SECONDS = 60;
|
|
1915
2021
|
function warnServerSide(method) {
|
|
1916
2022
|
console.warn(
|
|
@@ -1966,7 +2072,7 @@ var PollarClient = class {
|
|
|
1966
2072
|
this._walletAdapter = null;
|
|
1967
2073
|
this._loginController = null;
|
|
1968
2074
|
this.apiKey = config.apiKey;
|
|
1969
|
-
this.id =
|
|
2075
|
+
this.id = randomUUID();
|
|
1970
2076
|
this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
|
|
1971
2077
|
this._storage = config.storage ?? defaultStorage({
|
|
1972
2078
|
onDegrade: (reason, error) => {
|
|
@@ -1980,10 +2086,12 @@ var PollarClient = class {
|
|
|
1980
2086
|
this._deviceLabel = config.deviceLabel;
|
|
1981
2087
|
this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
|
|
1982
2088
|
this._maxIdleMs = config.maxIdleMs;
|
|
2089
|
+
this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
|
|
2090
|
+
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location.origin : "");
|
|
1983
2091
|
this._api = createApiClient(this.basePath);
|
|
1984
2092
|
this._wireMiddlewares();
|
|
1985
2093
|
this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
|
|
1986
|
-
if (!
|
|
2094
|
+
if (!isClientRuntime) {
|
|
1987
2095
|
warnServerSide("constructor");
|
|
1988
2096
|
this._initialized = Promise.resolve();
|
|
1989
2097
|
return;
|
|
@@ -2009,7 +2117,7 @@ var PollarClient = class {
|
|
|
2009
2117
|
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
2010
2118
|
async _initialize() {
|
|
2011
2119
|
this._apiKeyHash = await hashApiKey(this.apiKey);
|
|
2012
|
-
if (
|
|
2120
|
+
if (isBrowser) {
|
|
2013
2121
|
const sessionKey = sessionStorageKey(this._apiKeyHash);
|
|
2014
2122
|
const handler = (e) => {
|
|
2015
2123
|
if (e.key === sessionKey) {
|
|
@@ -2031,7 +2139,7 @@ var PollarClient = class {
|
|
|
2031
2139
|
}
|
|
2032
2140
|
/** Detach the cross-tab storage listener and abort any in-flight login. */
|
|
2033
2141
|
destroy() {
|
|
2034
|
-
if (this._storageEventHandler &&
|
|
2142
|
+
if (this._storageEventHandler && isBrowser) {
|
|
2035
2143
|
window.removeEventListener("storage", this._storageEventHandler);
|
|
2036
2144
|
this._storageEventHandler = null;
|
|
2037
2145
|
}
|
|
@@ -2314,7 +2422,7 @@ var PollarClient = class {
|
|
|
2314
2422
|
}
|
|
2315
2423
|
// ─── Login (unified entry point) ─────────────────────────────────────────
|
|
2316
2424
|
login(options) {
|
|
2317
|
-
if (!
|
|
2425
|
+
if (!isClientRuntime) {
|
|
2318
2426
|
warnServerSide("login");
|
|
2319
2427
|
return;
|
|
2320
2428
|
}
|
|
@@ -2325,7 +2433,9 @@ var PollarClient = class {
|
|
|
2325
2433
|
loginOAuth(options.provider, {
|
|
2326
2434
|
...deps,
|
|
2327
2435
|
basePath: this.basePath,
|
|
2328
|
-
apiKey: this.apiKey
|
|
2436
|
+
apiKey: this.apiKey,
|
|
2437
|
+
openAuthUrl: this._openAuthUrl,
|
|
2438
|
+
redirectUri: this._oauthRedirectUri
|
|
2329
2439
|
}).catch((err) => this._handleFlowError(err));
|
|
2330
2440
|
} else if (options.provider === "email") {
|
|
2331
2441
|
const { email } = options;
|
|
@@ -2341,7 +2451,7 @@ var PollarClient = class {
|
|
|
2341
2451
|
}
|
|
2342
2452
|
// ─── Email OTP flow (3 steps) ─────────────────────────────────────────────
|
|
2343
2453
|
beginEmailLogin() {
|
|
2344
|
-
if (!
|
|
2454
|
+
if (!isClientRuntime) {
|
|
2345
2455
|
warnServerSide("beginEmailLogin");
|
|
2346
2456
|
return;
|
|
2347
2457
|
}
|
|
@@ -2349,7 +2459,7 @@ var PollarClient = class {
|
|
|
2349
2459
|
initEmailSession(this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
|
|
2350
2460
|
}
|
|
2351
2461
|
sendEmailCode(email) {
|
|
2352
|
-
if (!
|
|
2462
|
+
if (!isClientRuntime) {
|
|
2353
2463
|
warnServerSide("sendEmailCode");
|
|
2354
2464
|
return;
|
|
2355
2465
|
}
|
|
@@ -2361,7 +2471,7 @@ var PollarClient = class {
|
|
|
2361
2471
|
sendEmailCode(email, clientSessionId, this._flowDeps(signal)).catch((err) => this._handleFlowError(err));
|
|
2362
2472
|
}
|
|
2363
2473
|
verifyEmailCode(code) {
|
|
2364
|
-
if (!
|
|
2474
|
+
if (!isClientRuntime) {
|
|
2365
2475
|
warnServerSide("verifyEmailCode");
|
|
2366
2476
|
return;
|
|
2367
2477
|
}
|
|
@@ -2379,7 +2489,7 @@ var PollarClient = class {
|
|
|
2379
2489
|
}
|
|
2380
2490
|
// ─── Wallet flow (single call) ────────────────────────────────────────────
|
|
2381
2491
|
loginWallet(type) {
|
|
2382
|
-
if (!
|
|
2492
|
+
if (!isClientRuntime) {
|
|
2383
2493
|
warnServerSide("loginWallet");
|
|
2384
2494
|
return;
|
|
2385
2495
|
}
|
|
@@ -2405,7 +2515,7 @@ var PollarClient = class {
|
|
|
2405
2515
|
* across all devices.
|
|
2406
2516
|
*/
|
|
2407
2517
|
async logout(options = {}) {
|
|
2408
|
-
if (!
|
|
2518
|
+
if (!isClientRuntime) {
|
|
2409
2519
|
warnServerSide("logout");
|
|
2410
2520
|
return;
|
|
2411
2521
|
}
|
|
@@ -2435,7 +2545,7 @@ var PollarClient = class {
|
|
|
2435
2545
|
* `current` flag identifies which entry corresponds to this client.
|
|
2436
2546
|
*/
|
|
2437
2547
|
async listSessions() {
|
|
2438
|
-
if (!
|
|
2548
|
+
if (!isClientRuntime) {
|
|
2439
2549
|
warnServerSide("listSessions");
|
|
2440
2550
|
return [];
|
|
2441
2551
|
}
|
|
@@ -2454,7 +2564,7 @@ var PollarClient = class {
|
|
|
2454
2564
|
* does NOT clear local state — call `logout()` for that case.
|
|
2455
2565
|
*/
|
|
2456
2566
|
async revokeSession(familyId) {
|
|
2457
|
-
if (!
|
|
2567
|
+
if (!isClientRuntime) {
|
|
2458
2568
|
warnServerSide("revokeSession");
|
|
2459
2569
|
return;
|
|
2460
2570
|
}
|
|
@@ -2952,6 +3062,11 @@ var PollarClient = class {
|
|
|
2952
3062
|
_flowDeps(signal) {
|
|
2953
3063
|
return {
|
|
2954
3064
|
api: this._api,
|
|
3065
|
+
basePath: this.basePath,
|
|
3066
|
+
// SSE status streaming works on web; React Native's `fetch` has no
|
|
3067
|
+
// readable `response.body`, so those clients poll the non-streaming
|
|
3068
|
+
// status endpoint instead. `isBrowser` is false in RN and SSR alike.
|
|
3069
|
+
useStreaming: isBrowser,
|
|
2955
3070
|
signal,
|
|
2956
3071
|
setAuthState: this._setAuthState.bind(this),
|
|
2957
3072
|
storeSession: this._storeSession.bind(this),
|