@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.mjs
CHANGED
|
@@ -1106,6 +1106,26 @@ async function pollRampTransaction(api, txId, { intervalMs = 5e3, timeoutMs = 6e
|
|
|
1106
1106
|
throw new Error("Ramp transaction polling timed out");
|
|
1107
1107
|
}
|
|
1108
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
|
+
|
|
1109
1129
|
// src/dpop.ts
|
|
1110
1130
|
async function buildProof(args, keyManager) {
|
|
1111
1131
|
const jwk = await keyManager.getPublicJwk();
|
|
@@ -1115,7 +1135,7 @@ async function buildProof(args, keyManager) {
|
|
|
1115
1135
|
jwk
|
|
1116
1136
|
};
|
|
1117
1137
|
const payload = {
|
|
1118
|
-
jti:
|
|
1138
|
+
jti: randomUUID(),
|
|
1119
1139
|
htm: args.htm.toUpperCase(),
|
|
1120
1140
|
htu: normalizeHtu(args.htu),
|
|
1121
1141
|
iat: Math.floor(Date.now() / 1e3)
|
|
@@ -1149,24 +1169,6 @@ function normalizeHtu(rawUrl) {
|
|
|
1149
1169
|
const portPart = port ? `:${port}` : "";
|
|
1150
1170
|
return `${scheme}//${host}${portPart}${url.pathname}`;
|
|
1151
1171
|
}
|
|
1152
|
-
function generateJti() {
|
|
1153
|
-
const c = globalThis.crypto;
|
|
1154
|
-
if (c && typeof c.randomUUID === "function") {
|
|
1155
|
-
return c.randomUUID();
|
|
1156
|
-
}
|
|
1157
|
-
if (c && typeof c.getRandomValues === "function") {
|
|
1158
|
-
const bytes = new Uint8Array(16);
|
|
1159
|
-
c.getRandomValues(bytes);
|
|
1160
|
-
bytes[6] = bytes[6] & 15 | 64;
|
|
1161
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
1162
|
-
const hex = [];
|
|
1163
|
-
for (let i = 0; i < 16; i++) hex.push(bytes[i].toString(16).padStart(2, "0"));
|
|
1164
|
-
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("")}`;
|
|
1165
|
-
}
|
|
1166
|
-
throw new Error(
|
|
1167
|
-
"[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."
|
|
1168
|
-
);
|
|
1169
|
-
}
|
|
1170
1172
|
|
|
1171
1173
|
// src/storage/web.ts
|
|
1172
1174
|
var LOG_PREFIX = "[PollarClient:storage]";
|
|
@@ -1309,6 +1311,8 @@ function defaultVisibilityProvider() {
|
|
|
1309
1311
|
// src/types.ts
|
|
1310
1312
|
var AUTH_ERROR_CODES = {
|
|
1311
1313
|
SESSION_CREATE_FAILED: "SESSION_CREATE_FAILED",
|
|
1314
|
+
SESSION_EXPIRED: "SESSION_EXPIRED",
|
|
1315
|
+
SESSION_INVALID: "SESSION_INVALID",
|
|
1312
1316
|
EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED",
|
|
1313
1317
|
EMAIL_VERIFY_FAILED: "EMAIL_VERIFY_FAILED",
|
|
1314
1318
|
EMAIL_CODE_EXPIRED: "EMAIL_CODE_EXPIRED",
|
|
@@ -1622,7 +1626,32 @@ async function readWalletType(storage, apiKeyHash) {
|
|
|
1622
1626
|
return storage.get(walletTypeStorageKey(apiKeyHash));
|
|
1623
1627
|
}
|
|
1624
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
|
+
|
|
1625
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
|
+
}
|
|
1626
1655
|
function abortableDelay(ms, signal) {
|
|
1627
1656
|
return new Promise((resolve, reject) => {
|
|
1628
1657
|
const t = setTimeout(resolve, ms);
|
|
@@ -1630,7 +1659,7 @@ function abortableDelay(ms, signal) {
|
|
|
1630
1659
|
"abort",
|
|
1631
1660
|
() => {
|
|
1632
1661
|
clearTimeout(t);
|
|
1633
|
-
reject(
|
|
1662
|
+
reject(abortError());
|
|
1634
1663
|
},
|
|
1635
1664
|
{ once: true }
|
|
1636
1665
|
);
|
|
@@ -1645,7 +1674,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1645
1674
|
else await new Promise((r) => setTimeout(r, ms));
|
|
1646
1675
|
};
|
|
1647
1676
|
while (true) {
|
|
1648
|
-
|
|
1677
|
+
throwIfAborted(signal);
|
|
1649
1678
|
let data, error;
|
|
1650
1679
|
try {
|
|
1651
1680
|
({ data, error } = await api.GET("/auth/session/status/{clientSessionId}", {
|
|
@@ -1668,7 +1697,7 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1668
1697
|
let sawAnyChunk = false;
|
|
1669
1698
|
try {
|
|
1670
1699
|
while (true) {
|
|
1671
|
-
|
|
1700
|
+
throwIfAborted(signal);
|
|
1672
1701
|
const { done, value } = await reader.read();
|
|
1673
1702
|
if (done) {
|
|
1674
1703
|
streamDone = true;
|
|
@@ -1679,17 +1708,22 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1679
1708
|
for (const message of chunk.split("\n\n").filter(Boolean)) {
|
|
1680
1709
|
const dataLine = message.split("\n").find((l) => l.startsWith("data:"));
|
|
1681
1710
|
if (!dataLine) continue;
|
|
1711
|
+
let parsed;
|
|
1682
1712
|
try {
|
|
1683
|
-
|
|
1684
|
-
if (check(parsed)) {
|
|
1685
|
-
return parsed;
|
|
1686
|
-
}
|
|
1713
|
+
parsed = JSON.parse(dataLine.slice("data:".length).trim());
|
|
1687
1714
|
} catch {
|
|
1715
|
+
continue;
|
|
1716
|
+
}
|
|
1717
|
+
const terminal = terminalStatusCode(parsed);
|
|
1718
|
+
if (terminal) throw new SessionStatusError(terminal);
|
|
1719
|
+
if (check(parsed)) {
|
|
1720
|
+
return parsed;
|
|
1688
1721
|
}
|
|
1689
1722
|
}
|
|
1690
1723
|
}
|
|
1691
1724
|
} catch (e) {
|
|
1692
1725
|
if (e instanceof Error && e.name === "AbortError") throw e;
|
|
1726
|
+
if (e instanceof SessionStatusError) throw e;
|
|
1693
1727
|
console.warn(e);
|
|
1694
1728
|
} finally {
|
|
1695
1729
|
reader.releaseLock();
|
|
@@ -1700,12 +1734,72 @@ async function streamUntilFound(api, clientSessionId, check, retryDelayMs = 200,
|
|
|
1700
1734
|
if (delay) await sleep(delay);
|
|
1701
1735
|
}
|
|
1702
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
|
+
}
|
|
1703
1775
|
|
|
1704
1776
|
// src/client/auth/authenticate.ts
|
|
1705
1777
|
async function authenticate(clientSessionId, deps, expectedWallet) {
|
|
1706
|
-
const { api, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1778
|
+
const { api, basePath, useStreaming, signal, setAuthState, storeSession, clearSession } = deps;
|
|
1707
1779
|
setAuthState({ step: "authenticating" });
|
|
1708
|
-
|
|
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
|
+
}
|
|
1709
1803
|
const dpopJwk = await deps.getPublicJwk();
|
|
1710
1804
|
const { data } = await api.POST("/auth/login", {
|
|
1711
1805
|
body: {
|
|
@@ -1829,26 +1923,36 @@ function severOpener(popup) {
|
|
|
1829
1923
|
} catch {
|
|
1830
1924
|
}
|
|
1831
1925
|
}
|
|
1832
|
-
async
|
|
1833
|
-
const
|
|
1834
|
-
const popup = window.open("about:blank", "_blank");
|
|
1926
|
+
var defaultWebOAuthOpener = async ({ getUrl }) => {
|
|
1927
|
+
const popup = typeof window !== "undefined" ? window.open("about:blank", "_blank") : null;
|
|
1835
1928
|
severOpener(popup);
|
|
1836
|
-
const
|
|
1837
|
-
if (!
|
|
1929
|
+
const url = await getUrl();
|
|
1930
|
+
if (!url) {
|
|
1838
1931
|
popup?.close();
|
|
1839
1932
|
return;
|
|
1840
1933
|
}
|
|
1841
|
-
setAuthState({ step: "opening_oauth", provider });
|
|
1842
|
-
const url = new URL(`${basePath}/auth/${provider}`);
|
|
1843
|
-
url.searchParams.set("api_key", apiKey);
|
|
1844
|
-
url.searchParams.set("client_session_id", clientSessionId);
|
|
1845
|
-
url.searchParams.set("redirect_uri", window.location.origin);
|
|
1846
1934
|
if (popup) {
|
|
1847
|
-
popup.location.href = url
|
|
1935
|
+
popup.location.href = url;
|
|
1848
1936
|
severOpener(popup);
|
|
1849
|
-
} else {
|
|
1850
|
-
window.open(url
|
|
1937
|
+
} else if (typeof window !== "undefined") {
|
|
1938
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1851
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;
|
|
1852
1956
|
await authenticate(clientSessionId, deps);
|
|
1853
1957
|
}
|
|
1854
1958
|
|
|
@@ -1858,10 +1962,10 @@ function withSignal(promise, signal) {
|
|
|
1858
1962
|
promise,
|
|
1859
1963
|
new Promise((_, reject) => {
|
|
1860
1964
|
if (signal.aborted) {
|
|
1861
|
-
reject(
|
|
1965
|
+
reject(abortError());
|
|
1862
1966
|
return;
|
|
1863
1967
|
}
|
|
1864
|
-
signal.addEventListener("abort", () => reject(
|
|
1968
|
+
signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
1865
1969
|
})
|
|
1866
1970
|
]);
|
|
1867
1971
|
}
|
|
@@ -1909,6 +2013,8 @@ async function loginWallet(type, deps) {
|
|
|
1909
2013
|
|
|
1910
2014
|
// src/client/client.ts
|
|
1911
2015
|
var isBrowser = typeof window !== "undefined" && typeof localStorage !== "undefined";
|
|
2016
|
+
var isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
2017
|
+
var isClientRuntime = isBrowser || isReactNative;
|
|
1912
2018
|
var REFRESH_SKEW_SECONDS = 60;
|
|
1913
2019
|
function warnServerSide(method) {
|
|
1914
2020
|
console.warn(
|
|
@@ -1964,7 +2070,7 @@ var PollarClient = class {
|
|
|
1964
2070
|
this._walletAdapter = null;
|
|
1965
2071
|
this._loginController = null;
|
|
1966
2072
|
this.apiKey = config.apiKey;
|
|
1967
|
-
this.id =
|
|
2073
|
+
this.id = randomUUID();
|
|
1968
2074
|
this.basePath = `${config.baseUrl || "https://sdk.api.pollar.xyz"}/v1`;
|
|
1969
2075
|
this._storage = config.storage ?? defaultStorage({
|
|
1970
2076
|
onDegrade: (reason, error) => {
|
|
@@ -1978,10 +2084,12 @@ var PollarClient = class {
|
|
|
1978
2084
|
this._deviceLabel = config.deviceLabel;
|
|
1979
2085
|
this._visibilityProvider = config.visibilityProvider ?? defaultVisibilityProvider();
|
|
1980
2086
|
this._maxIdleMs = config.maxIdleMs;
|
|
2087
|
+
this._openAuthUrl = config.openAuthUrl ?? defaultWebOAuthOpener;
|
|
2088
|
+
this._oauthRedirectUri = config.oauthRedirectUri ?? (isBrowser ? window.location.origin : "");
|
|
1981
2089
|
this._api = createApiClient(this.basePath);
|
|
1982
2090
|
this._wireMiddlewares();
|
|
1983
2091
|
this._networkState = { step: "connected", network: config.stellarNetwork ?? "testnet" };
|
|
1984
|
-
if (!
|
|
2092
|
+
if (!isClientRuntime) {
|
|
1985
2093
|
warnServerSide("constructor");
|
|
1986
2094
|
this._initialized = Promise.resolve();
|
|
1987
2095
|
return;
|
|
@@ -2007,7 +2115,7 @@ var PollarClient = class {
|
|
|
2007
2115
|
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
2008
2116
|
async _initialize() {
|
|
2009
2117
|
this._apiKeyHash = await hashApiKey(this.apiKey);
|
|
2010
|
-
if (
|
|
2118
|
+
if (isBrowser) {
|
|
2011
2119
|
const sessionKey = sessionStorageKey(this._apiKeyHash);
|
|
2012
2120
|
const handler = (e) => {
|
|
2013
2121
|
if (e.key === sessionKey) {
|
|
@@ -2029,7 +2137,7 @@ var PollarClient = class {
|
|
|
2029
2137
|
}
|
|
2030
2138
|
/** Detach the cross-tab storage listener and abort any in-flight login. */
|
|
2031
2139
|
destroy() {
|
|
2032
|
-
if (this._storageEventHandler &&
|
|
2140
|
+
if (this._storageEventHandler && isBrowser) {
|
|
2033
2141
|
window.removeEventListener("storage", this._storageEventHandler);
|
|
2034
2142
|
this._storageEventHandler = null;
|
|
2035
2143
|
}
|
|
@@ -2312,7 +2420,7 @@ var PollarClient = class {
|
|
|
2312
2420
|
}
|
|
2313
2421
|
// ─── Login (unified entry point) ─────────────────────────────────────────
|
|
2314
2422
|
login(options) {
|
|
2315
|
-
if (!
|
|
2423
|
+
if (!isClientRuntime) {
|
|
2316
2424
|
warnServerSide("login");
|
|
2317
2425
|
return;
|
|
2318
2426
|
}
|
|
@@ -2323,7 +2431,9 @@ var PollarClient = class {
|
|
|
2323
2431
|
loginOAuth(options.provider, {
|
|
2324
2432
|
...deps,
|
|
2325
2433
|
basePath: this.basePath,
|
|
2326
|
-
apiKey: this.apiKey
|
|
2434
|
+
apiKey: this.apiKey,
|
|
2435
|
+
openAuthUrl: this._openAuthUrl,
|
|
2436
|
+
redirectUri: this._oauthRedirectUri
|
|
2327
2437
|
}).catch((err) => this._handleFlowError(err));
|
|
2328
2438
|
} else if (options.provider === "email") {
|
|
2329
2439
|
const { email } = options;
|
|
@@ -2339,7 +2449,7 @@ var PollarClient = class {
|
|
|
2339
2449
|
}
|
|
2340
2450
|
// ─── Email OTP flow (3 steps) ─────────────────────────────────────────────
|
|
2341
2451
|
beginEmailLogin() {
|
|
2342
|
-
if (!
|
|
2452
|
+
if (!isClientRuntime) {
|
|
2343
2453
|
warnServerSide("beginEmailLogin");
|
|
2344
2454
|
return;
|
|
2345
2455
|
}
|
|
@@ -2347,7 +2457,7 @@ var PollarClient = class {
|
|
|
2347
2457
|
initEmailSession(this._flowDeps(controller.signal)).catch((err) => this._handleFlowError(err));
|
|
2348
2458
|
}
|
|
2349
2459
|
sendEmailCode(email) {
|
|
2350
|
-
if (!
|
|
2460
|
+
if (!isClientRuntime) {
|
|
2351
2461
|
warnServerSide("sendEmailCode");
|
|
2352
2462
|
return;
|
|
2353
2463
|
}
|
|
@@ -2359,7 +2469,7 @@ var PollarClient = class {
|
|
|
2359
2469
|
sendEmailCode(email, clientSessionId, this._flowDeps(signal)).catch((err) => this._handleFlowError(err));
|
|
2360
2470
|
}
|
|
2361
2471
|
verifyEmailCode(code) {
|
|
2362
|
-
if (!
|
|
2472
|
+
if (!isClientRuntime) {
|
|
2363
2473
|
warnServerSide("verifyEmailCode");
|
|
2364
2474
|
return;
|
|
2365
2475
|
}
|
|
@@ -2377,7 +2487,7 @@ var PollarClient = class {
|
|
|
2377
2487
|
}
|
|
2378
2488
|
// ─── Wallet flow (single call) ────────────────────────────────────────────
|
|
2379
2489
|
loginWallet(type) {
|
|
2380
|
-
if (!
|
|
2490
|
+
if (!isClientRuntime) {
|
|
2381
2491
|
warnServerSide("loginWallet");
|
|
2382
2492
|
return;
|
|
2383
2493
|
}
|
|
@@ -2403,7 +2513,7 @@ var PollarClient = class {
|
|
|
2403
2513
|
* across all devices.
|
|
2404
2514
|
*/
|
|
2405
2515
|
async logout(options = {}) {
|
|
2406
|
-
if (!
|
|
2516
|
+
if (!isClientRuntime) {
|
|
2407
2517
|
warnServerSide("logout");
|
|
2408
2518
|
return;
|
|
2409
2519
|
}
|
|
@@ -2433,7 +2543,7 @@ var PollarClient = class {
|
|
|
2433
2543
|
* `current` flag identifies which entry corresponds to this client.
|
|
2434
2544
|
*/
|
|
2435
2545
|
async listSessions() {
|
|
2436
|
-
if (!
|
|
2546
|
+
if (!isClientRuntime) {
|
|
2437
2547
|
warnServerSide("listSessions");
|
|
2438
2548
|
return [];
|
|
2439
2549
|
}
|
|
@@ -2452,7 +2562,7 @@ var PollarClient = class {
|
|
|
2452
2562
|
* does NOT clear local state — call `logout()` for that case.
|
|
2453
2563
|
*/
|
|
2454
2564
|
async revokeSession(familyId) {
|
|
2455
|
-
if (!
|
|
2565
|
+
if (!isClientRuntime) {
|
|
2456
2566
|
warnServerSide("revokeSession");
|
|
2457
2567
|
return;
|
|
2458
2568
|
}
|
|
@@ -2950,6 +3060,11 @@ var PollarClient = class {
|
|
|
2950
3060
|
_flowDeps(signal) {
|
|
2951
3061
|
return {
|
|
2952
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,
|
|
2953
3068
|
signal,
|
|
2954
3069
|
setAuthState: this._setAuthState.bind(this),
|
|
2955
3070
|
storeSession: this._storeSession.bind(this),
|