@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 CHANGED
@@ -27,11 +27,37 @@ yarn add @pollar/core
27
27
  For React Native / Expo, also install one of the storage adapter peer deps:
28
28
 
29
29
  ```bash
30
- # Expo
30
+ # Expo (react-native-quick-crypto is a native module → requires a dev build, not Expo Go)
31
31
  npx expo install expo-secure-store react-native-get-random-values
32
+ npm i react-native-quick-crypto react-native-polyfill-globals
32
33
 
33
34
  # Bare React Native
34
- npm i react-native-keychain react-native-get-random-values
35
+ npm i react-native-keychain react-native-get-random-values react-native-quick-crypto react-native-polyfill-globals
36
+ ```
37
+
38
+ > **React Native runtime requirements.** The SDK builds a DPoP proof (RFC 9449) for **every** authenticated request.
39
+ > That path uses four standard Web primitives that React Native / Hermes does **not** all ship by default. Register
40
+ > them at the very top of your entry file, **before** any `@pollar/core` import. If any is missing, DPoP proof
41
+ > construction fails and **no authenticated request works** — the SDK is not at fault, the runtime is.
42
+ >
43
+ > | Primitive | Used by | Polyfill |
44
+ > | --- | --- | --- |
45
+ > | `crypto.getRandomValues` | keypair generation (`NobleKeyManager`), DPoP `jti` | [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values) |
46
+ > | `crypto.subtle.digest('SHA-256')` | `sha256` → API-key namespace, DPoP `ath`, `NobleKeyManager.sign()` | [`react-native-quick-crypto`](https://github.com/margelo/react-native-quick-crypto) ≥ 0.7 (native module → Expo **dev build**, not Expo Go) |
47
+ > | `TextEncoder` / `TextDecoder` | DPoP proof encoding, base64url, JWK thumbprint | bundled in [`react-native-polyfill-globals`](https://github.com/acostalima/react-native-polyfill-globals) (or `text-encoding`) |
48
+ > | `URL` (spec-compliant) | DPoP `htu` normalization (`new URL(request.url)` on every proof) | bundled in `react-native-polyfill-globals` (or [`react-native-url-polyfill`](https://github.com/charpeni/react-native-url-polyfill)) |
49
+ >
50
+ > `react-native-polyfill-globals/auto` is the pragmatic one-liner — it installs `TextEncoder`/`TextDecoder` **and**
51
+ > `URL` together (plus base64 / fetch-streaming you don't strictly need). The SDK does **not** rely on `fetch` response
52
+ > streaming on React Native: it polls the non-streaming `/auth/session/status/{id}/poll` endpoint instead, so you do
53
+ > **not** need a fetch-streaming polyfill for auth — but you still need TextEncoder + URL from that same package.
54
+
55
+ Entry-file setup (e.g. `index.js`), **before importing `@pollar/core`**:
56
+
57
+ ```ts
58
+ import 'react-native-get-random-values'; // crypto.getRandomValues
59
+ import 'react-native-polyfill-globals/auto'; // TextEncoder/TextDecoder + URL
60
+ import 'react-native-quick-crypto'; // crypto.subtle.digest — register its global per the package's setup docs
35
61
  ```
36
62
 
37
63
  ## Overview
@@ -59,8 +85,10 @@ const client = new PollarClient({ apiKey: 'your-api-key' });
59
85
  ## React Native (Expo)
60
86
 
61
87
  ```ts
62
- // At your app entry — `crypto.getRandomValues` polyfill
63
- import 'react-native-get-random-values';
88
+ // At your app entry, BEFORE importing @pollar/core runtime polyfills (see table above):
89
+ import 'react-native-get-random-values'; // crypto.getRandomValues
90
+ import 'react-native-polyfill-globals/auto'; // TextEncoder/TextDecoder + URL
91
+ import 'react-native-quick-crypto'; // crypto.subtle.digest — register its global per the package's setup docs
64
92
 
65
93
  import { PollarClient } from '@pollar/core';
66
94
  import { createSecureStoreAdapter } from '@pollar/core/adapters/expo';
@@ -78,7 +106,9 @@ const client = new PollarClient({ apiKey: 'your-api-key', storage });
78
106
  ## React Native (`react-native-keychain`)
79
107
 
80
108
  ```ts
81
- import 'react-native-get-random-values';
109
+ import 'react-native-get-random-values'; // crypto.getRandomValues
110
+ import 'react-native-polyfill-globals/auto'; // TextEncoder/TextDecoder + URL
111
+ import 'react-native-quick-crypto'; // crypto.subtle.digest — register its global per the package's setup docs
82
112
  import { PollarClient } from '@pollar/core';
83
113
  import { createKeychainAdapter } from '@pollar/core/adapters/react-native-keychain';
84
114
 
@@ -86,6 +116,87 @@ const storage = await createKeychainAdapter();
86
116
  const client = new PollarClient({ apiKey: 'your-api-key', storage });
87
117
  ```
88
118
 
119
+ ## Framework integration
120
+
121
+ `@pollar/core` is framework-agnostic: `PollarClient` is a plain class and the `on*StateChange` methods are
122
+ callback subscriptions. To render reactively, bridge those callbacks into your framework's state primitive. The
123
+ client instance should be a singleton (module scope, context, or DI) — never recreate it on every render.
124
+
125
+ ### React / Next.js
126
+
127
+ `useSyncExternalStore` is the idiomatic bridge. In Next.js, only instantiate in Client Components (`'use client'`)
128
+ — server-side, the SDK degrades to a no-op and warns.
129
+
130
+ ```tsx
131
+ 'use client';
132
+ import { useSyncExternalStore } from 'react';
133
+ import { PollarClient, type AuthState } from '@pollar/core';
134
+
135
+ const client = new PollarClient({ apiKey: 'pk_...' }); // module scope = one instance
136
+
137
+ export function useAuthState(): AuthState {
138
+ return useSyncExternalStore(
139
+ (cb) => client.onAuthStateChange(cb), // returns the unsubscribe fn
140
+ () => client.getAuthState(), // client snapshot
141
+ () => client.getAuthState(), // server snapshot (idle)
142
+ );
143
+ }
144
+
145
+ // const auth = useAuthState(); // re-renders on every auth transition
146
+ ```
147
+
148
+ ### Angular
149
+
150
+ The SDK's callbacks fire **outside Angular's zone**, so wrap state updates in `NgZone.run()` (or use signals) or the
151
+ view won't update. Expose the client through a service.
152
+
153
+ ```ts
154
+ import { Injectable, NgZone, signal } from '@angular/core';
155
+ import { PollarClient, type AuthState } from '@pollar/core';
156
+
157
+ @Injectable({ providedIn: 'root' })
158
+ export class PollarService {
159
+ private client = new PollarClient({ apiKey: 'pk_...' });
160
+ readonly authState = signal<AuthState>(this.client.getAuthState());
161
+
162
+ constructor(private zone: NgZone) {
163
+ this.client.onAuthStateChange((state) => {
164
+ this.zone.run(() => this.authState.set(state)); // re-enter Angular's zone
165
+ });
166
+ }
167
+
168
+ login = (email: string) => this.client.login({ provider: 'email', email });
169
+ }
170
+ ```
171
+
172
+ ### Vue 3
173
+
174
+ Assign the callback payload into a `ref` (or `shallowRef`) inside `onMounted`; unsubscribe in `onUnmounted`.
175
+
176
+ ```ts
177
+ import { ref, shallowRef, onMounted, onUnmounted } from 'vue';
178
+ import { PollarClient, type AuthState } from '@pollar/core';
179
+
180
+ const client = new PollarClient({ apiKey: 'pk_...' });
181
+
182
+ export function useAuth() {
183
+ const authState = shallowRef<AuthState>(client.getAuthState());
184
+ let unsub = () => {
185
+ };
186
+ onMounted(() => {
187
+ unsub = client.onAuthStateChange((s) => (authState.value = s)); // ref assign = reactive
188
+ });
189
+ onUnmounted(() => unsub());
190
+ return { authState, login: client.login.bind(client) };
191
+ }
192
+ ```
193
+
194
+ ### React Native
195
+
196
+ Same as React (`useSyncExternalStore`), plus the entry-file polyfills and injected adapters shown in the
197
+ React Native sections above. OAuth and external-wallet logins require `openAuthUrl` / `walletAdapter` to be injected
198
+ (the built-in popup/extension adapters are web-only).
199
+
89
200
  ## Preserved-on-disk storage shape
90
201
 
91
202
  0.7.0 persists exactly:
@@ -139,7 +250,7 @@ const sessions = await client.listSessions();
139
250
  ### `new PollarClient(config)`
140
251
 
141
252
  | Option | Type | Required | Description |
142
- | ------------------ | ------------------------ | -------- | ----------------------------------------------------------------------------------------------------------- |
253
+ |--------------------|--------------------------|----------|-------------------------------------------------------------------------------------------------------------|
143
254
  | `apiKey` | `string` | Yes | Your Pollar API key |
144
255
  | `baseUrl` | `string` | No | Override the default API endpoint |
145
256
  | `stellarNetwork` | `'mainnet' \| 'testnet'` | No | Target Stellar network (default: `testnet`) |
@@ -167,6 +278,7 @@ client.login({ provider: 'email', email: 'user@example.com' });
167
278
 
168
279
  // Stellar wallet
169
280
  import { WalletType } from '@pollar/core';
281
+
170
282
  client.login({ provider: 'wallet', type: WalletType.FREIGHTER });
171
283
  client.login({ provider: 'wallet', type: WalletType.ALBEDO });
172
284
  ```
@@ -0,0 +1,10 @@
1
+ import { V as VisibilityProvider } from '../types-84G_htcn.mjs';
2
+
3
+ /**
4
+ * Create a `VisibilityProvider` backed by React Native's `AppState`.
5
+ *
6
+ * Throws (via the returned Promise) if `react-native` cannot be loaded.
7
+ */
8
+ declare function createAppStateVisibilityProvider(): Promise<VisibilityProvider>;
9
+
10
+ export { createAppStateVisibilityProvider };
@@ -0,0 +1,10 @@
1
+ import { V as VisibilityProvider } from '../types-84G_htcn.js';
2
+
3
+ /**
4
+ * Create a `VisibilityProvider` backed by React Native's `AppState`.
5
+ *
6
+ * Throws (via the returned Promise) if `react-native` cannot be loaded.
7
+ */
8
+ declare function createAppStateVisibilityProvider(): Promise<VisibilityProvider>;
9
+
10
+ export { createAppStateVisibilityProvider };
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ // src/adapters/react-native-appstate.ts
4
+ async function loadAppState() {
5
+ try {
6
+ const mod = await import('react-native');
7
+ const AppState = mod.AppState ?? mod.default?.AppState;
8
+ if (!AppState) {
9
+ throw new Error("'react-native' loaded but exposes no AppState export");
10
+ }
11
+ return AppState;
12
+ } catch (error) {
13
+ const message = `[PollarClient:visibility] Failed to load 'react-native' AppState. This adapter only runs inside a React Native app. Original error: ${error instanceof Error ? error.message : String(error)}`;
14
+ throw new Error(message);
15
+ }
16
+ }
17
+ async function createAppStateVisibilityProvider() {
18
+ const AppState = await loadAppState();
19
+ const isActive = (state) => state === "active";
20
+ return {
21
+ isVisible: () => isActive(AppState.currentState),
22
+ onChange: (cb) => {
23
+ let last = isActive(AppState.currentState);
24
+ const subscription = AppState.addEventListener("change", (state) => {
25
+ const next = isActive(state);
26
+ if (next !== last) {
27
+ last = next;
28
+ cb(next);
29
+ }
30
+ });
31
+ return () => subscription.remove();
32
+ }
33
+ };
34
+ }
35
+
36
+ exports.createAppStateVisibilityProvider = createAppStateVisibilityProvider;
37
+ //# sourceMappingURL=react-native-appstate.js.map
38
+ //# sourceMappingURL=react-native-appstate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/react-native-appstate.ts"],"names":[],"mappings":";;;AA8BA,eAAe,YAAA,GAAqC;AAClD,EAAA,IAAI;AAGF,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,cAAc,CAAA;AACvC,IAAA,MAAM,QAAA,GAAY,GAAA,CAAmC,QAAA,IAAa,GAAA,CAAiD,OAAA,EAAS,QAAA;AAC5H,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,IACxE;AACA,IAAA,OAAO,QAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,OAAA,GACJ,uIAEmB,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAC3E,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAOA,eAAsB,gCAAA,GAAgE;AACpF,EAAA,MAAM,QAAA,GAAW,MAAM,YAAA,EAAa;AAEpC,EAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAA2B,KAAA,KAAU,QAAA;AAEvD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,MAAM,QAAA,CAAS,QAAA,CAAS,YAAY,CAAA;AAAA,IAC/C,QAAA,EAAU,CAAC,EAAA,KAAO;AAIhB,MAAA,IAAI,IAAA,GAAO,QAAA,CAAS,QAAA,CAAS,YAAY,CAAA;AACzC,MAAA,MAAM,YAAA,GAAe,QAAA,CAAS,gBAAA,CAAiB,QAAA,EAAU,CAAC,KAAA,KAAU;AAClE,QAAA,MAAM,IAAA,GAAO,SAAS,KAAK,CAAA;AAC3B,QAAA,IAAI,SAAS,IAAA,EAAM;AACjB,UAAA,IAAA,GAAO,IAAA;AACP,UAAA,EAAA,CAAG,IAAI,CAAA;AAAA,QACT;AAAA,MACF,CAAC,CAAA;AACD,MAAA,OAAO,MAAM,aAAa,MAAA,EAAO;AAAA,IACnC;AAAA,GACF;AACF","file":"react-native-appstate.js","sourcesContent":["import type { VisibilityProvider } from '../visibility/types';\n\n/**\n * `AppState`-backed {@link VisibilityProvider} for React Native.\n *\n * Wire it into the silent-refresh scheduler so proactive token renewals are\n * skipped while the app is backgrounded and run the moment it returns to the\n * foreground — matching the web `visibilitychange` behavior and sidestepping\n * RN's aggressive background timer throttling.\n *\n * `react-native` is the consumer's framework (not a dependency of this SDK),\n * so the module is loaded lazily via dynamic `import('react-native')`. That\n * keeps web/Node bundles from ever resolving it. Because loading is async, the\n * factory is async too — mirror the `createSecureStoreAdapter` usage:\n *\n * import { createAppStateVisibilityProvider } from '@pollar/core/adapters/react-native-appstate';\n * const visibilityProvider = await createAppStateVisibilityProvider();\n * new PollarClient({ apiKey, storage, visibilityProvider });\n */\n\n/**\n * Minimal structural type for the slice of `react-native`'s `AppState` we use.\n * Typed here instead of importing the package's types because `react-native`\n * is an optional peer the SDK is not type-checked against.\n */\ntype AppStateApi = {\n currentState: string;\n addEventListener: (type: 'change', handler: (state: string) => void) => { remove: () => void };\n};\n\nasync function loadAppState(): Promise<AppStateApi> {\n try {\n // @ts-expect-error -- optional peer dep; resolved at runtime in RN apps,\n // absent when the SDK is built or run on web/Node.\n const mod = await import('react-native');\n const AppState = (mod as { AppState?: AppStateApi }).AppState ?? (mod as { default?: { AppState?: AppStateApi } }).default?.AppState;\n if (!AppState) {\n throw new Error(\"'react-native' loaded but exposes no AppState export\");\n }\n return AppState;\n } catch (error) {\n const message =\n `[PollarClient:visibility] Failed to load 'react-native' AppState. ` +\n `This adapter only runs inside a React Native app. ` +\n `Original error: ${error instanceof Error ? error.message : String(error)}`;\n throw new Error(message);\n }\n}\n\n/**\n * Create a `VisibilityProvider` backed by React Native's `AppState`.\n *\n * Throws (via the returned Promise) if `react-native` cannot be loaded.\n */\nexport async function createAppStateVisibilityProvider(): Promise<VisibilityProvider> {\n const AppState = await loadAppState();\n\n const isActive = (state: string): boolean => state === 'active';\n\n return {\n isVisible: () => isActive(AppState.currentState),\n onChange: (cb) => {\n // Filter duplicate notifications — listeners only see real transitions,\n // matching the web provider's contract. RN also emits 'inactive'\n // (iOS transition state) which we collapse into \"not visible\".\n let last = isActive(AppState.currentState);\n const subscription = AppState.addEventListener('change', (state) => {\n const next = isActive(state);\n if (next !== last) {\n last = next;\n cb(next);\n }\n });\n return () => subscription.remove();\n },\n };\n}\n"]}
@@ -0,0 +1,36 @@
1
+ // src/adapters/react-native-appstate.ts
2
+ async function loadAppState() {
3
+ try {
4
+ const mod = await import('react-native');
5
+ const AppState = mod.AppState ?? mod.default?.AppState;
6
+ if (!AppState) {
7
+ throw new Error("'react-native' loaded but exposes no AppState export");
8
+ }
9
+ return AppState;
10
+ } catch (error) {
11
+ const message = `[PollarClient:visibility] Failed to load 'react-native' AppState. This adapter only runs inside a React Native app. Original error: ${error instanceof Error ? error.message : String(error)}`;
12
+ throw new Error(message);
13
+ }
14
+ }
15
+ async function createAppStateVisibilityProvider() {
16
+ const AppState = await loadAppState();
17
+ const isActive = (state) => state === "active";
18
+ return {
19
+ isVisible: () => isActive(AppState.currentState),
20
+ onChange: (cb) => {
21
+ let last = isActive(AppState.currentState);
22
+ const subscription = AppState.addEventListener("change", (state) => {
23
+ const next = isActive(state);
24
+ if (next !== last) {
25
+ last = next;
26
+ cb(next);
27
+ }
28
+ });
29
+ return () => subscription.remove();
30
+ }
31
+ };
32
+ }
33
+
34
+ export { createAppStateVisibilityProvider };
35
+ //# sourceMappingURL=react-native-appstate.mjs.map
36
+ //# sourceMappingURL=react-native-appstate.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/react-native-appstate.ts"],"names":[],"mappings":";AA8BA,eAAe,YAAA,GAAqC;AAClD,EAAA,IAAI;AAGF,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,cAAc,CAAA;AACvC,IAAA,MAAM,QAAA,GAAY,GAAA,CAAmC,QAAA,IAAa,GAAA,CAAiD,OAAA,EAAS,QAAA;AAC5H,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,MAAM,sDAAsD,CAAA;AAAA,IACxE;AACA,IAAA,OAAO,QAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,OAAA,GACJ,uIAEmB,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAC3E,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAOA,eAAsB,gCAAA,GAAgE;AACpF,EAAA,MAAM,QAAA,GAAW,MAAM,YAAA,EAAa;AAEpC,EAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAA2B,KAAA,KAAU,QAAA;AAEvD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,MAAM,QAAA,CAAS,QAAA,CAAS,YAAY,CAAA;AAAA,IAC/C,QAAA,EAAU,CAAC,EAAA,KAAO;AAIhB,MAAA,IAAI,IAAA,GAAO,QAAA,CAAS,QAAA,CAAS,YAAY,CAAA;AACzC,MAAA,MAAM,YAAA,GAAe,QAAA,CAAS,gBAAA,CAAiB,QAAA,EAAU,CAAC,KAAA,KAAU;AAClE,QAAA,MAAM,IAAA,GAAO,SAAS,KAAK,CAAA;AAC3B,QAAA,IAAI,SAAS,IAAA,EAAM;AACjB,UAAA,IAAA,GAAO,IAAA;AACP,UAAA,EAAA,CAAG,IAAI,CAAA;AAAA,QACT;AAAA,MACF,CAAC,CAAA;AACD,MAAA,OAAO,MAAM,aAAa,MAAA,EAAO;AAAA,IACnC;AAAA,GACF;AACF","file":"react-native-appstate.mjs","sourcesContent":["import type { VisibilityProvider } from '../visibility/types';\n\n/**\n * `AppState`-backed {@link VisibilityProvider} for React Native.\n *\n * Wire it into the silent-refresh scheduler so proactive token renewals are\n * skipped while the app is backgrounded and run the moment it returns to the\n * foreground — matching the web `visibilitychange` behavior and sidestepping\n * RN's aggressive background timer throttling.\n *\n * `react-native` is the consumer's framework (not a dependency of this SDK),\n * so the module is loaded lazily via dynamic `import('react-native')`. That\n * keeps web/Node bundles from ever resolving it. Because loading is async, the\n * factory is async too — mirror the `createSecureStoreAdapter` usage:\n *\n * import { createAppStateVisibilityProvider } from '@pollar/core/adapters/react-native-appstate';\n * const visibilityProvider = await createAppStateVisibilityProvider();\n * new PollarClient({ apiKey, storage, visibilityProvider });\n */\n\n/**\n * Minimal structural type for the slice of `react-native`'s `AppState` we use.\n * Typed here instead of importing the package's types because `react-native`\n * is an optional peer the SDK is not type-checked against.\n */\ntype AppStateApi = {\n currentState: string;\n addEventListener: (type: 'change', handler: (state: string) => void) => { remove: () => void };\n};\n\nasync function loadAppState(): Promise<AppStateApi> {\n try {\n // @ts-expect-error -- optional peer dep; resolved at runtime in RN apps,\n // absent when the SDK is built or run on web/Node.\n const mod = await import('react-native');\n const AppState = (mod as { AppState?: AppStateApi }).AppState ?? (mod as { default?: { AppState?: AppStateApi } }).default?.AppState;\n if (!AppState) {\n throw new Error(\"'react-native' loaded but exposes no AppState export\");\n }\n return AppState;\n } catch (error) {\n const message =\n `[PollarClient:visibility] Failed to load 'react-native' AppState. ` +\n `This adapter only runs inside a React Native app. ` +\n `Original error: ${error instanceof Error ? error.message : String(error)}`;\n throw new Error(message);\n }\n}\n\n/**\n * Create a `VisibilityProvider` backed by React Native's `AppState`.\n *\n * Throws (via the returned Promise) if `react-native` cannot be loaded.\n */\nexport async function createAppStateVisibilityProvider(): Promise<VisibilityProvider> {\n const AppState = await loadAppState();\n\n const isActive = (state: string): boolean => state === 'active';\n\n return {\n isVisible: () => isActive(AppState.currentState),\n onChange: (cb) => {\n // Filter duplicate notifications — listeners only see real transitions,\n // matching the web provider's contract. RN also emits 'inactive'\n // (iOS transition state) which we collapse into \"not visible\".\n let last = isActive(AppState.currentState);\n const subscription = AppState.addEventListener('change', (state) => {\n const next = isActive(state);\n if (next !== last) {\n last = next;\n cb(next);\n }\n });\n return () => subscription.remove();\n },\n };\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { S as Storage, O as OnStorageDegrade } from './types-DqgJIJBl.mjs';
2
2
  export { a as StorageDegradeReason } from './types-DqgJIJBl.mjs';
3
+ import { V as VisibilityProvider } from './types-84G_htcn.mjs';
3
4
  import * as openapi_fetch from 'openapi-fetch';
4
5
 
5
6
  type StellarNetwork = 'mainnet' | 'testnet';
@@ -75,43 +76,6 @@ interface KeyManager {
75
76
  sign(payload: Uint8Array): Promise<Uint8Array>;
76
77
  }
77
78
 
78
- /**
79
- * Pluggable "is the user looking at this app right now?" signal.
80
- *
81
- * Used by the silent-refresh scheduler so token renewals are skipped while
82
- * the tab is hidden / the app is backgrounded — both saves network and
83
- * works around aggressive `setTimeout` throttling that web browsers and RN
84
- * apply to non-foreground contexts.
85
- *
86
- * Default web implementation listens to `visibilitychange` plus
87
- * `pageshow`/`pagehide` (covers BFCache on iOS) and `focus`/`blur` (covers
88
- * the cases where `visibilitychange` lags). Default for non-browser
89
- * environments is a noop that always reports "visible".
90
- *
91
- * TODO(@pollar/react-native): when the dedicated RN package ships, it will
92
- * export an `AppState`-backed provider. Until then, RN consumers can wire
93
- * one inline:
94
- *
95
- * import { AppState } from 'react-native';
96
- * const rnVisibility = {
97
- * isVisible: () => AppState.currentState === 'active',
98
- * onChange: (cb) => {
99
- * const sub = AppState.addEventListener('change', (s) => cb(s === 'active'));
100
- * return () => sub.remove();
101
- * },
102
- * };
103
- * new PollarClient({ apiKey, visibilityProvider: rnVisibility });
104
- */
105
- interface VisibilityProvider {
106
- isVisible(): boolean;
107
- /**
108
- * Subscribe to visibility transitions. The callback receives the new
109
- * visibility state (`true` = visible). Returns an unsubscribe function
110
- * that must detach every listener registered by this call.
111
- */
112
- onChange(cb: (visible: boolean) => void): () => void;
113
- }
114
-
115
79
  declare enum WalletType {
116
80
  FREIGHTER = "freighter",
117
81
  ALBEDO = "albedo"
@@ -290,6 +254,47 @@ interface PollarClientConfig {
290
254
  * `undefined` = refresh forever as long as the app is visible.
291
255
  */
292
256
  maxIdleMs?: number;
257
+ /**
258
+ * Strategy for opening the hosted OAuth URL during
259
+ * `login({ provider: 'google' | 'github' })`. Defaults to a browser popup
260
+ * on web. React Native consumers MUST provide one (typically wrapping
261
+ * `expo-web-browser`'s `openAuthSessionAsync`), since `window.open` does
262
+ * not exist there. The SDK still drives the rest of the flow by polling the
263
+ * auth-session status, so the opener only needs to surface the URL — it does
264
+ * NOT need to capture the redirect payload.
265
+ */
266
+ openAuthUrl?: AuthUrlOpener;
267
+ /**
268
+ * Value sent to the backend as `redirect_uri` for hosted OAuth (where the
269
+ * provider returns the user afterwards). Defaults to `window.location.origin`
270
+ * on web. On React Native set this to your app's deep link / scheme — the
271
+ * same URL you pass to `WebBrowser.openAuthSessionAsync`.
272
+ */
273
+ oauthRedirectUri?: string;
274
+ }
275
+ /**
276
+ * Strategy for opening the hosted OAuth URL. The SDK mints the per-login auth
277
+ * session lazily inside `getUrl()` (call it once; the first call creates the
278
+ * `clientSessionId` and returns the full URL, or `null` if session creation
279
+ * failed). Open the resolved URL however the platform allows — a popup on web,
280
+ * `WebBrowser.openAuthSessionAsync(url, redirectUri)` on React Native — and
281
+ * resolve once the user-facing browser step is done or dismissed. You do NOT
282
+ * need to capture the redirect payload: the SDK polls the auth-session status
283
+ * until the backend marks it READY.
284
+ */
285
+ type AuthUrlOpener = (ctx: AuthOpenContext) => void | Promise<void>;
286
+ interface AuthOpenContext {
287
+ provider: 'google' | 'github';
288
+ /**
289
+ * Mints the auth session (once) and returns the full hosted-OAuth URL, or
290
+ * `null` if session creation failed. On web, call it AFTER reserving the
291
+ * popup window so popup blockers (which only honor `window.open` inside the
292
+ * original user-gesture tick) don't swallow it.
293
+ */
294
+ getUrl: () => Promise<string | null>;
295
+ /** The redirect target passed to the backend as `redirect_uri`. */
296
+ redirectUri: string;
297
+ signal: AbortSignal;
293
298
  }
294
299
  /**
295
300
  * One row in the active-sessions list (returned by `PollarClient.listSessions()`).
@@ -436,6 +441,8 @@ type SubmitOutcome = {
436
441
  };
437
442
  declare const AUTH_ERROR_CODES: {
438
443
  readonly SESSION_CREATE_FAILED: "SESSION_CREATE_FAILED";
444
+ readonly SESSION_EXPIRED: "SESSION_EXPIRED";
445
+ readonly SESSION_INVALID: "SESSION_INVALID";
439
446
  readonly EMAIL_SEND_FAILED: "EMAIL_SEND_FAILED";
440
447
  readonly EMAIL_VERIFY_FAILED: "EMAIL_VERIFY_FAILED";
441
448
  readonly EMAIL_CODE_EXPIRED: "EMAIL_CODE_EXPIRED";
@@ -637,6 +644,10 @@ declare class PollarClient {
637
644
  private readonly _walletAdapterResolver;
638
645
  private readonly _walletResolverTimeoutMs;
639
646
  private _loginController;
647
+ /** Platform strategy for opening the hosted-OAuth URL (popup on web; injected on RN). */
648
+ private readonly _openAuthUrl;
649
+ /** `redirect_uri` sent to the backend for hosted OAuth. */
650
+ private readonly _oauthRedirectUri;
640
651
  constructor(config: PollarClientConfig);
641
652
  /** Awaitable handle for the initial keypair + session restore. */
642
653
  ready(): Promise<void>;
@@ -1123,6 +1134,26 @@ interface paths {
1123
1134
  patch?: never;
1124
1135
  trace?: never;
1125
1136
  };
1137
+ "/auth/session/status/{clientSessionId}/poll": {
1138
+ parameters: {
1139
+ query?: never;
1140
+ header?: never;
1141
+ path?: never;
1142
+ cookie?: never;
1143
+ };
1144
+ /**
1145
+ * Poll client session status (non-streaming)
1146
+ * @description One-shot JSON variant of the SSE status stream, for clients without fetch response-body streaming (React Native). Returns the current `{status, user.ready}` immediately. Poll until `status` reaches a ready/consumed state.
1147
+ */
1148
+ get: operations["getAuthSessionStatusByClientSessionIdPoll"];
1149
+ put?: never;
1150
+ post?: never;
1151
+ delete?: never;
1152
+ options?: never;
1153
+ head?: never;
1154
+ patch?: never;
1155
+ trace?: never;
1156
+ };
1126
1157
  "/auth/google": {
1127
1158
  parameters: {
1128
1159
  query?: never;
@@ -1442,7 +1473,7 @@ interface paths {
1442
1473
  put?: never;
1443
1474
  /**
1444
1475
  * Submit a pre-signed XDR
1445
- * @description Submit step of the split build/sign/submit flow. Accepts a signed XDR produced by /tx/sign or by an external-wallet adapter. Goes through wallet-service /v1/tx/submit so the submission is policy-validated and idempotency-tracked.
1476
+ * @description Submit step of the split build/sign/submit flow. Accepts a signed XDR produced by /tx/sign or signed client-side by an external wallet (Freighter/Albedo/SWK). Routing is custody-aware: EXTERNAL (user-controlled) wallets and adapter-signed wallets are broadcast directly via Soroban RPC, since wallet-service holds no record of them; custodial wallets go through wallet-service /v1/tx/submit so the submission is policy-validated and idempotency-tracked. The EXTERNAL signal is per-user, so apps mixing social login and wallet login submit each user correctly. All paths return the same PENDING | SUCCESS | FAILED outcome.
1446
1477
  */
1447
1478
  post: operations["postTxSubmit"];
1448
1479
  delete?: never;
@@ -1877,6 +1908,65 @@ interface operations {
1877
1908
  };
1878
1909
  };
1879
1910
  };
1911
+ getAuthSessionStatusByClientSessionIdPoll: {
1912
+ parameters: {
1913
+ query?: never;
1914
+ header?: never;
1915
+ path: {
1916
+ clientSessionId: string;
1917
+ };
1918
+ cookie?: never;
1919
+ };
1920
+ requestBody?: never;
1921
+ responses: {
1922
+ /** @description Current session status */
1923
+ 200: {
1924
+ headers: {
1925
+ [name: string]: unknown;
1926
+ };
1927
+ content: {
1928
+ "application/json": {
1929
+ /** @constant */
1930
+ code: "SDK_SESSION_STATUS";
1931
+ /** @constant */
1932
+ success: true;
1933
+ content: {
1934
+ status: string;
1935
+ user: {
1936
+ ready: boolean;
1937
+ };
1938
+ };
1939
+ };
1940
+ };
1941
+ };
1942
+ /** @description Not found */
1943
+ 404: {
1944
+ headers: {
1945
+ [name: string]: unknown;
1946
+ };
1947
+ content: {
1948
+ "application/json": {
1949
+ /** @constant */
1950
+ success: false;
1951
+ code: string;
1952
+ };
1953
+ };
1954
+ };
1955
+ /** @description Gone (expired) */
1956
+ 410: {
1957
+ headers: {
1958
+ [name: string]: unknown;
1959
+ };
1960
+ content: {
1961
+ "application/json": {
1962
+ /** @constant */
1963
+ success: false;
1964
+ code: string;
1965
+ };
1966
+ };
1967
+ };
1968
+ };
1969
+ };
1880
1970
  getAuthGoogle: {
1881
1971
  parameters: {
1882
1972
  query: {
@@ -2172,6 +2262,19 @@ interface operations {
2172
2262
  };
2173
2263
  };
2174
2264
  };
2265
+ /** @description Gone (expired) */
2266
+ 410: {
2267
+ headers: {
2268
+ [name: string]: unknown;
2269
+ };
2270
+ content: {
2271
+ "application/json": {
2272
+ /** @constant */
2273
+ success: false;
2274
+ code: string;
2275
+ };
2276
+ };
2277
+ };
2175
2278
  };
2176
2279
  };
2177
2280
  postAuthEmailVerifyCode: {
@@ -2259,6 +2362,19 @@ interface operations {
2259
2362
  };
2260
2363
  };
2261
2364
  };
2365
+ /** @description Gone (expired) */
2366
+ 410: {
2367
+ headers: {
2368
+ [name: string]: unknown;
2369
+ };
2370
+ content: {
2371
+ "application/json": {
2372
+ /** @constant */
2373
+ success: false;
2374
+ code: string;
2375
+ };
2376
+ };
2377
+ };
2262
2378
  };
2263
2379
  };
2264
2380
  postAuthWallet: {
@@ -2347,6 +2463,19 @@ interface operations {
2347
2463
  };
2348
2464
  };
2349
2465
  };
2466
+ /** @description Gone (expired) */
2467
+ 410: {
2468
+ headers: {
2469
+ [name: string]: unknown;
2470
+ };
2471
+ content: {
2472
+ "application/json": {
2473
+ /** @constant */
2474
+ success: false;
2475
+ code: string;
2476
+ };
2477
+ };
2478
+ };
2350
2479
  };
2351
2480
  };
2352
2481
  postAuthLogin: {
@@ -2478,6 +2607,19 @@ interface operations {
2478
2607
  };
2479
2608
  };
2480
2609
  };
2610
+ /** @description Gone (expired) */
2611
+ 410: {
2612
+ headers: {
2613
+ [name: string]: unknown;
2614
+ };
2615
+ content: {
2616
+ "application/json": {
2617
+ /** @constant */
2618
+ success: false;
2619
+ code: string;
2620
+ };
2621
+ };
2622
+ };
2481
2623
  };
2482
2624
  };
2483
2625
  postAuthRefresh: {
@@ -2568,6 +2710,19 @@ interface operations {
2568
2710
  };
2569
2711
  };
2570
2712
  };
2713
+ /** @description Gone (expired) */
2714
+ 410: {
2715
+ headers: {
2716
+ [name: string]: unknown;
2717
+ };
2718
+ content: {
2719
+ "application/json": {
2720
+ /** @constant */
2721
+ success: false;
2722
+ code: string;
2723
+ };
2724
+ };
2725
+ };
2571
2726
  };
2572
2727
  };
2573
2728
  postAuthLogout: {
@@ -4842,4 +4997,4 @@ declare function listDistributionRules(api: PollarApiClient): Promise<Distributi
4842
4997
  */
4843
4998
  declare function claimDistributionRule(api: PollarApiClient, body: DistributionClaimBody): Promise<DistributionClaimContent>;
4844
4999
 
4845
- export { AUTH_ERROR_CODES, type AdapterFn, AlbedoAdapter, type AuthErrorCode, type AuthState, type BuildOutcome, type BuildProofArgs, type ConnectWalletResponse, type DistributionClaimBody, type DistributionClaimContent, type DistributionRule, type DistributionRulesState, FreighterAdapter, type KeyManager, type KycFlow, type KycLevel, type KycProvider, type KycStartBody, type KycStartResponse, type KycStatus, type LocalStorageAdapterOptions, type NetworkState, OnStorageDegrade, type PaymentInstructions, type PollarAdapter, type PollarAdapters, type PollarApiClient, type PollarApplicationConfigContent, type PollarApplicationConfigResponse, PollarClient, type PollarClientConfig, PollarFlowError, type PollarLoginOptions, type PollarPersistedSession, type PollarUserProfile, type PublicEcJwk, type RampDirection, type RampQuote, type RampTxStatus, type RampsOfframpBody, type RampsOfframpResponse, type RampsOnrampBody, type RampsOnrampResponse, type RampsQuoteQuery, type RampsQuoteResponse, type RampsTransactionResponse, type RulePeriod, type SessionInfo, type SignAuthEntryOptions, type SignAuthEntryResponse, type SignOutcome, type SignTransactionOptions, type SignTransactionResponse, type StellarBalance, StellarClient, type StellarClientConfig, type StellarNetwork, Storage, type SubmitOutcome, type TransactionState, type TxBuildBody, type TxBuildContent, type TxBuildResponse, type TxBuildSignSubmitBody, type TxBuildSignSubmitContent, type TxBuildSignSubmitResponse, type TxErrorPhase, type TxHistoryContent, type TxHistoryParams, type TxHistoryRecord, type TxHistoryState, type TxSignAndSendBody, type TxSignBody, type TxSignContent, type TxSignResponse, type TxSignSendResponse, type TxSubmitSignedBody, type WalletAdapter, type WalletAdapterResolver, type WalletBalanceContent, type WalletBalanceRecord, type WalletBalanceState, type WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, type paths as pollarPaths, resolveKyc, startKyc };
5000
+ export { AUTH_ERROR_CODES, type AdapterFn, AlbedoAdapter, type AuthErrorCode, type AuthOpenContext, type AuthState, type AuthUrlOpener, type BuildOutcome, type BuildProofArgs, type ConnectWalletResponse, type DistributionClaimBody, type DistributionClaimContent, type DistributionRule, type DistributionRulesState, FreighterAdapter, type KeyManager, type KycFlow, type KycLevel, type KycProvider, type KycStartBody, type KycStartResponse, type KycStatus, type LocalStorageAdapterOptions, type NetworkState, OnStorageDegrade, type PaymentInstructions, type PollarAdapter, type PollarAdapters, type PollarApiClient, type PollarApplicationConfigContent, type PollarApplicationConfigResponse, PollarClient, type PollarClientConfig, PollarFlowError, type PollarLoginOptions, type PollarPersistedSession, type PollarUserProfile, type PublicEcJwk, type RampDirection, type RampQuote, type RampTxStatus, type RampsOfframpBody, type RampsOfframpResponse, type RampsOnrampBody, type RampsOnrampResponse, type RampsQuoteQuery, type RampsQuoteResponse, type RampsTransactionResponse, type RulePeriod, type SessionInfo, type SignAuthEntryOptions, type SignAuthEntryResponse, type SignOutcome, type SignTransactionOptions, type SignTransactionResponse, type StellarBalance, StellarClient, type StellarClientConfig, type StellarNetwork, Storage, type SubmitOutcome, type TransactionState, type TxBuildBody, type TxBuildContent, type TxBuildResponse, type TxBuildSignSubmitBody, type TxBuildSignSubmitContent, type TxBuildSignSubmitResponse, type TxErrorPhase, type TxHistoryContent, type TxHistoryParams, type TxHistoryRecord, type TxHistoryState, type TxSignAndSendBody, type TxSignBody, type TxSignContent, type TxSignResponse, type TxSignSendResponse, type TxSubmitSignedBody, type WalletAdapter, type WalletAdapterResolver, type WalletBalanceContent, type WalletBalanceRecord, type WalletBalanceState, type WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, claimDistributionRule, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, listDistributionRules, normalizeHtu, pollKycStatus, pollRampTransaction, type paths as pollarPaths, resolveKyc, startKyc };