@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.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var sha2 = require('@noble/hashes/sha2');
|
|
4
|
+
|
|
3
5
|
var __create = Object.create;
|
|
4
6
|
var __defProp = Object.defineProperty;
|
|
5
7
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -184,11 +186,8 @@ function defaultKeyManager(storage, apiKey) {
|
|
|
184
186
|
}
|
|
185
187
|
return _factory(storage, apiKey);
|
|
186
188
|
}
|
|
187
|
-
|
|
188
|
-
// src/lib/sha256.ts
|
|
189
189
|
async function sha256(data) {
|
|
190
|
-
|
|
191
|
-
return new Uint8Array(buf);
|
|
190
|
+
return sha2.sha256(data);
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
// src/lib/api-key-hash.ts
|
|
@@ -981,6 +980,26 @@ async function pollRampTransaction(api, txId, { intervalMs = 5e3, timeoutMs = 6e
|
|
|
981
980
|
throw new Error("Ramp transaction polling timed out");
|
|
982
981
|
}
|
|
983
982
|
|
|
983
|
+
// src/lib/random-uuid.ts
|
|
984
|
+
function randomUUID() {
|
|
985
|
+
const c = globalThis.crypto;
|
|
986
|
+
if (c && typeof c.randomUUID === "function") {
|
|
987
|
+
return c.randomUUID();
|
|
988
|
+
}
|
|
989
|
+
if (c && typeof c.getRandomValues === "function") {
|
|
990
|
+
const bytes = new Uint8Array(16);
|
|
991
|
+
c.getRandomValues(bytes);
|
|
992
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
993
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
994
|
+
const hex = [];
|
|
995
|
+
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
996
|
+
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("")}`;
|
|
997
|
+
}
|
|
998
|
+
throw new Error(
|
|
999
|
+
"[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."
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
984
1003
|
// src/dpop.ts
|
|
985
1004
|
async function buildProof(args, keyManager) {
|
|
986
1005
|
const jwk = await keyManager.getPublicJwk();
|
|
@@ -990,7 +1009,7 @@ async function buildProof(args, keyManager) {
|
|
|
990
1009
|
jwk
|
|
991
1010
|
};
|
|
992
1011
|
const payload = {
|
|
993
|
-
jti:
|
|
1012
|
+
jti: randomUUID(),
|
|
994
1013
|
htm: args.htm.toUpperCase(),
|
|
995
1014
|
htu: normalizeHtu(args.htu),
|
|
996
1015
|
iat: Math.floor(Date.now() / 1e3)
|
|
@@ -1024,24 +1043,6 @@ function normalizeHtu(rawUrl) {
|
|
|
1024
1043
|
const portPart = port ? `:${port}` : "";
|
|
1025
1044
|
return `${scheme}//${host}${portPart}${url.pathname}`;
|
|
1026
1045
|
}
|
|
1027
|
-
function generateJti() {
|
|
1028
|
-
const c = globalThis.crypto;
|
|
1029
|
-
if (c && typeof c.randomUUID === "function") {
|
|
1030
|
-
return c.randomUUID();
|
|
1031
|
-
}
|
|
1032
|
-
if (c && typeof c.getRandomValues === "function") {
|
|
1033
|
-
const bytes = new Uint8Array(16);
|
|
1034
|
-
c.getRandomValues(bytes);
|
|
1035
|
-
bytes[6] = bytes[6] & 15 | 64;
|
|
1036
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
1037
|
-
const hex = [];
|
|
1038
|
-
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
1039
|
-
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("")}`;
|
|
1040
|
-
}
|
|
1041
|
-
throw new Error(
|
|
1042
|
-
"[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."
|
|
1043
|
-
);
|
|
1044
|
-
}
|
|
1045
1046
|
|
|
1046
1047
|
// src/storage/web.ts
|
|
1047
1048
|
var LOG_PREFIX = "[PollarClient:storage]";
|
|
@@ -1184,6 +1185,8 @@ function defaultVisibilityProvider() {
|
|
|
1184
1185
|
// src/types.ts
|
|
1185
1186
|
var AUTH_ERROR_CODES = {
|
|
1186
1187
|
SESSION_CREATE_FAILED: "SESSION_CREATE_FAILED",
|
|
1188
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
1189
|
+
SESSION_INVALID: "SESSION_INVALID",
|
|
1187
1190
|
EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED",
|
|
1188
1191
|
EMAIL_VERIFY_FAILED: "EMAIL_VERIFY_FAILED",
|
|
1189
1192
|
EMAIL_CODE_EXPIRED: "EMAIL_CODE_EXPIRED",
|
|
@@ -1497,7 +1500,32 @@ async function readWalletType(storage, apiKeyHash) {
|
|
|
1497
1500
|
return storage.get(walletTypeStorageKey(apiKeyHash));
|
|
1498
1501
|
}
|
|
1499
1502
|
|
|
1503
|
+
// src/lib/abort.ts
|
|
1504
|
+
function abortError() {
|
|
1505
|
+
if (typeof DOMException !== "undefined") {
|
|
1506
|
+
return new DOMException("Aborted", "AbortError");
|
|
1507
|
+
}
|
|
1508
|
+
const err = new Error("Aborted");
|
|
1509
|
+
err.name = "AbortError";
|
|
1510
|
+
return err;
|
|
1511
|
+
}
|
|
1512
|
+
function throwIfAborted(signal) {
|
|
1513
|
+
if (signal?.aborted) throw abortError();
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1500
1516
|
// src/client/stream.ts
|
|
1517
|
+
var SessionStatusError = class extends Error {
|
|
1518
|
+
constructor(code) {
|
|
1519
|
+
super(`[PollarClient] Session status terminal: ${code}`);
|
|
1520
|
+
this.code = code;
|
|
1521
|
+
this.name = "SessionStatusError";
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
function terminalStatusCode(parsed) {
|
|
1525
|
+
const err = parsed?.error;
|
|
1526
|
+
if (err === "INVALID_CLIENT_SESSION_ID" || err === "EXPIRED_CLIENT_ID") return err;
|
|
1527
|
+
return null;
|
|
1528
|
+
}
|
|
1501
1529
|
function abortableDelay(ms, signal) {
|
|
1502
1530
|
return new Promise((resolve, reject) => {
|
|
1503
1531
|
const t = setTimeout(resolve, ms);
|
|
@@ -1505,7 +1533,7 @@ function abortableDelay(ms, signal) {
|
|
|
1505
1533
|
"abort",
|
|
1506
1534
|
() => {
|
|
1507
1535
|
clearTimeout(t);
|
|
1508
|
-
reject(
|
|
1536
|
+
reject(abortError());
|
|
1509
1537
|
},
|
|
1510
1538
|
{ once: true }
|
|
1511
1539
|
);
|
|
@@ -1520,7 +1548,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1520
1548
|
else await new Promise((r) => setTimeout(r, ms));
|
|
1521
1549
|
};
|
|
1522
1550
|
while (true) {
|
|
1523
|
-
|
|
1551
|
+
throwIfAborted(signal);
|
|
1524
1552
|
let data, error;
|
|
1525
1553
|
try {
|
|
1526
1554
|
({ data, error } = await api.GET("/auth/session/status/{clientSessionId}", {
|
|
@@ -1543,7 +1571,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1543
1571
|
let sawAnyChunk = false;
|
|
1544
1572
|
try {
|
|
1545
1573
|
while (true) {
|
|
1546
|
-
|
|
1574
|
+
throwIfAborted(signal);
|
|
1547
1575
|
const { done, value } = await reader.read();
|
|
1548
1576
|
if (done) {
|
|
1549
1577
|
streamDone = true;
|
|
@@ -1554,17 +1582,22 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1554
1582
|
for (const message of chunk.split("\n\n").filter(Boolean)) {
|
|
1555
1583
|
const dataLine = message.split("\n").find((l) => l.startsWith("data:"));
|
|
1556
1584
|
if (!dataLine) continue;
|
|
1585
|
+
let parsed;
|
|
1557
1586
|
try {
|
|
1558
|
-
|
|
1559
|
-
if (check(parsed)) {
|
|
1560
|
-
return parsed;
|
|
1561
|
-
}
|
|
1587
|
+
parsed = JSON.parse(dataLine.slice("data:".length).trim());
|
|
1562
1588
|
} catch {
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
const terminal = terminalStatusCode(parsed);
|
|
1592
|
+
if (terminal) throw new SessionStatusError(terminal);
|
|
1593
|
+
if (check(parsed)) {
|
|
1594
|
+
return parsed;
|
|
1563
1595
|
}
|
|
1564
1596
|
}
|
|
1565
1597
|
}
|
|
1566
1598
|
} catch (e) {
|
|
1567
1599
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1600
|
+
if (e instanceof SessionStatusError) throw e;
|
|
1568
1601
|
console.warn(e);
|
|
1569
1602
|
} finally {
|
|
1570
1603
|
reader.releaseLock();
|
|
@@ -1575,12 +1608,72 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1575
1608
|
if (delay) await sleep(delay);
|
|
1576
1609
|
}
|
|
1577
1610
|
}
|
|
1611
|
+
async function pollUntilFound(baseUrl, clientSessionId, check, intervalMs = 500, signal) {
|
|
1612
|
+
const url = `${baseUrl}/auth/session/status/${encodeURIComponent(clientSessionId)}/poll`;
|
|
1613
|
+
let backoff = intervalMs;
|
|
1614
|
+
const sleep = async (ms) => {
|
|
1615
|
+
if (ms <= 0) return;
|
|
1616
|
+
if (signal) await abortableDelay(ms, signal);
|
|
1617
|
+
else await new Promise((r) => setTimeout(r, ms));
|
|
1618
|
+
};
|
|
1619
|
+
while (true) {
|
|
1620
|
+
throwIfAborted(signal);
|
|
1621
|
+
let envelope = null;
|
|
1622
|
+
let httpStatus = 0;
|
|
1623
|
+
try {
|
|
1624
|
+
const response = await fetch(url, { headers: { accept: "application/json" }, signal: signal ?? null });
|
|
1625
|
+
httpStatus = response.status;
|
|
1626
|
+
envelope = await response.json().catch(() => null);
|
|
1627
|
+
} catch (e) {
|
|
1628
|
+
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1629
|
+
console.warn(e);
|
|
1630
|
+
}
|
|
1631
|
+
if (httpStatus === 404 || envelope?.code === "INVALID_CLIENT_SESSION_ID") {
|
|
1632
|
+
throw new SessionStatusError("INVALID_CLIENT_SESSION_ID");
|
|
1633
|
+
}
|
|
1634
|
+
if (httpStatus === 410 || envelope?.code === "EXPIRED_CLIENT_ID") {
|
|
1635
|
+
throw new SessionStatusError("EXPIRED_CLIENT_ID");
|
|
1636
|
+
}
|
|
1637
|
+
if (envelope?.success && envelope.content && check(envelope.content)) {
|
|
1638
|
+
return envelope.content;
|
|
1639
|
+
}
|
|
1640
|
+
if (envelope) backoff = intervalMs;
|
|
1641
|
+
else backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
1642
|
+
await sleep(backoff);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
function waitForSessionReady(args) {
|
|
1646
|
+
const { api, baseUrl, clientSessionId, check, useStreaming, retryDelayMs, signal } = args;
|
|
1647
|
+
return useStreaming ? streamUntilFound(api, clientSessionId, check, retryDelayMs ?? 200, signal) : pollUntilFound(baseUrl, clientSessionId, check, retryDelayMs ?? 500, signal);
|
|
1648
|
+
}
|
|
1578
1649
|
|
|
1579
1650
|
// src/client/auth/authenticate.ts
|
|
1580
1651
|
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
1581
|
-
const { api, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1652
|
+
const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1582
1653
|
setAuthState({ step: "authenticating" });
|
|
1583
|
-
|
|
1654
|
+
try {
|
|
1655
|
+
await waitForSessionReady({
|
|
1656
|
+
api,
|
|
1657
|
+
baseUrl: basePath,
|
|
1658
|
+
clientSessionId,
|
|
1659
|
+
check: (data2) => data2?.status === "READY",
|
|
1660
|
+
useStreaming,
|
|
1661
|
+
signal
|
|
1662
|
+
});
|
|
1663
|
+
} catch (err) {
|
|
1664
|
+
if (err instanceof SessionStatusError) {
|
|
1665
|
+
const expired = err.code === "EXPIRED_CLIENT_ID";
|
|
1666
|
+
setAuthState({
|
|
1667
|
+
step: "error",
|
|
1668
|
+
previousStep: "authenticating",
|
|
1669
|
+
message: expired ? "Login session expired \u2014 please try again" : "Login session is no longer valid \u2014 please try again",
|
|
1670
|
+
errorCode: expired ? AUTH_ERROR_CODES.SESSION_EXPIRED : AUTH_ERROR_CODES.SESSION_INVALID
|
|
1671
|
+
});
|
|
1672
|
+
await clearSession();
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
throw err;
|
|
1676
|
+
}
|
|
1584
1677
|
const dpopJwk = await deps.getPublicJwk();
|
|
1585
1678
|
const { data } = await api.POST("/auth/login", {
|
|
1586
1679
|
body: {
|
|
@@ -1704,26 +1797,36 @@ function severOpener(popup) {
|
|
|
1704
1797
|
} catch {
|
|
1705
1798
|
}
|
|
1706
1799
|
}
|
|
1707
|
-
async
|
|
1708
|
-
const
|
|
1709
|
-
const popup = window.open("about:blank", "_blank");
|
|
1800
|
+
var defaultWebOAuthOpener = async ({ getUrl }) => {
|
|
1801
|
+
const popup = typeof window !== "undefined" ? window.open("about:blank", "_blank") : null;
|
|
1710
1802
|
severOpener(popup);
|
|
1711
|
-
const
|
|
1712
|
-
if (!
|
|
1803
|
+
const url = await getUrl();
|
|
1804
|
+
if (!url) {
|
|
1713
1805
|
popup?.close();
|
|
1714
1806
|
return;
|
|
1715
1807
|
}
|
|
1716
|
-
setAuthState({ step: "opening_oauth", provider });
|
|
1717
|
-
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1718
|
-
url.searchParams.set("api_key", apiKey);
|
|
1719
|
-
url.searchParams.set("client_session_id", clientSessionId);
|
|
1720
|
-
url.searchParams.set("redirect_uri", window.location.origin);
|
|
1721
1808
|
if (popup) {
|
|
1722
|
-
popup.location.href = url
|
|
1809
|
+
popup.location.href = url;
|
|
1723
1810
|
severOpener(popup);
|
|
1724
|
-
} else {
|
|
1725
|
-
window.open(url
|
|
1811
|
+
} else if (typeof window !== "undefined") {
|
|
1812
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1726
1813
|
}
|
|
1814
|
+
};
|
|
1815
|
+
async function loginOAuth(provider, deps) {
|
|
1816
|
+
const { setAuthState, basePath, apiKey, openAuthUrl, redirectUri, signal } = deps;
|
|
1817
|
+
let clientSessionId = null;
|
|
1818
|
+
const getUrl = async () => {
|
|
1819
|
+
clientSessionId = await createAuthSession(deps);
|
|
1820
|
+
if (!clientSessionId) return null;
|
|
1821
|
+
setAuthState({ step: "opening_oauth", provider });
|
|
1822
|
+
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1823
|
+
url.searchParams.set("api_key", apiKey);
|
|
1824
|
+
url.searchParams.set("client_session_id", clientSessionId);
|
|
1825
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
1826
|
+
return url.toString();
|
|
1827
|
+
};
|
|
1828
|
+
await openAuthUrl({ provider, getUrl, redirectUri, signal });
|
|
1829
|
+
if (!clientSessionId) return;
|
|
1727
1830
|
await authenticate(clientSessionId, deps);
|
|
1728
1831
|
}
|
|
1729
1832
|
|
|
@@ -1733,10 +1836,10 @@ function withSignal(promise, signal) {
|
|
|
1733
1836
|
promise,
|
|
1734
1837
|
new Promise((_, reject) => {
|
|
1735
1838
|
if (signal.aborted) {
|
|
1736
|
-
reject(
|
|
1839
|
+
reject(abortError());
|
|
1737
1840
|
return;
|
|
1738
1841
|
}
|
|
1739
|
-
signal.addEventListener("abort", () => reject(
|
|
1842
|
+
signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
1740
1843
|
})
|
|
1741
1844
|
]);
|
|
1742
1845
|
}
|
|
@@ -1784,6 +1887,8 @@ async function loginWallet(type, deps) {
|
|
|
1784
1887
|
|
|
1785
1888
|
// src/client/client.ts
|
|
1786
1889
|
var isBrowser = typeof window !== "undefined" && typeof localStorage !== "undefined";
|
|
1890
|
+
var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
1891
|
+
var isClientRuntime = isBrowser || isReactNative;
|
|
1787
1892
|
var REFRESH_SKEW_SECONDS = 60;
|
|
1788
1893
|
function warnServerSide(method) {
|
|
1789
1894
|
console.warn(
|
|
@@ -1839,7 +1944,7 @@ var PollarClient = class {
|
|
|
1839
1944
|
this._walletAdapter = null;
|
|
1840
1945
|
this._loginController = null;
|
|
1841
1946
|
this.apiKey = config.apiKey;
|
|
1842
|
-
this.id =
|
|
1947
|
+
this.id = randomUUID();
|
|
1843
1948
|
this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
|
|
1844
1949
|
this._storage = config.storage ?? defaultStorage({
|
|
1845
1950
|
onDegrade: (reason, error) => {
|
|
@@ -1853,10 +1958,12 @@ var PollarClient = class {
|
|
|
1853
1958
|
this._deviceLabel = config.deviceLabel;
|
|
1854
1959
|
this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
|
|
1855
1960
|
this._maxIdleMs = config.maxIdleMs;
|
|
1961
|
+
this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
|
|
1962
|
+
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location.origin : "");
|
|
1856
1963
|
this._api = createApiClient(this.basePath);
|
|
1857
1964
|
this._wireMiddlewares();
|
|
1858
1965
|
this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
|
|
1859
|
-
if (!
|
|
1966
|
+
if (!isClientRuntime) {
|
|
1860
1967
|
warnServerSide("constructor");
|
|
1861
1968
|
this._initialized = Promise.resolve();
|
|
1862
1969
|
return;
|
|
@@ -1882,7 +1989,7 @@ var PollarClient = class {
|
|
|
1882
1989
|
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
1883
1990
|
async _initialize() {
|
|
1884
1991
|
this._apiKeyHash = await hashApiKey(this.apiKey);
|
|
1885
|
-
if (
|
|
1992
|
+
if (isBrowser) {
|
|
1886
1993
|
const sessionKey = sessionStorageKey(this._apiKeyHash);
|
|
1887
1994
|
const handler = (e) => {
|
|
1888
1995
|
if (e.key === sessionKey) {
|
|
@@ -1904,7 +2011,7 @@ var PollarClient = class {
|
|
|
1904
2011
|
}
|
|
1905
2012
|
/** Detach the cross-tab storage listener and abort any in-flight login. */
|
|
1906
2013
|
destroy() {
|
|
1907
|
-
if (this._storageEventHandler &&
|
|
2014
|
+
if (this._storageEventHandler && isBrowser) {
|
|
1908
2015
|
window.removeEventListener("storage", this._storageEventHandler);
|
|
1909
2016
|
this._storageEventHandler = null;
|
|
1910
2017
|
}
|
|
@@ -2187,7 +2294,7 @@ var PollarClient = class {
|
|
|
2187
2294
|
}
|
|
2188
2295
|
// ─── Login (unified entry point) ─────────────────────────────────────────
|
|
2189
2296
|
login(options) {
|
|
2190
|
-
if (!
|
|
2297
|
+
if (!isClientRuntime) {
|
|
2191
2298
|
warnServerSide("login");
|
|
2192
2299
|
return;
|
|
2193
2300
|
}
|
|
@@ -2198,7 +2305,9 @@ var PollarClient = class {
|
|
|
2198
2305
|
loginOAuth(options.provider, {
|
|
2199
2306
|
...deps,
|
|
2200
2307
|
basePath: this.basePath,
|
|
2201
|
-
apiKey: this.apiKey
|
|
2308
|
+
apiKey: this.apiKey,
|
|
2309
|
+
openAuthUrl: this._openAuthUrl,
|
|
2310
|
+
redirectUri: this._oauthRedirectUri
|
|
2202
2311
|
}).catch((err) => this._handleFlowError(err));
|
|
2203
2312
|
} else if (options.provider === "email") {
|
|
2204
2313
|
const { email } = options;
|
|
@@ -2214,7 +2323,7 @@ var PollarClient = class {
|
|
|
2214
2323
|
}
|
|
2215
2324
|
// ─── Email OTP flow (3 steps) ─────────────────────────────────────────────
|
|
2216
2325
|
beginEmailLogin() {
|
|
2217
|
-
if (!
|
|
2326
|
+
if (!isClientRuntime) {
|
|
2218
2327
|
warnServerSide("beginEmailLogin");
|
|
2219
2328
|
return;
|
|
2220
2329
|
}
|
|
@@ -2222,7 +2331,7 @@ var PollarClient = class {
|
|
|
2222
2331
|
initEmailSession(this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
|
|
2223
2332
|
}
|
|
2224
2333
|
sendEmailCode(email) {
|
|
2225
|
-
if (!
|
|
2334
|
+
if (!isClientRuntime) {
|
|
2226
2335
|
warnServerSide("sendEmailCode");
|
|
2227
2336
|
return;
|
|
2228
2337
|
}
|
|
@@ -2234,7 +2343,7 @@ var PollarClient = class {
|
|
|
2234
2343
|
sendEmailCode(email, clientSessionId, this._flowDeps(signal)).catch((err) => this._handleFlowError(err));
|
|
2235
2344
|
}
|
|
2236
2345
|
verifyEmailCode(code) {
|
|
2237
|
-
if (!
|
|
2346
|
+
if (!isClientRuntime) {
|
|
2238
2347
|
warnServerSide("verifyEmailCode");
|
|
2239
2348
|
return;
|
|
2240
2349
|
}
|
|
@@ -2252,7 +2361,7 @@ var PollarClient = class {
|
|
|
2252
2361
|
}
|
|
2253
2362
|
// ─── Wallet flow (single call) ────────────────────────────────────────────
|
|
2254
2363
|
loginWallet(type) {
|
|
2255
|
-
if (!
|
|
2364
|
+
if (!isClientRuntime) {
|
|
2256
2365
|
warnServerSide("loginWallet");
|
|
2257
2366
|
return;
|
|
2258
2367
|
}
|
|
@@ -2278,7 +2387,7 @@ var PollarClient = class {
|
|
|
2278
2387
|
* across all devices.
|
|
2279
2388
|
*/
|
|
2280
2389
|
async logout(options = {}) {
|
|
2281
|
-
if (!
|
|
2390
|
+
if (!isClientRuntime) {
|
|
2282
2391
|
warnServerSide("logout");
|
|
2283
2392
|
return;
|
|
2284
2393
|
}
|
|
@@ -2308,7 +2417,7 @@ var PollarClient = class {
|
|
|
2308
2417
|
* `current` flag identifies which entry corresponds to this client.
|
|
2309
2418
|
*/
|
|
2310
2419
|
async listSessions() {
|
|
2311
|
-
if (!
|
|
2420
|
+
if (!isClientRuntime) {
|
|
2312
2421
|
warnServerSide("listSessions");
|
|
2313
2422
|
return [];
|
|
2314
2423
|
}
|
|
@@ -2327,7 +2436,7 @@ var PollarClient = class {
|
|
|
2327
2436
|
* does NOT clear local state — call `logout()` for that case.
|
|
2328
2437
|
*/
|
|
2329
2438
|
async revokeSession(familyId) {
|
|
2330
|
-
if (!
|
|
2439
|
+
if (!isClientRuntime) {
|
|
2331
2440
|
warnServerSide("revokeSession");
|
|
2332
2441
|
return;
|
|
2333
2442
|
}
|
|
@@ -2825,6 +2934,11 @@ var PollarClient = class {
|
|
|
2825
2934
|
_flowDeps(signal) {
|
|
2826
2935
|
return {
|
|
2827
2936
|
api: this._api,
|
|
2937
|
+
basePath: this.basePath,
|
|
2938
|
+
// SSE status streaming works on web; React Native's `fetch` has no
|
|
2939
|
+
// readable `response.body`, so those clients poll the non-streaming
|
|
2940
|
+
// status endpoint instead. `isBrowser` is false in RN and SSR alike.
|
|
2941
|
+
useStreaming: isBrowser,
|
|
2828
2942
|
signal,
|
|
2829
2943
|
setAuthState: this._setAuthState.bind(this),
|
|
2830
2944
|
storeSession: this._storeSession.bind(this),
|