@dexterai/connect 0.2.0 → 0.4.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.
@@ -228,9 +228,198 @@ function createPasskeySigner(vault, apiBase, opts = {}) {
228
228
  });
229
229
  }
230
230
 
231
+ // src/walletStore.ts
232
+ var ACTIVE_HANDLE_KEY = "dexter:passkey:userHandle";
233
+ var ROSTER_KEY = "dexter:passkey:wallets";
234
+ var listeners = /* @__PURE__ */ new Set();
235
+ function hasStorage() {
236
+ try {
237
+ return typeof window !== "undefined" && !!window.localStorage;
238
+ } catch {
239
+ return false;
240
+ }
241
+ }
242
+ function readRoster() {
243
+ if (!hasStorage()) return [];
244
+ try {
245
+ const raw = window.localStorage.getItem(ROSTER_KEY);
246
+ if (!raw) return [];
247
+ const parsed = JSON.parse(raw);
248
+ if (!Array.isArray(parsed)) return [];
249
+ return parsed.filter(
250
+ (w) => !!w && typeof w === "object" && typeof w.handle === "string"
251
+ );
252
+ } catch {
253
+ return [];
254
+ }
255
+ }
256
+ function writeRoster(wallets) {
257
+ if (!hasStorage()) return;
258
+ try {
259
+ window.localStorage.setItem(ROSTER_KEY, JSON.stringify(wallets));
260
+ } catch {
261
+ }
262
+ }
263
+ function emit() {
264
+ for (const l of listeners) {
265
+ try {
266
+ l();
267
+ } catch {
268
+ }
269
+ }
270
+ }
271
+ function getActiveHandle() {
272
+ if (!hasStorage()) return null;
273
+ try {
274
+ return window.localStorage.getItem(ACTIVE_HANDLE_KEY);
275
+ } catch {
276
+ return null;
277
+ }
278
+ }
279
+ function setActiveHandle(handle, label, credentialId) {
280
+ if (!hasStorage() || !handle) return;
281
+ try {
282
+ window.localStorage.setItem(ACTIVE_HANDLE_KEY, handle);
283
+ } catch {
284
+ return;
285
+ }
286
+ const roster = readRoster();
287
+ const existing = roster.find((w) => w.handle === handle);
288
+ const now = Date.now();
289
+ if (existing) {
290
+ existing.lastUsedAt = now;
291
+ if (label !== void 0) existing.label = label;
292
+ if (credentialId !== void 0) existing.credentialId = credentialId;
293
+ } else {
294
+ roster.push({ handle, label, credentialId, lastUsedAt: now });
295
+ }
296
+ writeRoster(roster);
297
+ emit();
298
+ }
299
+ function getCredentialId(handle) {
300
+ return readRoster().find((w) => w.handle === handle)?.credentialId;
301
+ }
302
+ function ejectActiveWallet(opts) {
303
+ if (!hasStorage()) return;
304
+ const current = getActiveHandle();
305
+ try {
306
+ window.localStorage.removeItem(ACTIVE_HANDLE_KEY);
307
+ } catch {
308
+ }
309
+ if (opts?.forget && current) {
310
+ writeRoster(readRoster().filter((w) => w.handle !== current));
311
+ }
312
+ emit();
313
+ }
314
+ function listWallets() {
315
+ return readRoster().sort((a, b) => (b.lastUsedAt ?? 0) - (a.lastUsedAt ?? 0));
316
+ }
317
+ function switchWallet(handle) {
318
+ if (!readRoster().some((w) => w.handle === handle)) return false;
319
+ setActiveHandle(handle);
320
+ return true;
321
+ }
322
+ function forgetWallet(handle) {
323
+ if (getActiveHandle() === handle) {
324
+ ejectActiveWallet({ forget: true });
325
+ return;
326
+ }
327
+ writeRoster(readRoster().filter((w) => w.handle !== handle));
328
+ emit();
329
+ }
330
+ function subscribe(listener) {
331
+ listeners.add(listener);
332
+ if (hasStorage() && listeners.size === 1) {
333
+ window.addEventListener("storage", onStorageEvent);
334
+ }
335
+ return () => {
336
+ listeners.delete(listener);
337
+ if (hasStorage() && listeners.size === 0) {
338
+ window.removeEventListener("storage", onStorageEvent);
339
+ }
340
+ };
341
+ }
342
+ function onStorageEvent(e) {
343
+ if (e.key === ACTIVE_HANDLE_KEY || e.key === ROSTER_KEY || e.key === null) emit();
344
+ }
345
+ var ACTIVE_WALLET_STORAGE_KEY = ACTIVE_HANDLE_KEY;
346
+
347
+ // src/signals.ts
348
+ function pkc() {
349
+ if (typeof window === "undefined") return null;
350
+ const g = globalThis.PublicKeyCredential;
351
+ return g ?? null;
352
+ }
353
+ function defaultRpId() {
354
+ return typeof window !== "undefined" ? window.location.hostname : "";
355
+ }
356
+ function passkeySignalSupport() {
357
+ const p = pkc();
358
+ return {
359
+ rename: typeof p?.signalCurrentUserDetails === "function",
360
+ prune: typeof p?.signalUnknownCredential === "function",
361
+ syncAccepted: typeof p?.signalAllAcceptedCredentials === "function"
362
+ };
363
+ }
364
+ async function renamePasskey(args) {
365
+ const p = pkc();
366
+ if (typeof p?.signalCurrentUserDetails !== "function") return false;
367
+ try {
368
+ await p.signalCurrentUserDetails({
369
+ rpId: args.rpId ?? defaultRpId(),
370
+ userId: args.userId,
371
+ name: args.name,
372
+ displayName: args.displayName ?? args.name
373
+ });
374
+ return true;
375
+ } catch {
376
+ return false;
377
+ }
378
+ }
379
+ async function prunePasskey(args) {
380
+ const p = pkc();
381
+ if (typeof p?.signalUnknownCredential !== "function") return false;
382
+ try {
383
+ await p.signalUnknownCredential({
384
+ rpId: args.rpId ?? defaultRpId(),
385
+ credentialId: args.credentialId
386
+ });
387
+ return true;
388
+ } catch {
389
+ return false;
390
+ }
391
+ }
392
+ async function syncAcceptedPasskeys(args) {
393
+ const p = pkc();
394
+ if (typeof p?.signalAllAcceptedCredentials !== "function") return false;
395
+ try {
396
+ await p.signalAllAcceptedCredentials({
397
+ rpId: args.rpId ?? defaultRpId(),
398
+ userId: args.userId,
399
+ allAcceptedCredentialIds: args.acceptedCredentialIds
400
+ });
401
+ return true;
402
+ } catch {
403
+ return false;
404
+ }
405
+ }
406
+
231
407
  export {
232
408
  ConnectError,
233
409
  passkeyLogin,
234
410
  createAnonServerPolicy,
235
- createPasskeySigner
411
+ createPasskeySigner,
412
+ getActiveHandle,
413
+ setActiveHandle,
414
+ getCredentialId,
415
+ ejectActiveWallet,
416
+ listWallets,
417
+ switchWallet,
418
+ forgetWallet,
419
+ subscribe,
420
+ ACTIVE_WALLET_STORAGE_KEY,
421
+ passkeySignalSupport,
422
+ renamePasskey,
423
+ prunePasskey,
424
+ syncAcceptedPasskeys
236
425
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DexterConnectConfig, S as SignInResult, C as ConnectVault } from './types---RcNI2Y.js';
2
- export { a as ConnectError, P as PasskeyLoginTokens } from './types---RcNI2Y.js';
1
+ import { D as DexterConnectConfig, S as SignInResult, C as ConnectVault } from './signals-CkBFwCNw.js';
2
+ export { A as ACTIVE_WALLET_STORAGE_KEY, a as ConnectError, P as PasskeyLoginTokens, b as PasskeySignalSupport, c as StoredWallet, e as ejectActiveWallet, f as forgetWallet, g as getActiveHandle, d as getCredentialId, l as listWallets, p as passkeySignalSupport, h as prunePasskey, r as renamePasskey, s as setActiveHandle, i as subscribeWallet, j as switchWallet, k as syncAcceptedPasskeys } from './signals-CkBFwCNw.js';
3
3
  import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
4
4
 
5
5
  /**
package/dist/index.js CHANGED
@@ -1,12 +1,38 @@
1
1
  import {
2
+ ACTIVE_WALLET_STORAGE_KEY,
2
3
  ConnectError,
3
4
  createAnonServerPolicy,
4
5
  createPasskeySigner,
5
- passkeyLogin
6
- } from "./chunk-46P7XAAI.js";
6
+ ejectActiveWallet,
7
+ forgetWallet,
8
+ getActiveHandle,
9
+ getCredentialId,
10
+ listWallets,
11
+ passkeyLogin,
12
+ passkeySignalSupport,
13
+ prunePasskey,
14
+ renamePasskey,
15
+ setActiveHandle,
16
+ subscribe,
17
+ switchWallet,
18
+ syncAcceptedPasskeys
19
+ } from "./chunk-2V6EGIHV.js";
7
20
  export {
21
+ ACTIVE_WALLET_STORAGE_KEY,
8
22
  ConnectError,
9
23
  createAnonServerPolicy,
10
24
  createPasskeySigner,
11
- passkeyLogin
25
+ ejectActiveWallet,
26
+ forgetWallet,
27
+ getActiveHandle,
28
+ getCredentialId,
29
+ listWallets,
30
+ passkeyLogin,
31
+ passkeySignalSupport,
32
+ prunePasskey,
33
+ renamePasskey,
34
+ setActiveHandle,
35
+ subscribe as subscribeWallet,
36
+ switchWallet,
37
+ syncAcceptedPasskeys
12
38
  };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
2
- import { S as SignInResult, P as PasskeyLoginTokens, C as ConnectVault, a as ConnectError } from './types---RcNI2Y.js';
2
+ import { S as SignInResult, P as PasskeyLoginTokens, C as ConnectVault, a as ConnectError, c as StoredWallet, b as PasskeySignalSupport } from './signals-CkBFwCNw.js';
3
3
  import { ReactElement } from 'react';
4
4
 
5
5
  type ConnectStatus = 'idle' | 'pending' | 'done' | 'error';
@@ -64,4 +64,34 @@ interface SignInWithDexterProps extends UseSignInWithDexterConfig {
64
64
  */
65
65
  declare function SignInWithDexter(props: SignInWithDexterProps): ReactElement | null;
66
66
 
67
- export { type ConnectStatus, SignInWithDexter, type SignInWithDexterProps, type UseSignInWithDexter, type UseSignInWithDexterConfig, useSignInWithDexter };
67
+ interface UseDexterWallet {
68
+ /** Active wallet handle, or null if this browser has no active wallet. */
69
+ activeHandle: string | null;
70
+ /** Known wallets on this browser, most-recently-used first. */
71
+ wallets: StoredWallet[];
72
+ /** What the WebAuthn Signal API supports in THIS browser (rename / prune). */
73
+ support: PasskeySignalSupport;
74
+ /**
75
+ * Eject the active wallet — "switch / start fresh". Clears the local binding
76
+ * and, where supported, prunes the old passkey from the OS manager so it
77
+ * disappears from the user's list. `{ forget: true }` also drops it from the
78
+ * roster.
79
+ */
80
+ eject: (opts?: {
81
+ forget?: boolean;
82
+ }) => void;
83
+ /** Switch the active wallet to a known handle. No-op if unknown. */
84
+ switchTo: (handle: string) => boolean;
85
+ /** Record/activate a handle (after enroll or recover). Prefer over writing
86
+ * localStorage by hand so the roster + subscribers stay correct. */
87
+ setActive: (handle: string, label?: string, credentialId?: string) => void;
88
+ /**
89
+ * Rename the ACTIVE passkey in the OS keychain (post-creation). Returns true
90
+ * if the browser supported it and the signal fired; false otherwise (the
91
+ * keychain entry is then just left as-is).
92
+ */
93
+ rename: (name: string, displayName?: string) => Promise<boolean>;
94
+ }
95
+ declare function useDexterWallet(): UseDexterWallet;
96
+
97
+ export { type ConnectStatus, SignInWithDexter, type SignInWithDexterProps, type UseDexterWallet, type UseSignInWithDexter, type UseSignInWithDexterConfig, useDexterWallet, useSignInWithDexter };
package/dist/react.js CHANGED
@@ -1,8 +1,18 @@
1
1
  import {
2
2
  ConnectError,
3
3
  createPasskeySigner,
4
- passkeyLogin
5
- } from "./chunk-46P7XAAI.js";
4
+ ejectActiveWallet,
5
+ getActiveHandle,
6
+ getCredentialId,
7
+ listWallets,
8
+ passkeyLogin,
9
+ passkeySignalSupport,
10
+ prunePasskey,
11
+ renamePasskey,
12
+ setActiveHandle,
13
+ subscribe,
14
+ switchWallet
15
+ } from "./chunk-2V6EGIHV.js";
6
16
 
7
17
  // src/useSignInWithDexter.ts
8
18
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -198,7 +208,51 @@ var DISCONNECT = {
198
208
  lineHeight: 1,
199
209
  opacity: 0.6
200
210
  };
211
+
212
+ // src/useDexterWallet.ts
213
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
214
+ var NO_SUPPORT = { rename: false, prune: false, syncAccepted: false };
215
+ function useDexterWallet() {
216
+ const [activeHandle, setHandle] = useState2(() => getActiveHandle());
217
+ const [wallets, setWallets] = useState2(() => listWallets());
218
+ const [support, setSupport] = useState2(NO_SUPPORT);
219
+ useEffect2(() => {
220
+ const sync = () => {
221
+ setHandle(getActiveHandle());
222
+ setWallets(listWallets());
223
+ };
224
+ setSupport(passkeySignalSupport());
225
+ sync();
226
+ return subscribe(sync);
227
+ }, []);
228
+ const eject = useCallback2((opts) => {
229
+ const handle = getActiveHandle();
230
+ const credentialId = handle ? getCredentialId(handle) : void 0;
231
+ ejectActiveWallet(opts);
232
+ if (credentialId) void prunePasskey({ credentialId });
233
+ }, []);
234
+ const rename = useCallback2(async (name, displayName) => {
235
+ const handle = getActiveHandle();
236
+ if (!handle) return false;
237
+ const ok = await renamePasskey({ userId: handle, name, displayName });
238
+ if (ok) setActiveHandle(handle, name);
239
+ return ok;
240
+ }, []);
241
+ return {
242
+ activeHandle,
243
+ wallets,
244
+ support,
245
+ eject,
246
+ switchTo: useCallback2((handle) => switchWallet(handle), []),
247
+ setActive: useCallback2(
248
+ (handle, label, credentialId) => setActiveHandle(handle, label, credentialId),
249
+ []
250
+ ),
251
+ rename
252
+ };
253
+ }
201
254
  export {
202
255
  SignInWithDexter,
256
+ useDexterWallet,
203
257
  useSignInWithDexter
204
258
  };
@@ -0,0 +1,142 @@
1
+ /** Supabase session tokens returned by dexter-api's passkey-login (camelCase). */
2
+ interface PasskeyLoginTokens {
3
+ accessToken: string;
4
+ refreshToken: string;
5
+ expiresAt: number;
6
+ expiresIn: number;
7
+ tokenType: string;
8
+ }
9
+ /**
10
+ * Vault identity, returned ALONGSIDE the session by passkey-login once
11
+ * vault-review ships the dexter-api change (ASK 1). Optional until then —
12
+ * the connector degrades to session-only. Consumers that open x402 tabs
13
+ * (dexter-agents) need `vaultPda` + `publicKey` to build a passkey signer.
14
+ */
15
+ interface ConnectVault {
16
+ vaultPda: string;
17
+ /** Swig state address, base58 — the user-facing Dexter Wallet address. */
18
+ swigAddress: string;
19
+ /** v2 swig wallet PDA (deposit address); null until the swig is deployed. */
20
+ receiveAddress: string | null;
21
+ /** Swig wallet's USDC ATA, base58 (for the connected-chip balance read);
22
+ * null until the swig is deployed. Server-resolved (off-curve-safe). */
23
+ usdcAta: string | null;
24
+ /** base64 33-byte SEC1 compressed P-256 authority pubkey (for the signer). */
25
+ publicKey: string;
26
+ userHandle: string;
27
+ credentialId: string;
28
+ }
29
+ /** Result of a completed "Sign in with Dexter" ceremony. */
30
+ interface SignInResult {
31
+ session: PasskeyLoginTokens;
32
+ /** Present once vault-review ships the vault-in-login change. */
33
+ vault?: ConnectVault;
34
+ }
35
+ interface DexterConnectConfig {
36
+ /** dexter-api base. Default https://api.dexter.cash. */
37
+ apiBase?: string;
38
+ }
39
+ /** Typed error whose `code` is the server's snake_case error string. */
40
+ declare class ConnectError extends Error {
41
+ readonly code: string;
42
+ constructor(code: string, message?: string);
43
+ }
44
+
45
+ /** A wallet this browser knows about. `handle` is the identity; the rest is UX. */
46
+ interface StoredWallet {
47
+ /** base64url 16-byte user handle — the vault identity. */
48
+ handle: string;
49
+ /** Human label for switch UIs (e.g. an email, or "Dexter Wallet"). */
50
+ label?: string;
51
+ /** base64url credential id — enables the WebAuthn Signal API to prune this
52
+ * passkey from the OS manager on eject (see ./signals). */
53
+ credentialId?: string;
54
+ /** Epoch ms of last activation — for ordering the switcher. */
55
+ lastUsedAt?: number;
56
+ }
57
+ type Listener = () => void;
58
+ /** The active wallet handle, or null if this browser has no active wallet. */
59
+ declare function getActiveHandle(): string | null;
60
+ /**
61
+ * Set the active wallet handle (e.g. after enroll or recover), upserting it into
62
+ * the roster with a fresh `lastUsedAt`. Idempotent. Fires subscribers.
63
+ */
64
+ declare function setActiveHandle(handle: string, label?: string, credentialId?: string): void;
65
+ /** Look up a known wallet's stored credentialId (for Signal-API prune on eject). */
66
+ declare function getCredentialId(handle: string): string | undefined;
67
+ /**
68
+ * EJECT — clear the active wallet so the browser is no longer bound to it. This
69
+ * is "switch / start fresh / sign out of this wallet". The wallet stays in the
70
+ * roster (so the user can switch back) unless `forget` is true. After eject,
71
+ * `getActiveHandle()` is null and the next enroll/recover starts clean. Fires
72
+ * subscribers. This is the function whose absence WAS the welded-wallet bug.
73
+ */
74
+ declare function ejectActiveWallet(opts?: {
75
+ forget?: boolean;
76
+ }): void;
77
+ /** Every wallet this browser knows about, most-recently-used first. */
78
+ declare function listWallets(): StoredWallet[];
79
+ /**
80
+ * Switch the active wallet to a handle ALREADY in the roster. Returns false (and
81
+ * does nothing) if the handle is unknown — switching is only ever to a wallet
82
+ * this browser has seen, never to an arbitrary string.
83
+ */
84
+ declare function switchWallet(handle: string): boolean;
85
+ /** Remove a wallet from the roster entirely; clears active if it was active. */
86
+ declare function forgetWallet(handle: string): void;
87
+ /**
88
+ * Subscribe to active-wallet/roster changes. Returns an unsubscribe fn. Also
89
+ * wires the cross-tab `storage` event once, so ejecting in one tab updates the
90
+ * others. The React hook (`useDexterWallet`) is a thin wrapper over this.
91
+ */
92
+ declare function subscribe(listener: Listener): () => void;
93
+ /** Exposed for consumers that must reference the canonical key (migrations,
94
+ * tests). Prefer the accessors above — do NOT read localStorage by hand. */
95
+ declare const ACTIVE_WALLET_STORAGE_KEY = "dexter:passkey:userHandle";
96
+
97
+ interface PasskeySignalSupport {
98
+ /** signalCurrentUserDetails — rename a passkey post-creation. */
99
+ rename: boolean;
100
+ /** signalUnknownCredential — remove one stale passkey from the manager. */
101
+ prune: boolean;
102
+ /** signalAllAcceptedCredentials — reconcile the full valid set. */
103
+ syncAccepted: boolean;
104
+ }
105
+ /**
106
+ * What the CURRENT browser supports, by direct feature-detection. Instant, no
107
+ * network, no UA sniffing — tells you exactly what will light up on THIS device
108
+ * (e.g. call once on Branch's iPhone to learn its Safari's status).
109
+ */
110
+ declare function passkeySignalSupport(): PasskeySignalSupport;
111
+ /**
112
+ * Rename a passkey in the OS keychain AFTER creation. `userId` is the base64url
113
+ * user handle; `rpId` defaults to the current host. Returns true if the signal
114
+ * fired, false if unsupported/failed (caller treats false as "left as-is").
115
+ */
116
+ declare function renamePasskey(args: {
117
+ userId: string;
118
+ name: string;
119
+ displayName?: string;
120
+ rpId?: string;
121
+ }): Promise<boolean>;
122
+ /**
123
+ * Tell the OS manager a credential is gone so it removes that passkey from the
124
+ * user's list — the welded-old-wallet auto-cleanup. `credentialId` is base64url.
125
+ * Returns true if fired, false if unsupported/failed.
126
+ */
127
+ declare function prunePasskey(args: {
128
+ credentialId: string;
129
+ rpId?: string;
130
+ }): Promise<boolean>;
131
+ /**
132
+ * Declare the FULL set of still-valid credential IDs for a user; the manager
133
+ * prunes anything not listed. Use after sign-in or eject to reconcile in one
134
+ * shot (pass `[]` to clear all of a user's passkeys). Returns true if fired.
135
+ */
136
+ declare function syncAcceptedPasskeys(args: {
137
+ userId: string;
138
+ acceptedCredentialIds: string[];
139
+ rpId?: string;
140
+ }): Promise<boolean>;
141
+
142
+ export { ACTIVE_WALLET_STORAGE_KEY as A, type ConnectVault as C, type DexterConnectConfig as D, type PasskeyLoginTokens as P, type SignInResult as S, ConnectError as a, type PasskeySignalSupport as b, type StoredWallet as c, getCredentialId as d, ejectActiveWallet as e, forgetWallet as f, getActiveHandle as g, prunePasskey as h, subscribe as i, switchWallet as j, syncAcceptedPasskeys as k, listWallets as l, passkeySignalSupport as p, renamePasskey as r, setActiveHandle as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/connect",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Sign in with Dexter — passkey connector. Composes @dexterai/vault.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,45 +0,0 @@
1
- /** Supabase session tokens returned by dexter-api's passkey-login (camelCase). */
2
- interface PasskeyLoginTokens {
3
- accessToken: string;
4
- refreshToken: string;
5
- expiresAt: number;
6
- expiresIn: number;
7
- tokenType: string;
8
- }
9
- /**
10
- * Vault identity, returned ALONGSIDE the session by passkey-login once
11
- * vault-review ships the dexter-api change (ASK 1). Optional until then —
12
- * the connector degrades to session-only. Consumers that open x402 tabs
13
- * (dexter-agents) need `vaultPda` + `publicKey` to build a passkey signer.
14
- */
15
- interface ConnectVault {
16
- vaultPda: string;
17
- /** Swig state address, base58 — the user-facing Dexter Wallet address. */
18
- swigAddress: string;
19
- /** v2 swig wallet PDA (deposit address); null until the swig is deployed. */
20
- receiveAddress: string | null;
21
- /** Swig wallet's USDC ATA, base58 (for the connected-chip balance read);
22
- * null until the swig is deployed. Server-resolved (off-curve-safe). */
23
- usdcAta: string | null;
24
- /** base64 33-byte SEC1 compressed P-256 authority pubkey (for the signer). */
25
- publicKey: string;
26
- userHandle: string;
27
- credentialId: string;
28
- }
29
- /** Result of a completed "Sign in with Dexter" ceremony. */
30
- interface SignInResult {
31
- session: PasskeyLoginTokens;
32
- /** Present once vault-review ships the vault-in-login change. */
33
- vault?: ConnectVault;
34
- }
35
- interface DexterConnectConfig {
36
- /** dexter-api base. Default https://api.dexter.cash. */
37
- apiBase?: string;
38
- }
39
- /** Typed error whose `code` is the server's snake_case error string. */
40
- declare class ConnectError extends Error {
41
- readonly code: string;
42
- constructor(code: string, message?: string);
43
- }
44
-
45
- export { type ConnectVault as C, type DexterConnectConfig as D, type PasskeyLoginTokens as P, type SignInResult as S, ConnectError as a };