@dexterai/connect 0.24.1 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,226 @@
1
+ import { S as SignInResult, C as CreateWalletResult, a as CreateWalletConfig, b as CeremonyPhase, D as DexterConnectConfig, c as ConnectVault, R as RecoverWalletConfig, d as RecoverOutcome, I as IdentityKind } from './signals-C05rIVey.js';
2
+ export { A as ACTIVE_WALLET_STORAGE_KEY, e as ConnectError, f as IdentityInput, P as PasskeyLoginTokens, g as PasskeySignalSupport, h as RecoverVault, i as ResolvedIdentity, j as SESSION_TTL_30D, k as SpendPolicy, l as StoredWallet, m as authoredPolicy, n as createWallet, o as ejectActiveWallet, p as forgetWallet, q as getActiveHandle, r as getCredentialId, s as listWallets, t as passkeySignalSupport, u as prunePasskey, v as renamePasskey, w as resolveIdentity, x as setActiveHandle, y as subscribeWallet, z as switchWallet, B as syncAcceptedPasskeys, E as usdToAtomic } from './signals-C05rIVey.js';
3
+ import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
4
+
5
+ /**
6
+ * "Sign in with Dexter" — the discoverable-credential login ceremony.
7
+ *
8
+ * 1. POST /login-challenge → a server-issued challenge (no allow-list:
9
+ * the resident passkey itself identifies the user)
10
+ * 2. navigator.credentials.get over that challenge (no allowCredentials)
11
+ * 3. POST /passkey-login → the server resolves the credential + vault,
12
+ * verifies the assertion, and returns a Supabase session (+ the vault
13
+ * payload once vault-review ships the dexter-api change — ASK 1)
14
+ *
15
+ * Relays to dexter-api's ANON router — a first-time third-party user has no
16
+ * Supabase session, so the Supabase-gated router would 401.
17
+ */
18
+ declare function passkeyLogin(config?: DexterConnectConfig, onPhase?: (phase: CeremonyPhase) => void): Promise<SignInResult>;
19
+ type ContinueResult = ({
20
+ kind: 'signin';
21
+ } & SignInResult) | ({
22
+ kind: 'create';
23
+ } & CreateWalletResult);
24
+ declare function continueWithDexter(config?: CreateWalletConfig, onPhase?: (phase: CeremonyPhase) => void): Promise<ContinueResult>;
25
+
26
+ /** What `issueChallenge` returns to the SDK signer. */
27
+ interface AnonChallengeResult {
28
+ /** Server-issued WebAuthn challenge (=== the supplied operationHash). */
29
+ challenge: Uint8Array;
30
+ /** Credential id the server resolved from the userHandle (allowCredentials[0]). */
31
+ credentialId: Uint8Array;
32
+ rpId?: string;
33
+ transports?: AuthenticatorTransport[];
34
+ }
35
+ /** The policy the SDK's guest `DexterApiBrowserPasskeySigner` consumes. */
36
+ interface AnonServerPolicy {
37
+ issueChallenge(args: {
38
+ userHandle: Uint8Array;
39
+ operationHash: Uint8Array;
40
+ }): Promise<AnonChallengeResult>;
41
+ verify(args: {
42
+ userHandle: Uint8Array;
43
+ credentialId: Uint8Array;
44
+ signature: Uint8Array;
45
+ clientDataJSON: Uint8Array;
46
+ authenticatorData: Uint8Array;
47
+ }): Promise<void>;
48
+ }
49
+ /**
50
+ * Build the anon ServerPolicy for a given dexter-api base.
51
+ *
52
+ * `issueChallenge` → POST /challenge { userHandle, operationHash } (both base64url).
53
+ * The server uses operationHash AS the WebAuthn challenge (replay binding +
54
+ * the on-chain webauthn.rs law: clientDataJSON.challenge === sha256(op)) and
55
+ * resolves the credential into options.allowCredentials[0].
56
+ * `verify` → POST /verify { credential, userHandle }. NOTE: the SDK hands us the
57
+ * COMPACT 64-byte signature; dexter-api's WebAuthn verifier wants DER, so we
58
+ * re-encode compact → DER here (compactSignatureToDer).
59
+ */
60
+ declare function createAnonServerPolicy(apiBase?: string): AnonServerPolicy;
61
+
62
+ /** Test seam mirroring the SDK's injected-assertion shape (production omits it). */
63
+ type AssertionLike = {
64
+ credentialId: Uint8Array;
65
+ assertOver(challenge: Uint8Array): Promise<{
66
+ signature: Uint8Array;
67
+ clientDataJSON: Uint8Array;
68
+ authenticatorData: Uint8Array;
69
+ }>;
70
+ };
71
+ /**
72
+ * Construct the guest signer from a connected `ConnectVault`.
73
+ *
74
+ * `vault.publicKey` is base64 (33-byte SEC1 compressed P-256); `vault.userHandle`
75
+ * is base64url (server-minted). Both are decoded to the Uint8Arrays the SDK wants.
76
+ *
77
+ * @param vault the connected vault from useSignInWithDexter()
78
+ * @param apiBase dexter-api base (defaults to https://api.dexter.cash via the policy)
79
+ * @param opts.__assertion test-only injected assertion (skips real WebAuthn)
80
+ */
81
+ declare function createPasskeySigner(vault: ConnectVault, apiBase?: string, opts?: {
82
+ __assertion?: AssertionLike;
83
+ }): DexterApiBrowserPasskeySigner;
84
+
85
+ declare function recoverWallet(config?: RecoverWalletConfig): Promise<RecoverOutcome>;
86
+
87
+ /**
88
+ * Human-readable label for a ceremony phase — the live "connecting step" copy.
89
+ * ONE source of truth so sign-in (SignInWithDexter) and create (consumer setup
90
+ * flows) show identical wording. Consumers surfacing createWallet's `onPhase`
91
+ * should use this instead of hand-rolling their own strings (Rule #7).
92
+ */
93
+ declare function ceremonyPhaseLabel(phase: CeremonyPhase): string;
94
+
95
+ /** The automatic role-2 agent-spend rail. */
96
+ interface AutomaticAgentSpend {
97
+ /** true = agent-spend is ON (not revoked). Derived from revokedAt === null. */
98
+ active: boolean;
99
+ /** ISO timestamp the rail was revoked, or null when active. */
100
+ revokedAt: string | null;
101
+ /**
102
+ * On-chain role-2 arm state, decoded from authority.signer by the backend:
103
+ * true = armed (the rail is live and can spend)
104
+ * false = dormant (granted but not yet armed — arms on first pay)
105
+ * null = indeterminate (vault not activated, or a transient chain read failed)
106
+ * NEVER derived from liveSessionCount (that counts the wrong session model).
107
+ */
108
+ armed: boolean | null;
109
+ spentTodayAtomic?: string;
110
+ dailyCapAtomic?: string;
111
+ perCallCapAtomic?: string;
112
+ lifetimeSpentAtomic?: string;
113
+ }
114
+ /** One explicit user-opened Tab (a V6 per-counterparty session). */
115
+ interface AgentSpendTab {
116
+ /** The session pubkey — the handle a Tab revoke targets. */
117
+ id: string;
118
+ /** The counterparty (agent/app) address this Tab authorizes. */
119
+ counterparty: string;
120
+ /** Display label: the Dexter-verified app name, else a shortened address. */
121
+ label: string;
122
+ /** Whether the Tab is currently live (not expired/spent-out/revoked). */
123
+ live: boolean;
124
+ /** Spent so far against this Tab's cap, atomic USDC (6dp) string. */
125
+ spentAtomic: string;
126
+ /** This Tab's spending cap, atomic USDC (6dp) string. */
127
+ capAtomic: string;
128
+ /** Unix seconds when the Tab expires. */
129
+ expiresAt: number;
130
+ }
131
+ /** The honest two-mode status: one balance, two separately-accounted rails. */
132
+ interface AgentSpendStatus {
133
+ /** Vault USDC balance, atomic (6dp) string — the ONE pool both rails draw. */
134
+ balanceAtomic: string | null;
135
+ /** The automatic role-2 rail. */
136
+ automatic: AutomaticAgentSpend;
137
+ /** The explicit Tabs. */
138
+ tabs: AgentSpendTab[];
139
+ }
140
+ /** The fields of GET /status the two-mode read consumes. */
141
+ interface RawAgentSpendStatus {
142
+ /** ISO timestamp when revoked, null when active. Top-level on /status. */
143
+ agentSpendRevokedAt?: string | null;
144
+ /** On-chain armed read (authority.signer). true/false/null. Top-level on /status. */
145
+ agentSpendArmed?: boolean | null;
146
+ /** On-chain block; usdcAtomic is the vault balance. */
147
+ onchain?: {
148
+ usdcAtomic?: string | null;
149
+ /** Present but DELIBERATELY UNUSED here — counts the wrong session model. */
150
+ liveSessionCount?: number;
151
+ } | null;
152
+ agentSpendDaily?: {
153
+ spentTodayAtomic?: string;
154
+ dailyCapAtomic?: string;
155
+ perCallCapAtomic?: string;
156
+ lifetimeSpentAtomic?: string;
157
+ } | null;
158
+ }
159
+ /** The fields of one GET /sessions row the Tabs rail consumes. */
160
+ interface RawAgentSpendSession {
161
+ sessionPubkey: string;
162
+ counterparty: string;
163
+ appName?: string | null;
164
+ live: boolean;
165
+ spent: string;
166
+ maxAmount: string;
167
+ expiresAt: number;
168
+ }
169
+ /**
170
+ * Assemble the honest two-mode agent-spend status from the raw /status response
171
+ * and the raw /sessions rows. Pure: no fetch, no clock, no I/O.
172
+ */
173
+ declare function assembleAgentSpendStatus(status: RawAgentSpendStatus, sessions?: RawAgentSpendSession[]): AgentSpendStatus;
174
+ /**
175
+ * The minimal identity the off/on switch needs: WHO is active + the wallet
176
+ * handle the anon router keys on. Structurally satisfied by connect's
177
+ * ResolvedIdentity (pass it straight through), or hand-build `{ kind, userHandle }`.
178
+ */
179
+ interface AgentSpendIdentity {
180
+ /** Passkey-vault-first identity axis. Agent-spend is Dexter-Wallet-only. */
181
+ kind: IdentityKind;
182
+ /** The passkey-vault user handle the anon router addresses, or null. */
183
+ userHandle: string | null;
184
+ }
185
+ /** Typed error whose `code` is the server's snake_case error string. */
186
+ declare class AgentSpendError extends Error {
187
+ readonly code: string;
188
+ constructor(code: string, message?: string);
189
+ }
190
+ /** Map an AgentSpendError.code to plain, user-facing copy. */
191
+ declare function describeAgentSpendError(code: string): string;
192
+ interface RevokeAgentSpendResult {
193
+ revoked: boolean;
194
+ }
195
+ /**
196
+ * Revoke the AUTOMATIC role-2 agent-spend rail — the off-switch. Takes effect on
197
+ * the very next agent payment (the spend path reads agent_spend_revoked_at fresh
198
+ * per spend). Dexter-Wallet (anon-vault) only; `credentialId` (base64url) targets
199
+ * the biometric prompt.
200
+ *
201
+ * @param id WHO is active — must be the passkey-vault (Dexter Wallet).
202
+ * @param vaultPda The vault PDA, base58 string. Becomes the signed message.
203
+ * @param apiOrigin The dexter-api origin (e.g. https://api.dexter.cash). The
204
+ * caller owns env; connect reads none.
205
+ * @param credentialId The wallet's passkey credential id (base64url), to make
206
+ * the assertion a direct biometric, not an account picker.
207
+ */
208
+ declare function revokeAgentSpend(id: AgentSpendIdentity, vaultPda: string, apiOrigin: string, credentialId?: string | null): Promise<RevokeAgentSpendResult>;
209
+ interface EnableAgentSpendResult {
210
+ enabled: boolean;
211
+ }
212
+ /**
213
+ * Re-enable the AUTOMATIC role-2 agent-spend rail — the ON switch. Turning spend
214
+ * back ON is the dangerous direction, so it is a two-step, replay-protected nonce
215
+ * flow: fetch a server-minted nonce+expiry (inert until redeemed), sign
216
+ * enableAgentSpendMessage over those EXACT values as the WebAuthn challenge,
217
+ * submit. Dexter-Wallet (anon-vault) only.
218
+ *
219
+ * @param id WHO is active — must be the passkey-vault (Dexter Wallet).
220
+ * @param vaultPda The vault PDA, base58 string.
221
+ * @param apiOrigin The dexter-api origin (e.g. https://api.dexter.cash).
222
+ * @param credentialId The wallet's passkey credential id (base64url).
223
+ */
224
+ declare function enableAgentSpend(id: AgentSpendIdentity, vaultPda: string, apiOrigin: string, credentialId?: string | null): Promise<EnableAgentSpendResult>;
225
+
226
+ export { AgentSpendError, type AgentSpendIdentity, type AgentSpendStatus, type AgentSpendTab, type AnonChallengeResult, type AnonServerPolicy, type AutomaticAgentSpend, CeremonyPhase, ConnectVault, type ContinueResult, CreateWalletConfig, CreateWalletResult, DexterConnectConfig, type EnableAgentSpendResult, IdentityKind, type RawAgentSpendSession, type RawAgentSpendStatus, RecoverOutcome, RecoverWalletConfig, type RevokeAgentSpendResult, SignInResult, assembleAgentSpendStatus, ceremonyPhaseLabel, continueWithDexter, createAnonServerPolicy, createPasskeySigner, describeAgentSpendError, enableAgentSpend, passkeyLogin, recoverWallet, revokeAgentSpend };
@@ -0,0 +1,263 @@
1
+ import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
2
+ import { b as CeremonyPhase, S as SignInResult, d as RecoverOutcome, P as PasskeyLoginTokens, c as ConnectVault, e as ConnectError, l as StoredWallet, g as PasskeySignalSupport, i as ResolvedIdentity, C as CreateWalletResult } from './signals-C05rIVey.js';
3
+ export { h as RecoverVault } from './signals-C05rIVey.js';
4
+ import { ReactElement, ButtonHTMLAttributes, ReactNode } from 'react';
5
+
6
+ type ConnectStatus = 'idle' | 'pending' | 'done' | 'error';
7
+ interface UseSignInWithDexterConfig {
8
+ /** dexter-api base. Default https://api.dexter.cash. */
9
+ apiBase?: string;
10
+ /** RPC for the connected-chip balance read. Default: Dexter's Helius proxy. */
11
+ rpcUrl?: string;
12
+ /** Ceremony transport (both verbs). 'auto' (default) = inline on dexter.cash,
13
+ * popup anywhere else. Exposed so tests/staging can force a leg —
14
+ * CreateWalletPanel already had this knob; the sign-in surface was the odd
15
+ * one out. */
16
+ transport?: 'auto' | 'popup' | 'inline';
17
+ /** Hosted ceremony page for the popup transport. Default dexter.cash/connect. */
18
+ connectHost?: string;
19
+ /** Chrome-149+ immediate UI mode for the wallet-only verb: instant fast-fail
20
+ * when this device holds no passkey. Ignored by signIn(). */
21
+ preferImmediate?: boolean;
22
+ }
23
+ interface UseSignInWithDexter {
24
+ status: ConnectStatus;
25
+ /** Live ceremony phase while status==='pending' (challenge → passkey →
26
+ * verifying); null otherwise. Drives the button's "connecting steps". */
27
+ phase: CeremonyPhase | null;
28
+ isVaultConnected: boolean;
29
+ /** Run the ceremony. Resolves with the result; throws ConnectError on failure
30
+ * (error is also captured in `error` + `status==='error'` for declarative UI). */
31
+ signIn: () => Promise<SignInResult>;
32
+ /** Wallet-only sign-in (P0c): re-points this browser at an existing wallet,
33
+ * mints NO session. Returns a discriminated outcome — cancel is a normal
34
+ * result, never a throw. Identity surfaces (useIdentity/useDexterWallet)
35
+ * light up via the wallet store; `session`/`vault` here stay null. Fire on
36
+ * tap only — never on mount (iOS gesture rule). */
37
+ recover: () => Promise<RecoverOutcome>;
38
+ /** Last recover outcome; null until recover() settles. */
39
+ recovered: RecoverOutcome | null;
40
+ disconnect: () => void;
41
+ session: PasskeyLoginTokens | null;
42
+ vault: ConnectVault | null;
43
+ /** Dexter Wallet address (swigAddress, base58). */
44
+ vaultAddress: string | null;
45
+ vaultPda: string | null;
46
+ credentialId: string | null;
47
+ /** Guest passkey signer for authorizing spends / opening x402 tabs. null until
48
+ * a vault is connected. Drive it via `passkeySigner.signOperation(op)`. */
49
+ passkeySigner: DexterApiBrowserPasskeySigner | null;
50
+ /** USD available. number once read; null = unknown → chip shows wallet only. */
51
+ usdcBalance: number | null;
52
+ refreshBalance: () => Promise<void>;
53
+ error: ConnectError | null;
54
+ }
55
+ /**
56
+ * "Sign in with Dexter" — React surface over the login ceremony.
57
+ *
58
+ * Returns the Supabase session (always) plus the vault identity + USD balance
59
+ * (vault-review's login payload is live). dexter.cash login needs only
60
+ * `session`; the vault fields + balance drive the connected chip. The
61
+ * passkeySigner (for opening x402 tabs — dexter-agents) lands next, on the
62
+ * anon ServerPolicy bridge over the now-live publicKey/credentialId.
63
+ */
64
+ declare function useSignInWithDexter(config?: UseSignInWithDexterConfig): UseSignInWithDexter;
65
+
66
+ interface SignInWithDexterProps extends UseSignInWithDexterConfig {
67
+ /** 'signin' (default) = full sign-in minting the account session.
68
+ * 'recover' = wallet-only: re-points this browser at an existing wallet and
69
+ * mints NOTHING else (the wallet IS the sign-in). After a successful
70
+ * recover the element renders null — identity display belongs to
71
+ * DexterWalletChip/useIdentity, which light up via the wallet store. */
72
+ mode?: 'signin' | 'recover';
73
+ /** Fired with the result the moment sign-in completes. */
74
+ onSuccess?: (result: SignInResult) => void;
75
+ /** Recover mode: fired with EVERY settled outcome (ok, no_credential,
76
+ * cancelled, error) — the single channel; onError is not used in this mode.
77
+ * Branch on `reason`: no_credential → offer create; cancelled → stay silent. */
78
+ onRecovered?: (outcome: RecoverOutcome) => void;
79
+ /** Fired with the typed error if the ceremony fails. */
80
+ onError?: (error: ConnectError) => void;
81
+ /** Button label when signed out. Default "Sign in with Dexter". */
82
+ label?: string;
83
+ /** 'primary' = filled ember (default), 'secondary' = outline. */
84
+ variant?: 'primary' | 'secondary';
85
+ /** Full-width button. */
86
+ block?: boolean;
87
+ /** 'md' (default) or 'sm' — the mini header variant of the button. */
88
+ size?: 'md' | 'sm';
89
+ /** Extra className composed after the brand classes. Prefer overriding the
90
+ * `--dx-*` CSS variables for theming. */
91
+ className?: string;
92
+ /** Render the built-in connected chip (wallet + balance). Default true. */
93
+ showConnectedChip?: boolean;
94
+ }
95
+ /**
96
+ * Turnkey "Sign in with Dexter" element. Signed out → the branded DexterButton
97
+ * (hover / focus / active / loading states, themeable via --dx-* CSS vars);
98
+ * signed in → a compact chip with the Dexter Wallet address + USD available.
99
+ * Wraps useSignInWithDexter; for the wallet CREATE flow use <DexterButton>
100
+ * wired to your create action. Brand voice: no emojis, "unlock" banned.
101
+ */
102
+ declare function SignInWithDexter(props: SignInWithDexterProps): ReactElement | null;
103
+
104
+ /** The Dexter passkey mark — the brand glyph carried on the branded button. */
105
+ declare function DexterMark(): ReactElement;
106
+ interface DexterButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'onClick' | 'disabled' | 'className' | 'type'> {
107
+ /** Button content (e.g. "Sign in with Dexter", "Create your Dexter Wallet"). */
108
+ children?: ReactNode;
109
+ /** Loading state: shows the animated spinner + `loadingLabel`, disables click. */
110
+ loading?: boolean;
111
+ /** Label shown next to the spinner while loading. Default "Connecting…". */
112
+ loadingLabel?: string;
113
+ /** 'primary' = filled ember (default), 'secondary' = outline,
114
+ * 'danger' = outline in the danger color for destructive actions. */
115
+ variant?: 'primary' | 'secondary' | 'danger';
116
+ /** Full-width (fills its container). */
117
+ block?: boolean;
118
+ /** 'md' (default) = the standard CTA. 'sm' = the mini header/chip-row
119
+ * variant: tighter padding, smaller type and mark. Same states, same
120
+ * theming — never hand-shrink the md button with a className. */
121
+ size?: 'md' | 'sm';
122
+ /** Render the Dexter mark before the children. Default true. */
123
+ withMark?: boolean;
124
+ onClick?: () => void;
125
+ disabled?: boolean;
126
+ /** Extra className composed after the brand classes. */
127
+ className?: string;
128
+ type?: 'button' | 'submit';
129
+ }
130
+ /** The branded Dexter button. Wire it to any action via `onClick`. */
131
+ declare function DexterButton(props: DexterButtonProps): ReactElement;
132
+
133
+ interface UseDexterWallet {
134
+ /** Active wallet handle, or null if this browser has no active wallet. */
135
+ activeHandle: string | null;
136
+ /** The active wallet's roster entry (handle + label + credentialId), or
137
+ * null. `activeWallet.label` is the wallet's human name — identity is
138
+ * first-class, so display surfaces read it here instead of re-fetching. */
139
+ activeWallet: StoredWallet | null;
140
+ /** Known wallets on this browser, most-recently-used first. */
141
+ wallets: StoredWallet[];
142
+ /** What the WebAuthn Signal API supports in THIS browser (rename / prune). */
143
+ support: PasskeySignalSupport;
144
+ /**
145
+ * Eject the active wallet — "switch / start fresh". Clears the local binding
146
+ * and, where supported, prunes the old passkey from the OS manager so it
147
+ * disappears from the user's list. `{ forget: true }` also drops it from the
148
+ * roster.
149
+ */
150
+ eject: (opts?: {
151
+ forget?: boolean;
152
+ }) => void;
153
+ /** Switch the active wallet to a known handle. No-op if unknown. */
154
+ switchTo: (handle: string) => boolean;
155
+ /** Record/activate a handle (after enroll or recover). Prefer over writing
156
+ * localStorage by hand so the roster + subscribers stay correct. */
157
+ setActive: (handle: string, label?: string, credentialId?: string) => void;
158
+ /**
159
+ * Rename the ACTIVE passkey in the OS keychain (post-creation). Returns true
160
+ * if the browser supported it and the signal fired; false otherwise (the
161
+ * keychain entry is then just left as-is).
162
+ */
163
+ rename: (name: string, displayName?: string) => Promise<boolean>;
164
+ }
165
+ declare function useDexterWallet(): UseDexterWallet;
166
+
167
+ interface DexterWalletChipProps {
168
+ /** Connected (a wallet/account is present) → avatar + label; else signed-out label only. */
169
+ connected: boolean;
170
+ /** What to show: account name, wallet label, or the signed-out prompt (e.g. "Log in"). */
171
+ label: string;
172
+ /** Avatar image (e.g. a linked X avatar); falls back to the initial. */
173
+ avatarUrl?: string | null;
174
+ /** Single-character avatar fallback (defaults to the first letter of `label`). */
175
+ avatarInitial?: string;
176
+ onClick?: () => void;
177
+ /** Extra className composed after the brand classes. */
178
+ className?: string;
179
+ /** Reflected to aria-expanded (when the chip toggles a menu). */
180
+ ariaExpanded?: boolean;
181
+ }
182
+ /** The branded wallet/account chip. Wire it to open your menu via `onClick`. */
183
+ declare function DexterWalletChip(props: DexterWalletChipProps): ReactElement;
184
+
185
+ interface DexterWalletMenuProps {
186
+ /** The wallet's display name (nickname, else "Dexter Wallet"). */
187
+ walletLabel: string;
188
+ /** Avatar initial (defaults to the first letter of walletLabel). */
189
+ avatarInitial?: string;
190
+ /** "Manage wallet" → the consumer's wallet page. Row hidden if omitted. */
191
+ onManageWallet?: () => void;
192
+ /** Eject row → the consumer ejects/resets (guard + perform on its side). Row hidden if omitted. */
193
+ onStartFresh?: () => void;
194
+ /** Label for the eject/reset row. Default "Eject wallet". */
195
+ startFreshLabel?: string;
196
+ /** Sign-in/save UI revealed when "Save your wallet" is tapped (e.g. <SignInWithDexter/>). Row hidden if omitted. */
197
+ saveSlot?: ReactNode;
198
+ /** Short hint shown above the save UI. */
199
+ saveHint?: string;
200
+ /** Extra className composed after the brand classes. */
201
+ className?: string;
202
+ }
203
+ /** The branded wallet dropdown. */
204
+ declare function DexterWalletMenu(props: DexterWalletMenuProps): ReactElement;
205
+
206
+ interface UseIdentityConfig {
207
+ /** The account session token (e.g. a Supabase access_token), or null when the
208
+ * user has no account session. The SDK is auth-agnostic — pass your own. */
209
+ accountToken: string | null;
210
+ }
211
+ declare function useIdentity({ accountToken }: UseIdentityConfig): ResolvedIdentity;
212
+
213
+ interface AllowanceChipsProps {
214
+ /** The authored USD amount as a raw string, or null when nothing is chosen.
215
+ * NONE selected initially → pass null. Preset chips echo '5' / '20' / '50';
216
+ * Custom echoes whatever the user types. */
217
+ value: string | null;
218
+ /** Fired with the raw USD string (or null when Custom is opened empty). */
219
+ onChange: (usd: string | null) => void;
220
+ /** Extra className composed after the brand classes. */
221
+ className?: string;
222
+ }
223
+ /** The consent-at-birth allowance chips. */
224
+ declare function AllowanceChips(props: AllowanceChipsProps): ReactElement;
225
+
226
+ interface CreateWalletPanelProps {
227
+ /** Fired with the minted wallet the moment creation succeeds. */
228
+ onCreated?: (result: CreateWalletResult) => void;
229
+ /** Fired with the typed error if the ceremony fails. */
230
+ onError?: (error: ConnectError) => void;
231
+ /** dexter-api base. Default https://api.dexter.cash (createWallet's default). */
232
+ apiBase?: string;
233
+ /** Where the WebAuthn ceremony runs. Default 'auto' (createWallet's default). */
234
+ transport?: 'auto' | 'popup' | 'inline';
235
+ /** Render the optional "Name your wallet" field. Default true. */
236
+ showName?: boolean;
237
+ /** Extra className composed after the brand classes. */
238
+ className?: string;
239
+ }
240
+ /** The turnkey consent-at-birth create panel. */
241
+ declare function CreateWalletPanel(props: CreateWalletPanelProps): ReactElement;
242
+
243
+ type InstallApp = 'cursor' | 'vscode' | 'hermes' | 'claude-code';
244
+ interface AppInstallButtonsProps {
245
+ /** MCP endpoint to install. Default: OpenDexter. */
246
+ mcpUrl?: string;
247
+ /** Server name written into the app's config. Default: opendexter. */
248
+ serverName?: string;
249
+ /** Which app buttons to render, in order. Default: all four. */
250
+ apps?: InstallApp[];
251
+ /** Stack full-width instead of a wrapping row. */
252
+ block?: boolean;
253
+ className?: string;
254
+ /** Observability hook: fired on every action a user takes. */
255
+ onAction?: (app: InstallApp, action: 'deeplink' | 'copied') => void;
256
+ }
257
+ declare function cursorInstallUrl(name: string, mcpUrl: string): string;
258
+ declare function vscodeInstallUrl(name: string, mcpUrl: string): string;
259
+ declare function hermesInstallCommand(name: string, mcpUrl: string): string;
260
+ declare function claudeCodeInstallCommand(name: string, mcpUrl: string): string;
261
+ declare function AppInstallButtons(props: AppInstallButtonsProps): ReactElement;
262
+
263
+ export { AllowanceChips, type AllowanceChipsProps, AppInstallButtons, type AppInstallButtonsProps, type ConnectStatus, CreateWalletPanel, type CreateWalletPanelProps, DexterButton, type DexterButtonProps, DexterMark, DexterWalletChip, type DexterWalletChipProps, DexterWalletMenu, type DexterWalletMenuProps, type InstallApp, RecoverOutcome, SignInWithDexter, type SignInWithDexterProps, type UseDexterWallet, type UseIdentityConfig, type UseSignInWithDexter, type UseSignInWithDexterConfig, claudeCodeInstallCommand, cursorInstallUrl, hermesInstallCommand, useDexterWallet, useIdentity, useSignInWithDexter, vscodeInstallUrl };
package/dist/react.js CHANGED
@@ -677,7 +677,7 @@ var DEFAULT_MCP_URL = "https://open.dexter.cash/mcp";
677
677
  var DEFAULT_NAME = "opendexter";
678
678
  var ALL_APPS = ["cursor", "vscode", "hermes", "claude-code"];
679
679
  function cursorInstallUrl(name, mcpUrl) {
680
- const config = typeof btoa === "function" ? btoa(JSON.stringify({ url: mcpUrl })) : Buffer.from(JSON.stringify({ url: mcpUrl })).toString("base64");
680
+ const config = btoa(JSON.stringify({ url: mcpUrl }));
681
681
  return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(name)}&config=${encodeURIComponent(config)}`;
682
682
  }
683
683
  function vscodeInstallUrl(name, mcpUrl) {
@@ -0,0 +1,72 @@
1
+ import { JWTPayload, JWK, JSONWebKeySet } from 'jose';
2
+
3
+ /**
4
+ * @dexterai/connect/server — offline Dexter session verification.
5
+ *
6
+ * The server half of Sign in with Dexter (CONTRACT-dexter-session-token.md):
7
+ * a local ES256 signature check against the published JWKS — no call to
8
+ * Supabase or dexter-api on the hot path, so it runs on Node and edge
9
+ * runtimes alike. Pre-hook tokens (no `dexter` claim) verify as signed-in
10
+ * with `vaultAddress: null`; once the access-token hook is enabled the
11
+ * claim appears with no code change here.
12
+ *
13
+ * Phase 1 issuer is Supabase (CONTRACT §3); everything is parameterized on
14
+ * (iss, jwksUrl) so the Phase-2 sovereign cutover is a config flip.
15
+ */
16
+
17
+ declare const DEFAULT_ISS = "https://qdgumpoqnthrjfmqziwm.supabase.co/auth/v1";
18
+ declare const DEFAULT_AUDIENCE = "authenticated";
19
+ /** The namespaced claim sealed into the token by the access-token hook. */
20
+ interface DexterClaim {
21
+ ver: number;
22
+ /** Swig state address (base58) — the canonical Dexter Wallet identity. */
23
+ vault: string;
24
+ /** 16-byte passkey handle, base64url; absent on rows without one. */
25
+ userHandle?: string;
26
+ agentGrant?: unknown;
27
+ }
28
+ type VerifyFailureReason = 'no_token' | 'invalid' | 'expired' | 'issuer_mismatch' | 'audience_mismatch';
29
+ type DexterSession = {
30
+ isSignedIn: true;
31
+ sub: string;
32
+ vaultAddress: string | null;
33
+ userHandle: string | null;
34
+ agentGrant: unknown;
35
+ sessionId: string | null;
36
+ aal: string | null;
37
+ claims: JWTPayload & {
38
+ dexter?: DexterClaim;
39
+ };
40
+ } | {
41
+ isSignedIn: false;
42
+ reason: VerifyFailureReason;
43
+ };
44
+ interface VerifyOptions {
45
+ /** Expected issuer. Phase 1 default: the Dexter Supabase project. */
46
+ iss?: string;
47
+ /** JWKS location; defaults to `${iss}/.well-known/jwks.json`. */
48
+ jwksUrl?: string;
49
+ /**
50
+ * Public key(s) for fully networkless verification (a JWK or a JWKS).
51
+ * When omitted, the JWKS is fetched once and cached in-instance.
52
+ */
53
+ jwtKey?: JWK | JSONWebKeySet;
54
+ /** Expected audience. Default: Supabase's `authenticated`. */
55
+ audience?: string;
56
+ }
57
+ /** A fetch-API Request or anything with a node-style headers bag. */
58
+ type RequestLike = Request | {
59
+ headers: Record<string, string | string[] | undefined>;
60
+ };
61
+ interface DexterClient {
62
+ verifyDexterSession(token: string): Promise<DexterSession>;
63
+ authenticateRequest(req: RequestLike): Promise<DexterSession>;
64
+ }
65
+ declare function createDexterClient(options?: VerifyOptions): DexterClient;
66
+ /**
67
+ * One-off verification. For servers verifying many requests against a
68
+ * remote JWKS, create a client once instead so the key set caches.
69
+ */
70
+ declare function verifyDexterSession(token: string, options?: VerifyOptions): Promise<DexterSession>;
71
+
72
+ export { DEFAULT_AUDIENCE, DEFAULT_ISS, type DexterClaim, type DexterClient, type DexterSession, type RequestLike, type VerifyFailureReason, type VerifyOptions, createDexterClient, verifyDexterSession };
@@ -0,0 +1,289 @@
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
+ /** The wallet's cross-device display name (user-authored via rename), or
29
+ * null when never named. Identity is first-class: every sign-in carries
30
+ * the human name so no consumer ever falls back to a synthetic email.
31
+ * Optional for wire-compat with servers/popup pages predating 0.23. */
32
+ walletLabel?: string | null;
33
+ }
34
+ /** Result of a completed "Sign in with Dexter" ceremony. */
35
+ interface SignInResult {
36
+ session: PasskeyLoginTokens;
37
+ /** Present once vault-review ships the vault-in-login change. */
38
+ vault?: ConnectVault;
39
+ }
40
+ /**
41
+ * Coarse ceremony phase, emitted as a sign-in/create ceremony progresses so the
42
+ * UI can show live "connecting steps" instead of one flat spinner:
43
+ * challenge → passkey (the OS prompt) → verifying → finalizing (create only).
44
+ */
45
+ type CeremonyPhase = 'challenge' | 'passkey' | 'verifying' | 'finalizing';
46
+ /**
47
+ * Vault identity on the wallet-only recover leg, as reported by
48
+ * /api/passkey-vault-anon/status. Narrower than ConnectVault on purpose —
49
+ * the status endpoint carries no publicKey/usdcAta, so a recover cannot
50
+ * construct a passkey signer; it re-points this browser at the wallet and
51
+ * lets useIdentity/useDexterWallet light the UI.
52
+ */
53
+ interface RecoverVault {
54
+ vaultPda: string;
55
+ /** Swig state address, base58 — the user-facing Dexter Wallet address. */
56
+ swigAddress: string;
57
+ /** Deposit address; null until the swig is deployed. */
58
+ receiveAddress: string | null;
59
+ isActivated: boolean;
60
+ walletLabel: string | null;
61
+ }
62
+ /**
63
+ * Result of a wallet-only recover ceremony. A discriminated RESULT, not a
64
+ * throw: user-cancel is a normal outcome in WebAuthn, and consumers branch on
65
+ * `reason` (no_credential → offer create; cancelled → stay silent; error →
66
+ * retry copy). `no_credential` covers both the immediate-mode instant
67
+ * rejection (no passkey on this device) and a verify 404 (a passkey the
68
+ * server has no row for).
69
+ */
70
+ type RecoverOutcome = {
71
+ ok: true;
72
+ userHandle: string;
73
+ credentialId: string;
74
+ vault: RecoverVault;
75
+ } | {
76
+ ok: false;
77
+ reason: 'no_credential' | 'cancelled' | 'error';
78
+ error?: ConnectError;
79
+ };
80
+ interface RecoverWalletConfig extends DexterConnectConfig {
81
+ /** Chrome-149+ immediate UI mode: instant fast-fail when this device has no
82
+ * discoverable passkey (no empty account-picker sheet). Falls back to the
83
+ * normal modal wherever unsupported. */
84
+ preferImmediate?: boolean;
85
+ onPhase?: (phase: CeremonyPhase) => void;
86
+ }
87
+ interface DexterConnectConfig {
88
+ /** dexter-api base. Default https://api.dexter.cash. */
89
+ apiBase?: string;
90
+ /**
91
+ * Where the WebAuthn ceremony runs:
92
+ * - 'auto' (default): inline on the canonical Dexter origin (dexter.cash),
93
+ * popup on ANY other origin — so a third-party site works without the
94
+ * WebAuthn rpId-origin problem (in-page only works on dexter.cash).
95
+ * - 'popup': always via the hosted popup (works on any website).
96
+ * - 'inline': always in-page — only valid on a Dexter origin; this is what
97
+ * the hosted ceremony page itself uses.
98
+ */
99
+ transport?: 'auto' | 'popup' | 'inline';
100
+ /** Hosted ceremony page (popup transport). Default https://dexter.cash/connect. */
101
+ connectHost?: string;
102
+ }
103
+ /** Typed error whose `code` is the server's snake_case error string. */
104
+ declare class ConnectError extends Error {
105
+ readonly code: string;
106
+ constructor(code: string, message?: string);
107
+ }
108
+
109
+ /** Consent-at-birth allowance (Branch rulings 2026-07-02/03).
110
+ * The user authors the number; zero is not consent; TTL is fixed 30d and
111
+ * never user-editable; no caller may invent a default. */
112
+ declare const SESSION_TTL_30D = "2592000";
113
+ interface SpendPolicy {
114
+ /** Role-2 allowance, atomic USDC (6dp), decimal string. User-authored. */
115
+ spendLimitAtomic: string;
116
+ /** Fixed 30d. Present for wire compatibility; always SESSION_TTL_30D. */
117
+ sessionTtlSeconds: string;
118
+ }
119
+ /** Parse user-entered USD ("5", "$20", "1,000", "20.5") to atomic USDC.
120
+ * Null on anything invalid — callers must not invent a fallback. */
121
+ declare function usdToAtomic(input: string): bigint | null;
122
+ /** Null when invalid or zero (zero is not consent). */
123
+ declare function authoredPolicy(usdInput: string): SpendPolicy | null;
124
+
125
+ interface CreateWalletConfig extends DexterConnectConfig {
126
+ /** Label for the passkey in the OS keychain AND the wallet roster. Set at
127
+ * creation — the only moment naming is guaranteed to stick. Default "Dexter Wallet". */
128
+ name?: string;
129
+ /** RP id for the new credential. Default "dexter.cash". */
130
+ rpId?: string;
131
+ /** Consent-at-birth allowance the user authored at creation (chips $5/$20/$50
132
+ * or Custom; zero is not consent; build it with authoredPolicy()). When
133
+ * present it rides the /initialize body so the number becomes the server-side
134
+ * write-once consent record. The TTL is ruled fixed 30d — whatever the object
135
+ * carries, the wire always sends SESSION_TTL_30D. Absent → no policy authored
136
+ * (the vault initializes without one; nothing invents a default). */
137
+ spendPolicy?: SpendPolicy;
138
+ /** Called as the ceremony progresses, for live "connecting steps" UI:
139
+ * challenge → passkey → verifying → finalizing. */
140
+ onPhase?: (phase: CeremonyPhase) => void;
141
+ }
142
+ interface CreateWalletResult {
143
+ /** Server-minted 16-byte user handle, base64url — the vault identity. */
144
+ handle: string;
145
+ /** base64url credential id of the new passkey. */
146
+ credentialId: string;
147
+ /** The freshly initialized vault (swig not yet deployed; deploys lazily). */
148
+ vault: ConnectVault;
149
+ /** Wallet name recorded at birth (server-confirmed via /initialize). Rides
150
+ * the result so a popup-typed name reaches the OPENER's wallet store —
151
+ * before 0.23.2 it lived only on the popup origin. null = unnamed. */
152
+ label: string | null;
153
+ }
154
+ /**
155
+ * Mint a brand-new Dexter wallet (passkey + vault) and make it the active wallet.
156
+ *
157
+ * One passkey approval. Throws ConnectError on any failed leg (the `code` is the
158
+ * server's error string, or webauthn_failed / no_credential for the ceremony).
159
+ */
160
+ declare function createWallet(config?: CreateWalletConfig): Promise<CreateWalletResult>;
161
+
162
+ type IdentityKind = 'passkey-vault' | 'account' | 'none';
163
+ interface IdentityInput {
164
+ /** An account session token (e.g. Supabase access_token) when present, else null. */
165
+ accountToken: string | null;
166
+ /** The passkey-vault user handle (the connect wallet store), else null. */
167
+ userHandle: string | null;
168
+ /** The active wallet's display name from the connect wallet store (persisted
169
+ * at sign-in/recover/rename), else null. Browser-only input like the handle. */
170
+ walletLabel?: string | null;
171
+ }
172
+ interface ResolvedIdentity {
173
+ /** The primary identity axis, passkey-vault-first. */
174
+ kind: IdentityKind;
175
+ /** Passkey-vault identity (FIRST-CLASS): the wallet handle, or null. */
176
+ userHandle: string | null;
177
+ /** The wallet's human display name, or null when the wallet was never named
178
+ * (or no wallet is active). Display surfaces prefer this over any synthetic
179
+ * account identifier — a user should never be shown a generated email. */
180
+ walletLabel: string | null;
181
+ /** Account identity (secondary/legacy axis): bearer for account-scoped fetches, or null. */
182
+ accountToken: string | null;
183
+ /** A passkey vault is present on this device. */
184
+ hasPasskeyVault: boolean;
185
+ /** An account session is present. */
186
+ hasAccount: boolean;
187
+ /** Any identity at all — drives "show the wallet" vs "Sign in with Dexter". */
188
+ hasWallet: boolean;
189
+ }
190
+ declare function resolveIdentity(input: IdentityInput): ResolvedIdentity;
191
+
192
+ /** A wallet this browser knows about. `handle` is the identity; the rest is UX. */
193
+ interface StoredWallet {
194
+ /** base64url 16-byte user handle — the vault identity. */
195
+ handle: string;
196
+ /** Human label for switch UIs (e.g. an email, or "Dexter Wallet"). */
197
+ label?: string;
198
+ /** base64url credential id — enables the WebAuthn Signal API to prune this
199
+ * passkey from the OS manager on eject (see ./signals). */
200
+ credentialId?: string;
201
+ /** Epoch ms of last activation — for ordering the switcher. */
202
+ lastUsedAt?: number;
203
+ }
204
+ type Listener = () => void;
205
+ /** The active wallet handle, or null if this browser has no active wallet. */
206
+ declare function getActiveHandle(): string | null;
207
+ /**
208
+ * Set the active wallet handle (e.g. after enroll or recover), upserting it into
209
+ * the roster with a fresh `lastUsedAt`. Idempotent. Fires subscribers.
210
+ */
211
+ declare function setActiveHandle(handle: string, label?: string, credentialId?: string): void;
212
+ /** Look up a known wallet's stored credentialId (for Signal-API prune on eject). */
213
+ declare function getCredentialId(handle: string): string | undefined;
214
+ /**
215
+ * EJECT — clear the active wallet so the browser is no longer bound to it. This
216
+ * is "switch / start fresh / sign out of this wallet". The wallet stays in the
217
+ * roster (so the user can switch back) unless `forget` is true. After eject,
218
+ * `getActiveHandle()` is null and the next enroll/recover starts clean. Fires
219
+ * subscribers. This is the function whose absence WAS the welded-wallet bug.
220
+ */
221
+ declare function ejectActiveWallet(opts?: {
222
+ forget?: boolean;
223
+ }): void;
224
+ /** Every wallet this browser knows about, most-recently-used first. */
225
+ declare function listWallets(): StoredWallet[];
226
+ /**
227
+ * Switch the active wallet to a handle ALREADY in the roster. Returns false (and
228
+ * does nothing) if the handle is unknown — switching is only ever to a wallet
229
+ * this browser has seen, never to an arbitrary string.
230
+ */
231
+ declare function switchWallet(handle: string): boolean;
232
+ /** Remove a wallet from the roster entirely; clears active if it was active. */
233
+ declare function forgetWallet(handle: string): void;
234
+ /**
235
+ * Subscribe to active-wallet/roster changes. Returns an unsubscribe fn. Also
236
+ * wires the cross-tab `storage` event once, so ejecting in one tab updates the
237
+ * others. The React hook (`useDexterWallet`) is a thin wrapper over this.
238
+ */
239
+ declare function subscribe(listener: Listener): () => void;
240
+ /** Exposed for consumers that must reference the canonical key (migrations,
241
+ * tests). Prefer the accessors above — do NOT read localStorage by hand. */
242
+ declare const ACTIVE_WALLET_STORAGE_KEY = "dexter:passkey:userHandle";
243
+
244
+ interface PasskeySignalSupport {
245
+ /** signalCurrentUserDetails — rename a passkey post-creation. */
246
+ rename: boolean;
247
+ /** signalUnknownCredential — remove one stale passkey from the manager. */
248
+ prune: boolean;
249
+ /** signalAllAcceptedCredentials — reconcile the full valid set. */
250
+ syncAccepted: boolean;
251
+ }
252
+ /**
253
+ * What the CURRENT browser supports, by direct feature-detection. Instant, no
254
+ * network, no UA sniffing — tells you exactly what will light up on THIS device
255
+ * (e.g. call once on Branch's iPhone to learn its Safari's status).
256
+ */
257
+ declare function passkeySignalSupport(): PasskeySignalSupport;
258
+ /**
259
+ * Rename a passkey in the OS keychain AFTER creation. `userId` is the base64url
260
+ * user handle; `rpId` defaults to the current host. Returns true if the signal
261
+ * fired, false if unsupported/failed (caller treats false as "left as-is").
262
+ */
263
+ declare function renamePasskey(args: {
264
+ userId: string;
265
+ name: string;
266
+ displayName?: string;
267
+ rpId?: string;
268
+ }): Promise<boolean>;
269
+ /**
270
+ * Tell the OS manager a credential is gone so it removes that passkey from the
271
+ * user's list — the welded-old-wallet auto-cleanup. `credentialId` is base64url.
272
+ * Returns true if fired, false if unsupported/failed.
273
+ */
274
+ declare function prunePasskey(args: {
275
+ credentialId: string;
276
+ rpId?: string;
277
+ }): Promise<boolean>;
278
+ /**
279
+ * Declare the FULL set of still-valid credential IDs for a user; the manager
280
+ * prunes anything not listed. Use after sign-in or eject to reconcile in one
281
+ * shot (pass `[]` to clear all of a user's passkeys). Returns true if fired.
282
+ */
283
+ declare function syncAcceptedPasskeys(args: {
284
+ userId: string;
285
+ acceptedCredentialIds: string[];
286
+ rpId?: string;
287
+ }): Promise<boolean>;
288
+
289
+ export { ACTIVE_WALLET_STORAGE_KEY as A, syncAcceptedPasskeys as B, type CreateWalletResult as C, type DexterConnectConfig as D, usdToAtomic as E, type IdentityKind as I, type PasskeyLoginTokens as P, type RecoverWalletConfig as R, type SignInResult as S, type CreateWalletConfig as a, type CeremonyPhase as b, type ConnectVault as c, type RecoverOutcome as d, ConnectError as e, type IdentityInput as f, type PasskeySignalSupport as g, type RecoverVault as h, type ResolvedIdentity as i, SESSION_TTL_30D as j, type SpendPolicy as k, type StoredWallet as l, authoredPolicy as m, createWallet as n, ejectActiveWallet as o, forgetWallet as p, getActiveHandle as q, getCredentialId as r, listWallets as s, passkeySignalSupport as t, prunePasskey as u, renamePasskey as v, resolveIdentity as w, setActiveHandle as x, subscribe as y, switchWallet as z };
@@ -0,0 +1,61 @@
1
+ import { ReactElement } from 'react';
2
+ import { IDKitResult } from '@worldcoin/idkit';
3
+
4
+ type VerifyPersonhoodPhase = 'loading' | 'ready' | 'rp_error' | 'verified';
5
+ interface VerifyPersonhoodConfig {
6
+ /** World ID app id (`app_…`), from the developer portal. */
7
+ appId: `app_${string}`;
8
+ /** The registered action (e.g. `dexter-credit-root-v2`) — pins the nullifier namespace. */
9
+ action: string;
10
+ /** `production` | `staging`. Default `production`. */
11
+ environment?: 'production' | 'staging';
12
+ /**
13
+ * URL that returns the SERVER-SIGNED RP context as `{ rp_context: RpContext }`.
14
+ * The RP signing key is server-side only (never the browser), so the consumer
15
+ * exposes an endpoint that signs the request and returns just the signed
16
+ * context. Mirrors the capture rig's `/api/rp-context`.
17
+ */
18
+ rpContextUrl: string;
19
+ /** Optional `fetch` init for the RP-context request (auth headers, etc.). */
20
+ rpContextInit?: RequestInit;
21
+ }
22
+ interface UseVerifyPersonhood {
23
+ phase: VerifyPersonhoodPhase;
24
+ error: string | null;
25
+ result: IDKitResult | null;
26
+ /** Open the World App verification sheet. No-op until phase is 'ready'/'verified'. */
27
+ open: () => void;
28
+ /** The IDKitRequestWidget element to render (null until the RP context loads). */
29
+ widget: ReactElement | null;
30
+ }
31
+ /**
32
+ * Headless hook: manages the RP-context fetch + IDKit lifecycle and hands back
33
+ * the raw proof. Render `widget` and call `open()` from your own UI, or use the
34
+ * turnkey <VerifyPersonhood> below.
35
+ */
36
+ declare function useVerifyPersonhood(config: VerifyPersonhoodConfig, onProof?: (result: IDKitResult) => void, onError?: (error: Error) => void): UseVerifyPersonhood;
37
+ interface VerifyPersonhoodProps extends VerifyPersonhoodConfig {
38
+ /** Fired with the raw World ID v4 proof the moment verification completes. */
39
+ onProof?: (result: IDKitResult) => void;
40
+ /** Fired with the typed error if RP signing or verification fails. */
41
+ onError?: (error: Error) => void;
42
+ /** Button label when armed. Default "Verify your personhood". */
43
+ label?: string;
44
+ /** Label after a proof is captured. Default "Verify again". */
45
+ verifiedLabel?: string;
46
+ /** 'primary' = filled ember (default), 'secondary' = outline. */
47
+ variant?: 'primary' | 'secondary';
48
+ /** Full-width button. */
49
+ block?: boolean;
50
+ /** Extra className composed after the brand classes. */
51
+ className?: string;
52
+ }
53
+ /**
54
+ * Turnkey "Verify your personhood" element — the personhood sibling of
55
+ * <SignInWithDexter>. Renders the branded DexterButton (loading while the RP
56
+ * context signs server-side) that opens World App; on success hands the raw
57
+ * IDKitResult to `onProof`. Brand voice: no emojis. Themeable via --dx-* vars.
58
+ */
59
+ declare function VerifyPersonhood(props: VerifyPersonhoodProps): ReactElement;
60
+
61
+ export { type UseVerifyPersonhood, VerifyPersonhood, type VerifyPersonhoodConfig, type VerifyPersonhoodPhase, type VerifyPersonhoodProps, useVerifyPersonhood };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dexterai/connect",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "Sign in with Dexter — passkey connector. Composes @dexterai/vault.",
5
5
  "type": "module",
6
6
  "exports": {