@pollar/core 0.5.3 → 0.7.0

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/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { S as Storage, O as OnStorageDegrade } from './types-DqgJIJBl.js';
2
+ export { a as StorageDegradeReason } from './types-DqgJIJBl.js';
1
3
  import * as openapi_fetch from 'openapi-fetch';
2
4
 
3
5
  type StellarNetwork = 'mainnet' | 'testnet';
@@ -21,10 +23,70 @@ declare class StellarClient {
21
23
  }>;
22
24
  }
23
25
 
26
+ /**
27
+ * Public JWK shape for an EC P-256 key. Only the four required members for
28
+ * RFC 7638 thumbprint computation; never includes private fields or extras
29
+ * like `alg` / `use` / `kid`.
30
+ */
31
+ interface PublicEcJwk {
32
+ kty: 'EC';
33
+ crv: 'P-256';
34
+ /** Base64url-encoded big-endian X coordinate (32 bytes). */
35
+ x: string;
36
+ /** Base64url-encoded big-endian Y coordinate (32 bytes). */
37
+ y: string;
38
+ }
39
+ /**
40
+ * Manages the per-session ECDSA P-256 keypair used to sign DPoP proofs.
41
+ *
42
+ * Implementations:
43
+ * - `WebCryptoKeyManager` (web): non-extractable `CryptoKey` persisted in
44
+ * IndexedDB. Private key bytes never leave the browser's crypto context.
45
+ * - `NobleKeyManager` (React Native): private scalar bytes stored through an
46
+ * injected `Storage` adapter (Keychain / SecureStore). Pure-JS ECDSA via
47
+ * `@noble/curves`.
48
+ */
49
+ interface KeyManager {
50
+ /**
51
+ * Load an existing key for this session or generate a new one. Idempotent.
52
+ * Must be called before `getPublicJwk`, `getThumbprint`, or `sign`.
53
+ */
54
+ init(): Promise<void>;
55
+ /**
56
+ * Destroy the key. Removes it from persistent storage and clears any
57
+ * cached state. Used on logout.
58
+ */
59
+ reset(): Promise<void>;
60
+ /**
61
+ * The public JWK that goes into the DPoP proof header. Returns a fresh
62
+ * object every call (callers may mutate without affecting the manager).
63
+ */
64
+ getPublicJwk(): Promise<PublicEcJwk>;
65
+ /**
66
+ * RFC 7638 JWK thumbprint, base64url(SHA-256(canonical JWK)). The server
67
+ * compares this to the access token's `cnf.jkt` claim.
68
+ */
69
+ getThumbprint(): Promise<string>;
70
+ /**
71
+ * Sign the given bytes with ECDSA-P256-SHA256. Returns 64-byte raw r||s
72
+ * (IEEE P1363 / JOSE format), NOT DER. Suitable for direct base64url
73
+ * encoding into the JWS signature segment.
74
+ */
75
+ sign(payload: Uint8Array): Promise<Uint8Array>;
76
+ }
77
+
24
78
  declare enum WalletType {
25
79
  FREIGHTER = "freighter",
26
80
  ALBEDO = "albedo"
27
81
  }
82
+ /**
83
+ * A wallet identifier. Accepts the internal `WalletType` enum values
84
+ * (`'freighter'`, `'albedo'`) plus any opaque string id used by external
85
+ * adapter packages (e.g. Stellar Wallets Kit ids like `'xbull'`, `'lobstr'`).
86
+ * The `(string & {})` keeps autocomplete on the enum values without rejecting
87
+ * arbitrary strings.
88
+ */
89
+ type WalletId = WalletType | (string & {});
28
90
  interface ConnectWalletResponse {
29
91
  address: string;
30
92
  publicKey: string;
@@ -44,7 +106,7 @@ interface SignAuthEntryResponse {
44
106
  signedAuthEntry: string;
45
107
  }
46
108
  interface WalletAdapter {
47
- type: WalletType;
109
+ type: WalletId;
48
110
  isAvailable(): Promise<boolean>;
49
111
  connect(): Promise<ConnectWalletResponse>;
50
112
  disconnect(): Promise<void>;
@@ -52,6 +114,12 @@ interface WalletAdapter {
52
114
  signTransaction(xdr: string, options?: SignTransactionOptions): Promise<SignTransactionResponse>;
53
115
  signAuthEntry(entryXdr: string, options?: SignAuthEntryOptions): Promise<SignAuthEntryResponse>;
54
116
  }
117
+ /**
118
+ * Resolves a {@link WalletAdapter} for a given wallet id. Injected through
119
+ * `PollarClientConfig.walletAdapter` so wallet implementations (Stellar
120
+ * Wallets Kit, custom modules, etc.) can live outside `@pollar/core`.
121
+ */
122
+ type WalletAdapterResolver = (id: WalletId) => WalletAdapter | Promise<WalletAdapter>;
55
123
 
56
124
  declare class FreighterAdapter implements WalletAdapter {
57
125
  readonly type = WalletType.FREIGHTER;
@@ -76,11 +144,102 @@ declare class AlbedoAdapter implements WalletAdapter {
76
144
  }
77
145
 
78
146
  type PollarApplicationConfigResponse = paths['/auth/login']['post']['responses'][200]['content']['application/json'];
147
+ /** Full `/auth/login` response shape — used in transit but NOT persisted. */
79
148
  type PollarApplicationConfigContent = PollarApplicationConfigResponse['content'];
149
+ /**
150
+ * What we actually write to `Storage`. Drops the PII subtree (`data.*`)
151
+ * which is held in memory only on `PollarClient._profile` after auth.
152
+ */
153
+ interface PollarPersistedSession {
154
+ clientSessionId: string;
155
+ userId: string | null;
156
+ status: string;
157
+ token: {
158
+ accessToken: string;
159
+ refreshToken: string;
160
+ expiresAt: number;
161
+ };
162
+ user: {
163
+ id?: string;
164
+ ready: boolean;
165
+ };
166
+ wallet: {
167
+ publicKey: string | null;
168
+ existsOnStellar?: boolean;
169
+ createdAt?: number;
170
+ };
171
+ }
172
+ /** In-memory user profile (kept on `PollarClient`, never persisted). */
173
+ interface PollarUserProfile {
174
+ mail: string;
175
+ first_name: string;
176
+ last_name: string;
177
+ avatar: string;
178
+ providers: {
179
+ email: {
180
+ address: string;
181
+ } | null;
182
+ google: {
183
+ id: string;
184
+ } | null;
185
+ github: {
186
+ id: string;
187
+ } | null;
188
+ wallet: {
189
+ address: string;
190
+ } | null;
191
+ };
192
+ }
80
193
  interface PollarClientConfig {
81
194
  stellarNetwork?: StellarNetwork;
82
195
  baseUrl?: string;
83
196
  apiKey: string;
197
+ /**
198
+ * Pluggable storage. Defaults to `defaultStorage()` on web (localStorage
199
+ * with memory fallback). On RN you must inject one of the adapters from
200
+ * `@pollar/core/adapters/expo` or `@pollar/core/adapters/react-native-keychain`.
201
+ */
202
+ storage?: Storage;
203
+ /**
204
+ * Pluggable DPoP key manager. Defaults to `defaultKeyManager(storage,
205
+ * apiKeyHash)`: WebCrypto in browsers, `@noble/curves` in RN.
206
+ */
207
+ keyManager?: KeyManager;
208
+ /**
209
+ * Notified when persistent storage silently degrades to in-memory mode
210
+ * (Safari private browsing quota errors, sandboxed iframes, etc.). Useful
211
+ * for telemetry — the SDK keeps working but sessions won't survive reload.
212
+ */
213
+ onStorageDegrade?: OnStorageDegrade;
214
+ /**
215
+ * Resolves a {@link WalletAdapter} for a given wallet id. If omitted, the
216
+ * SDK falls back to its built-in `FreighterAdapter` / `AlbedoAdapter`,
217
+ * which only know `WalletType.FREIGHTER` and `WalletType.ALBEDO`. Inject
218
+ * `@pollar/stellar-wallets-kit-adapter` (or your own resolver) to support
219
+ * additional wallets without bundling those dependencies into `@pollar/core`.
220
+ */
221
+ walletAdapter?: WalletAdapterResolver;
222
+ /**
223
+ * Optional human-friendly label sent at /auth/login time and recorded on
224
+ * the server-side refresh-token row so the user can identify it in the
225
+ * "active sessions" UI (e.g. "iPhone — Safari", "Mac — Chrome 126").
226
+ * If unset, the server-recorded `user_agent` header is the fallback.
227
+ */
228
+ deviceLabel?: string;
229
+ }
230
+ /**
231
+ * One row in the active-sessions list (returned by `PollarClient.listSessions()`).
232
+ * Mirrors the sdk-api `SessionsListContent` schema.
233
+ */
234
+ interface SessionInfo {
235
+ familyId: string;
236
+ createdAt: string;
237
+ lastUsedAt: string | null;
238
+ userAgent: string | null;
239
+ ipHash: string | null;
240
+ deviceLabel: string | null;
241
+ current: boolean;
242
+ expiresAt: string;
84
243
  }
85
244
  type TxBuildBody = NonNullable<paths['/tx/build']['post']['requestBody']>['content']['application/json'];
86
245
  type TxBuildResponse = paths['/tx/build']['post']['responses'][200]['content']['application/json'];
@@ -95,7 +254,7 @@ type PollarLoginOptions = {
95
254
  email: string;
96
255
  } | {
97
256
  provider: 'wallet';
98
- type: WalletType;
257
+ type: WalletId;
99
258
  };
100
259
  type TxBuildContent = TxBuildResponse['content'];
101
260
  type TransactionState = {
@@ -155,17 +314,17 @@ type AuthState = {
155
314
  provider: 'google' | 'github';
156
315
  } | {
157
316
  step: 'connecting_wallet';
158
- walletType: WalletType;
317
+ walletType: WalletId;
159
318
  } | {
160
319
  step: 'wallet_not_installed';
161
- walletType: WalletType;
320
+ walletType: WalletId;
162
321
  } | {
163
322
  step: 'authenticating_wallet';
164
323
  } | {
165
324
  step: 'authenticating';
166
325
  } | {
167
326
  step: 'authenticated';
168
- session: PollarApplicationConfigContent;
327
+ session: PollarPersistedSession;
169
328
  } | {
170
329
  step: 'error';
171
330
  previousStep: string;
@@ -231,12 +390,12 @@ type RampsTransactionResponse = paths['/ramps/transaction/{txId}']['get']['respo
231
390
  type RampTxStatus = RampsTransactionResponse['status'];
232
391
  type RampDirection = RampsTransactionResponse['direction'];
233
392
  type PaymentInstructions = RampsOnrampResponse['paymentInstructions'];
234
- type EscrowFn<TParams = unknown> = (params: TParams) => Promise<{
393
+ type AdapterFn<TParams = unknown> = (params: TParams) => Promise<{
235
394
  unsignedTransaction: string;
236
395
  }>;
237
- type EscrowAdapter = Record<string, EscrowFn<any>>;
396
+ type PollarAdapter = Record<string, AdapterFn<any>>;
238
397
  interface PollarAdapters {
239
- [key: string]: EscrowAdapter;
398
+ [key: string]: PollarAdapter;
240
399
  }
241
400
 
242
401
  declare class PollarClient {
@@ -244,7 +403,32 @@ declare class PollarClient {
244
403
  readonly id: string;
245
404
  readonly basePath: string;
246
405
  private readonly _api;
406
+ private readonly _storage;
407
+ private readonly _keyManager;
408
+ /** Resolves once `keyManager.init()` and the initial session restore complete. */
409
+ private readonly _initialized;
410
+ /**
411
+ * Per-API-key storage namespace. Computed asynchronously inside
412
+ * `_initialize()` because SHA-256 lives behind `crypto.subtle.digest`.
413
+ * Accessing `apiKeyHash` before `await client.ready()` throws.
414
+ */
415
+ private _apiKeyHash;
416
+ /**
417
+ * Short SHA-256-derived namespace for this client's persisted state.
418
+ * Available after `await client.ready()` (or any awaited method); throws
419
+ * if read before initialization completes.
420
+ */
421
+ get apiKeyHash(): string;
247
422
  private _session;
423
+ private _profile;
424
+ /** Last `DPoP-Nonce` we saw from a server response. Carried into the next proof. */
425
+ private _dpopNonce;
426
+ /** Singleton in-flight refresh — concurrent 401s coalesce into one /auth/refresh call. */
427
+ private _refreshPromise;
428
+ private _storageEventHandler;
429
+ /** Optional UI label sent to the server at /auth/login so the sessions UI
430
+ * can show a recognizable device name. Set via PollarClientConfig.deviceLabel. */
431
+ private readonly _deviceLabel;
248
432
  private _transactionState;
249
433
  private _transactionStateListeners;
250
434
  private _txHistoryState;
@@ -256,17 +440,61 @@ declare class PollarClient {
256
440
  private _networkState;
257
441
  private _networkStateListeners;
258
442
  private _walletAdapter;
443
+ private readonly _walletAdapterResolver;
259
444
  private _loginController;
260
445
  constructor(config: PollarClientConfig);
446
+ /** Awaitable handle for the initial keypair + session restore. */
447
+ ready(): Promise<void>;
448
+ private _initialize;
449
+ /** Detach the cross-tab storage listener and abort any in-flight login. */
450
+ destroy(): void;
451
+ private _wireMiddlewares;
452
+ private _buildProofForRequest;
453
+ private _retryRequest;
454
+ /**
455
+ * Coalesce concurrent refresh attempts. The first caller does the work;
456
+ * everyone else awaits the same promise and sees the new tokens.
457
+ */
458
+ refresh(): Promise<void>;
459
+ private _doRefresh;
261
460
  getAuthState(): AuthState;
262
461
  onAuthStateChange(cb: (state: AuthState) => void): () => void;
462
+ /** PII (email, names, avatar, providers). Held in memory only — never persisted. */
463
+ getUserProfile(): PollarUserProfile | null;
263
464
  login(options: PollarLoginOptions): void;
264
465
  beginEmailLogin(): void;
265
466
  sendEmailCode(email: string): void;
266
467
  verifyEmailCode(code: string): void;
267
- loginWallet(type: WalletType): void;
468
+ loginWallet(type: WalletId): void;
268
469
  cancelLogin(): void;
269
- logout(): void;
470
+ /**
471
+ * Revoke the current session server-side, then clear local storage.
472
+ *
473
+ * Server revocation is best-effort: if the POST fails (offline, server
474
+ * down), local state is wiped regardless. The orphan refresh token then
475
+ * remains unused until its natural expiry. The in-flight access token
476
+ * stays valid until its own TTL elapses (≤10 min for DPoP-bound tokens).
477
+ *
478
+ * Pass `everywhere: true` to revoke every active session for this user
479
+ * across all devices.
480
+ */
481
+ logout(options?: {
482
+ everywhere?: boolean;
483
+ }): Promise<void>;
484
+ /** Convenience: revoke every active session for this user (all devices). */
485
+ logoutEverywhere(): Promise<void>;
486
+ /**
487
+ * List active sessions for the authenticated user. Returns one entry per
488
+ * refresh-token family with the metadata captured at issuance time. The
489
+ * `current` flag identifies which entry corresponds to this client.
490
+ */
491
+ listSessions(): Promise<SessionInfo[]>;
492
+ /**
493
+ * Revoke a specific refresh-token family (a single device session). Use
494
+ * `listSessions` to enumerate the familyIds. Revoking the current session
495
+ * does NOT clear local state — call `logout()` for that case.
496
+ */
497
+ revokeSession(familyId: string): Promise<void>;
270
498
  getNetwork(): StellarNetwork;
271
499
  getNetworkState(): NetworkState;
272
500
  setNetwork(network: StellarNetwork): void;
@@ -280,7 +508,7 @@ declare class PollarClient {
280
508
  onWalletBalanceStateChange(cb: (state: WalletBalanceState) => void): () => void;
281
509
  refreshBalance(publicKey?: string): Promise<void>;
282
510
  buildTx(operation: TxBuildBody['operation'], params: TxBuildBody['params'], options?: TxBuildBody['options']): Promise<void>;
283
- getWalletType(): WalletType | null;
511
+ getWalletType(): WalletId | null;
284
512
  signAndSubmitTx(unsignedXdr: string): Promise<void>;
285
513
  getAppConfig(): Promise<unknown>;
286
514
  getKycStatus(providerId?: string): Promise<{
@@ -318,10 +546,15 @@ declare class PollarClient {
318
546
  }): Promise<RampTxStatus>;
319
547
  private _setTxHistoryState;
320
548
  private _setWalletBalanceState;
321
- /** Creates a new AbortController, cancelling any existing flow first. */
322
549
  private _newController;
323
- /** Builds the deps object passed to flow functions via bind pattern. */
324
550
  private _flowDeps;
551
+ /**
552
+ * Resolves a wallet adapter for the requested id. Uses the consumer's
553
+ * injected `walletAdapter` resolver when present; otherwise falls back to
554
+ * the built-in `FreighterAdapter` / `AlbedoAdapter`. Throws if the id is
555
+ * unknown and no resolver is configured.
556
+ */
557
+ private _resolveWalletAdapter;
325
558
  private _handleFlowError;
326
559
  private _restoreSession;
327
560
  private _storeSession;
@@ -332,6 +565,179 @@ declare class PollarClient {
332
565
  private _setTransactionState;
333
566
  }
334
567
 
568
+ /**
569
+ * In-memory storage backed by a `Map`. Always available, never throws.
570
+ * Used as the default fallback for SSR, private browsing, sandboxed iframes
571
+ * without `allow-same-origin`, or any environment where `localStorage` is
572
+ * unusable.
573
+ */
574
+ declare function createMemoryAdapter(): Storage;
575
+ interface LocalStorageAdapterOptions {
576
+ /**
577
+ * Optional callback invoked the first time the adapter degrades to its
578
+ * in-memory fallback (e.g. quota exceeded, throwing `localStorage`).
579
+ */
580
+ onDegrade?: OnStorageDegrade;
581
+ }
582
+ /**
583
+ * `localStorage`-backed adapter that wraps every operation in try/catch and
584
+ * silently degrades to an in-memory fallback for the rest of the process
585
+ * lifetime on any throw. A single warning is logged when the degrade happens.
586
+ *
587
+ * Why every op (not just the probe): Safari private mode and sandboxed iframes
588
+ * may expose `localStorage` but throw `QuotaExceededError` / `SecurityError`
589
+ * on the first write — a successful probe at construction time isn't enough.
590
+ *
591
+ * Tokens persisted here are DPoP-bound to a non-extractable WebCrypto
592
+ * keypair, so XSS exposure is limited to a signing-oracle attack (the key
593
+ * itself never leaves the browser's crypto subsystem). Consumers who need
594
+ * stricter isolation can inject a custom `Storage` adapter — e.g. one that
595
+ * proxies to an httpOnly cookie on a host origin.
596
+ */
597
+ declare function createLocalStorageAdapter(options?: LocalStorageAdapterOptions): Storage;
598
+
599
+ /**
600
+ * Returns `localStorage`-backed storage when it works, otherwise an in-memory
601
+ * fallback. The probe writes-reads-removes a sentinel; any throw, value
602
+ * mismatch, or missing `localStorage` (SSR / disabled storage) falls back.
603
+ *
604
+ * Run-time degrade still happens inside `createLocalStorageAdapter` — see its
605
+ * docstring for the rationale.
606
+ */
607
+ declare function defaultStorage(options?: LocalStorageAdapterOptions): Storage;
608
+
609
+ /**
610
+ * Construct the default `KeyManager` for the current runtime. Throws if no
611
+ * factory has been registered — that only happens if `@pollar/core` was
612
+ * imported in a way that bypassed the entry-point module (a bundler or
613
+ * test setup bug).
614
+ */
615
+ declare function defaultKeyManager(storage: Storage, apiKey: string): KeyManager;
616
+
617
+ declare class WebCryptoKeyManager implements KeyManager {
618
+ private readonly apiKey;
619
+ private apiKeyHash;
620
+ private keyPair;
621
+ private publicJwk;
622
+ private thumbprint;
623
+ /**
624
+ * Cached in-flight init. Lets `init()` be called concurrently (or implicitly
625
+ * from `getPublicJwk` / `sign`) without doing the work twice. Cleared on
626
+ * failure so callers can retry, and cleared on `reset()`.
627
+ */
628
+ private _initPromise;
629
+ constructor(apiKey: string);
630
+ /**
631
+ * Idempotent and safe under concurrency. The first call kicks off the real
632
+ * init; subsequent (and concurrent) calls return the same in-flight promise.
633
+ * Other methods (`getPublicJwk`, `getThumbprint`, `sign`) auto-await this so
634
+ * the manager is self-healing if `init()` was never explicitly invoked.
635
+ */
636
+ init(): Promise<void>;
637
+ private _doInit;
638
+ reset(): Promise<void>;
639
+ getPublicJwk(): Promise<PublicEcJwk>;
640
+ getThumbprint(): Promise<string>;
641
+ sign(payload: Uint8Array): Promise<Uint8Array>;
642
+ }
643
+
644
+ /**
645
+ * Compute the RFC 7638 JWK thumbprint for an EC P-256 public JWK.
646
+ *
647
+ * Algorithm (RFC 7638 §3):
648
+ * 1. Build a JSON object containing ONLY the required members of the JWK,
649
+ * ordered lexicographically by member name (Unicode code point).
650
+ * For EC keys, that's exactly {crv, kty, x, y}.
651
+ * 2. Serialize to UTF-8 with no whitespace and no line breaks.
652
+ * 3. Hash with SHA-256.
653
+ * 4. Base64url-encode the hash (no padding).
654
+ *
655
+ * Common bugs guarded against:
656
+ * - Including extra fields (`alg`, `use`, `kid`, `ext`, `key_ops`).
657
+ * - Wrong member ordering (must be lex by Unicode code point).
658
+ * - Padded base64 instead of base64url unpadded.
659
+ * - Using `JSON.stringify(jwk)` of an arbitrary-key-order object — we build
660
+ * a fresh literal in canonical order to make the order explicit and not
661
+ * rely on V8's insertion-order semantics.
662
+ */
663
+ declare function computeJwkThumbprint(jwk: PublicEcJwk): Promise<string>;
664
+ /**
665
+ * Strip a JWK to only the four required EC public members. Useful when the
666
+ * input came from `crypto.subtle.exportKey('jwk', publicKey)` which adds
667
+ * `ext` / `key_ops`. Returns a fresh object — never mutates input.
668
+ */
669
+ declare function canonicalEcJwk(jwk: {
670
+ kty?: string;
671
+ crv?: string;
672
+ x?: string;
673
+ y?: string;
674
+ }): PublicEcJwk;
675
+
676
+ /**
677
+ * RFC 9449 DPoP proof builder.
678
+ *
679
+ * Produces a compact JWS that the consumer attaches as the `DPoP` HTTP
680
+ * header. The header `jwk` is the public part of the SDK's per-session
681
+ * keypair; the server verifies the signature, validates the `htm` / `htu` /
682
+ * `iat` / `jti` / optional `nonce` / optional `ath` claims, and matches the
683
+ * proof's JWK thumbprint against the access token's `cnf.jkt` claim.
684
+ *
685
+ * Server-issued nonce flow (RFC 9449 §8/§9): the server may respond with
686
+ * `WWW-Authenticate: DPoP ... error="use_dpop_nonce"` plus a `DPoP-Nonce`
687
+ * header. The client should re-build the proof with the new nonce and retry.
688
+ * `buildProof` accepts an optional nonce; the SDK client tracks it across
689
+ * requests and feeds it back here.
690
+ *
691
+ * The last seen `DPoP-Nonce` is stored verbatim and embedded in the next
692
+ * proof. The server validates it as an HMAC token, so an attacker who
693
+ * injects an arbitrary nonce cannot escalate — verification fails and the
694
+ * server replies with a fresh nonce on the next request.
695
+ */
696
+ interface BuildProofArgs {
697
+ /** HTTP method, e.g. `"GET"`. Will be uppercased before signing. */
698
+ htm: string;
699
+ /**
700
+ * HTTP target URI. Will be normalized per RFC 3986 §6.2 (lowercase scheme
701
+ * + host, default port elided, query+fragment+userinfo stripped, path
702
+ * dot-segments resolved, trailing slash preserved exactly as provided).
703
+ */
704
+ htu: string;
705
+ /**
706
+ * Access token to bind the proof to (its base64url(SHA-256) goes in the
707
+ * `ath` claim). Omit for proofs sent to the token endpoint per RFC 9449
708
+ * §5 / §6.1 (those proofs MUST NOT include `ath`).
709
+ */
710
+ accessToken?: string;
711
+ /**
712
+ * Server-issued DPoP nonce, if the server has previously challenged this
713
+ * client with `WWW-Authenticate: DPoP ... error="use_dpop_nonce"`. RFC
714
+ * 9449 §8.
715
+ */
716
+ nonce?: string;
717
+ }
718
+ /**
719
+ * Build a DPoP proof JWS for the given request. Returns the compact-form
720
+ * JWS string (`<header>.<payload>.<signature>`).
721
+ */
722
+ declare function buildProof(args: BuildProofArgs, keyManager: KeyManager): Promise<string>;
723
+ /**
724
+ * Normalize an HTTP URI for use as the `htu` claim.
725
+ *
726
+ * RFC 9449 §4.3 + RFC 3986 §6.2:
727
+ * - lowercase scheme + host
728
+ * - elide default port (`:443` for https, `:80` for http)
729
+ * - strip userinfo (never appears in `htu`)
730
+ * - strip query + fragment
731
+ * - apply path dot-segment removal (handled by the URL constructor)
732
+ * - **preserve trailing slash exactly** — `/foo` and `/foo/` are distinct
733
+ * paths per RFC 3986 §6 and must round-trip identically.
734
+ * - preserve IPv6 brackets in host
735
+ *
736
+ * Both client and server must apply the same normalization so the `htu`
737
+ * claim matches deterministically.
738
+ */
739
+ declare function normalizeHtu(rawUrl: string): string;
740
+
335
741
  /**
336
742
  * This file was auto-generated by openapi-typescript.
337
743
  * Do not make direct changes to the file.
@@ -435,6 +841,26 @@ interface paths {
435
841
  patch?: never;
436
842
  trace?: never;
437
843
  };
844
+ "/auth/oidc": {
845
+ parameters: {
846
+ query?: never;
847
+ header?: never;
848
+ path?: never;
849
+ cookie?: never;
850
+ };
851
+ /**
852
+ * Redirect to Authentik OIDC
853
+ * @description Redirects the user to the Authentik authorization endpoint (PKCE, per-app).
854
+ */
855
+ get: operations["getAuthOidc"];
856
+ put?: never;
857
+ post?: never;
858
+ delete?: never;
859
+ options?: never;
860
+ head?: never;
861
+ patch?: never;
862
+ trace?: never;
863
+ };
438
864
  "/auth/email": {
439
865
  parameters: {
440
866
  query?: never;
@@ -506,6 +932,59 @@ interface paths {
506
932
  patch?: never;
507
933
  trace?: never;
508
934
  };
935
+ "/auth/refresh": {
936
+ parameters: {
937
+ query?: never;
938
+ header?: never;
939
+ path?: never;
940
+ cookie?: never;
941
+ };
942
+ get?: never;
943
+ put?: never;
944
+ /**
945
+ * Rotate a DPoP-bound refresh token
946
+ * @description Single-use rotation per RFC 9449 §5. Requires a DPoP proof (no `ath`) bound to the same key as the refresh token (`cnf.jkt`). On reuse outside the 30s grace window, the entire token family is revoked.
947
+ */
948
+ post: operations["postAuthRefresh"];
949
+ delete?: never;
950
+ options?: never;
951
+ head?: never;
952
+ patch?: never;
953
+ trace?: never;
954
+ };
955
+ "/auth/logout": {
956
+ parameters: { query?: never; header?: never; path?: never; cookie?: never };
957
+ get?: never;
958
+ put?: never;
959
+ post: operations["postAuthLogout"];
960
+ delete?: never;
961
+ options?: never;
962
+ head?: never;
963
+ patch?: never;
964
+ trace?: never;
965
+ };
966
+ "/auth/sessions": {
967
+ parameters: { query?: never; header?: never; path?: never; cookie?: never };
968
+ get: operations["getAuthSessions"];
969
+ put?: never;
970
+ post?: never;
971
+ delete?: never;
972
+ options?: never;
973
+ head?: never;
974
+ patch?: never;
975
+ trace?: never;
976
+ };
977
+ "/auth/sessions/{familyId}": {
978
+ parameters: { query?: never; header?: never; path?: never; cookie?: never };
979
+ get?: never;
980
+ put?: never;
981
+ post?: never;
982
+ delete: operations["deleteAuthSessionByFamilyId"];
983
+ options?: never;
984
+ head?: never;
985
+ patch?: never;
986
+ trace?: never;
987
+ };
509
988
  "/applications/config": {
510
989
  parameters: {
511
990
  query?: never;
@@ -905,29 +1384,8 @@ interface operations {
905
1384
  "text/event-stream": {
906
1385
  status: string;
907
1386
  user: {
908
- id?: string;
909
1387
  ready: boolean;
910
1388
  };
911
- data: {
912
- mail: string;
913
- first_name: string;
914
- last_name: string;
915
- avatar: string;
916
- providers: {
917
- email: {
918
- address: string;
919
- } | null;
920
- google: {
921
- id: string;
922
- } | null;
923
- github: {
924
- id: string;
925
- } | null;
926
- wallet: {
927
- address: string;
928
- } | null;
929
- };
930
- };
931
1389
  };
932
1390
  };
933
1391
  };
@@ -1081,6 +1539,66 @@ interface operations {
1081
1539
  };
1082
1540
  };
1083
1541
  };
1542
+ getAuthOidc: {
1543
+ parameters: {
1544
+ query: {
1545
+ api_key: string;
1546
+ client_session_id: string;
1547
+ };
1548
+ header?: never;
1549
+ path?: never;
1550
+ cookie?: never;
1551
+ };
1552
+ requestBody?: never;
1553
+ responses: {
1554
+ /** @description Redirect to Authentik */
1555
+ 302: {
1556
+ headers: {
1557
+ [name: string]: unknown;
1558
+ };
1559
+ content?: never;
1560
+ };
1561
+ /** @description Validation error */
1562
+ 400: {
1563
+ headers: {
1564
+ [name: string]: unknown;
1565
+ };
1566
+ content: {
1567
+ "application/json": {
1568
+ /** @constant */
1569
+ success: false;
1570
+ error: string;
1571
+ };
1572
+ };
1573
+ };
1574
+ /** @description Unauthorized */
1575
+ 401: {
1576
+ headers: {
1577
+ [name: string]: unknown;
1578
+ };
1579
+ content: {
1580
+ "application/json": {
1581
+ /** @constant */
1582
+ success: false;
1583
+ error: string;
1584
+ };
1585
+ };
1586
+ };
1587
+ /** @description Not found */
1588
+ 404: {
1589
+ headers: {
1590
+ [name: string]: unknown;
1591
+ };
1592
+ content: {
1593
+ "application/json": {
1594
+ /** @constant */
1595
+ success: false;
1596
+ error: string;
1597
+ };
1598
+ };
1599
+ };
1600
+ };
1601
+ };
1084
1602
  postAuthEmail: {
1085
1603
  parameters: {
1086
1604
  query?: never;
@@ -1356,6 +1874,15 @@ interface operations {
1356
1874
  content: {
1357
1875
  "application/json": {
1358
1876
  clientSessionId: string;
1877
+ dpopJwk?: {
1878
+ /** @constant */
1879
+ kty: "EC";
1880
+ /** @constant */
1881
+ crv: "P-256";
1882
+ x: string;
1883
+ y: string;
1884
+ };
1885
+ deviceLabel?: string;
1359
1886
  };
1360
1887
  };
1361
1888
  };
@@ -1467,6 +1994,96 @@ interface operations {
1467
1994
  };
1468
1995
  };
1469
1996
  };
1997
+ postAuthRefresh: {
1998
+ parameters: {
1999
+ query?: never;
2000
+ header?: never;
2001
+ path?: never;
2002
+ cookie?: never;
2003
+ };
2004
+ requestBody: {
2005
+ content: {
2006
+ "application/json": {
2007
+ refreshToken: string;
2008
+ };
2009
+ };
2010
+ };
2011
+ responses: {
2012
+ /** @description New token pair issued */
2013
+ 200: {
2014
+ headers: {
2015
+ [name: string]: unknown;
2016
+ };
2017
+ content: {
2018
+ "application/json": {
2019
+ /** @constant */
2020
+ code: "SDK_TOKEN_REFRESHED";
2021
+ /** @constant */
2022
+ success: true;
2023
+ content: {
2024
+ token: {
2025
+ accessToken: string;
2026
+ refreshToken: string;
2027
+ expiresAt: number;
2028
+ };
2029
+ };
2030
+ };
2031
+ };
2032
+ };
2033
+ /** @description Validation error */
2034
+ 400: {
2035
+ headers: {
2036
+ [name: string]: unknown;
2037
+ };
2038
+ content: {
2039
+ "application/json": {
2040
+ /** @constant */
2041
+ success: false;
2042
+ error: string;
2043
+ };
2044
+ };
2045
+ };
2046
+ /** @description Unauthorized */
2047
+ 401: {
2048
+ headers: {
2049
+ [name: string]: unknown;
2050
+ };
2051
+ content: {
2052
+ "application/json": {
2053
+ /** @constant */
2054
+ success: false;
2055
+ error: string;
2056
+ };
2057
+ };
2058
+ };
2059
+ /** @description Forbidden */
2060
+ 403: {
2061
+ headers: {
2062
+ [name: string]: unknown;
2063
+ };
2064
+ content: {
2065
+ "application/json": {
2066
+ /** @constant */
2067
+ success: false;
2068
+ error: string;
2069
+ };
2070
+ };
2071
+ };
2072
+ /** @description Not found */
2073
+ 404: {
2074
+ headers: {
2075
+ [name: string]: unknown;
2076
+ };
2077
+ content: {
2078
+ "application/json": {
2079
+ /** @constant */
2080
+ success: false;
2081
+ error: string;
2082
+ };
2083
+ };
2084
+ };
2085
+ };
2086
+ };
1470
2087
  getApplicationsConfig: {
1471
2088
  parameters: {
1472
2089
  query?: never;
@@ -2677,12 +3294,102 @@ interface operations {
2677
3294
  };
2678
3295
  };
2679
3296
  };
3297
+ postAuthLogout: {
3298
+ parameters: { query?: never; header?: never; path?: never; cookie?: never };
3299
+ requestBody?: {
3300
+ content: {
3301
+ "application/json": {
3302
+ everywhere?: boolean;
3303
+ };
3304
+ };
3305
+ };
3306
+ responses: {
3307
+ 200: {
3308
+ headers: { [name: string]: unknown };
3309
+ content: {
3310
+ "application/json": {
3311
+ /** @constant */
3312
+ code: "SDK_LOGOUT_SUCCESS";
3313
+ /** @constant */
3314
+ success: true;
3315
+ content: {
3316
+ revoked: number;
3317
+ };
3318
+ };
3319
+ };
3320
+ };
3321
+ };
3322
+ };
3323
+ getAuthSessions: {
3324
+ parameters: { query?: never; header?: never; path?: never; cookie?: never };
3325
+ requestBody?: never;
3326
+ responses: {
3327
+ 200: {
3328
+ headers: { [name: string]: unknown };
3329
+ content: {
3330
+ "application/json": {
3331
+ /** @constant */
3332
+ code: "SDK_SESSIONS_LIST";
3333
+ /** @constant */
3334
+ success: true;
3335
+ content: {
3336
+ sessions: {
3337
+ familyId: string;
3338
+ createdAt: string;
3339
+ lastUsedAt: string | null;
3340
+ userAgent: string | null;
3341
+ ipHash: string | null;
3342
+ deviceLabel: string | null;
3343
+ current: boolean;
3344
+ expiresAt: string;
3345
+ }[];
3346
+ };
3347
+ };
3348
+ };
3349
+ };
3350
+ };
3351
+ };
3352
+ deleteAuthSessionByFamilyId: {
3353
+ parameters: {
3354
+ query?: never;
3355
+ header?: never;
3356
+ path: { familyId: string };
3357
+ cookie?: never;
3358
+ };
3359
+ requestBody?: never;
3360
+ responses: {
3361
+ 200: {
3362
+ headers: { [name: string]: unknown };
3363
+ content: {
3364
+ "application/json": {
3365
+ /** @constant */
3366
+ code: "SDK_SESSION_REVOKED";
3367
+ /** @constant */
3368
+ success: true;
3369
+ content: {
3370
+ revoked: number;
3371
+ };
3372
+ };
3373
+ };
3374
+ };
3375
+ 404: {
3376
+ headers: { [name: string]: unknown };
3377
+ content: {
3378
+ "application/json": {
3379
+ /** @constant */
3380
+ success: false;
3381
+ error: string;
3382
+ };
3383
+ };
3384
+ };
3385
+ };
3386
+ };
2680
3387
  }
2681
3388
 
2682
3389
  type PollarApiClient = ReturnType<typeof createApiClient>;
2683
3390
  declare function createApiClient(baseUrl: string): openapi_fetch.Client<paths, `${string}/${string}`>;
2684
3391
 
2685
- declare function isValidSession(value: unknown): value is PollarApplicationConfigContent;
3392
+ declare function isValidSession(value: unknown): value is PollarPersistedSession;
2686
3393
 
2687
3394
  /**
2688
3395
  * GET /kyc/status
@@ -2761,4 +3468,4 @@ declare function pollRampTransaction(api: PollarApiClient, txId: string, { inter
2761
3468
  timeoutMs?: number;
2762
3469
  }): Promise<RampTxStatus>;
2763
3470
 
2764
- export { AUTH_ERROR_CODES, AlbedoAdapter, type AuthErrorCode, type AuthState, type ConnectWalletResponse, type EscrowAdapter, type EscrowFn, FreighterAdapter, type KycFlow, type KycLevel, type KycProvider, type KycStartBody, type KycStartResponse, type KycStatus, type NetworkState, type PaymentInstructions, type PollarAdapters, type PollarApiClient, type PollarApplicationConfigContent, type PollarApplicationConfigResponse, PollarClient, type PollarClientConfig, PollarFlowError, type PollarLoginOptions, type RampDirection, type RampQuote, type RampTxStatus, type RampsOfframpBody, type RampsOfframpResponse, type RampsOnrampBody, type RampsOnrampResponse, type RampsQuoteQuery, type RampsQuoteResponse, type RampsTransactionResponse, type SignAuthEntryOptions, type SignAuthEntryResponse, type SignTransactionOptions, type SignTransactionResponse, type StellarBalance, StellarClient, type StellarClientConfig, type StellarNetwork, type TransactionState, type TxBuildBody, type TxBuildContent, type TxBuildResponse, type TxHistoryContent, type TxHistoryParams, type TxHistoryRecord, type TxHistoryState, type TxSignAndSendBody, type TxSignSendResponse, type WalletAdapter, type WalletBalanceContent, type WalletBalanceRecord, type WalletBalanceState, WalletType, createOffRamp, createOnRamp, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, pollKycStatus, pollRampTransaction, type paths as pollarPaths, resolveKyc, startKyc };
3471
+ export { AUTH_ERROR_CODES, type AdapterFn, AlbedoAdapter, type AuthErrorCode, type AuthState, type BuildProofArgs, type ConnectWalletResponse, 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 SessionInfo, type SignAuthEntryOptions, type SignAuthEntryResponse, type SignTransactionOptions, type SignTransactionResponse, type StellarBalance, StellarClient, type StellarClientConfig, type StellarNetwork, Storage, type TransactionState, type TxBuildBody, type TxBuildContent, type TxBuildResponse, type TxHistoryContent, type TxHistoryParams, type TxHistoryRecord, type TxHistoryState, type TxSignAndSendBody, type TxSignSendResponse, type WalletAdapter, type WalletAdapterResolver, type WalletBalanceContent, type WalletBalanceRecord, type WalletBalanceState, type WalletId, WalletType, WebCryptoKeyManager, buildProof, canonicalEcJwk, computeJwkThumbprint, createLocalStorageAdapter, createMemoryAdapter, createOffRamp, createOnRamp, defaultKeyManager, defaultStorage, getKycProviders, getKycStatus, getRampTransaction, getRampsQuote, isValidSession, normalizeHtu, pollKycStatus, pollRampTransaction, type paths as pollarPaths, resolveKyc, startKyc };