@dexterai/connect 0.24.3 → 0.25.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/{chunk-P3ZBIO7N.js → chunk-VGERNAQ3.js} +163 -130
- package/dist/index.d.ts +3 -24
- package/dist/index.js +1 -1
- package/dist/react.d.ts +15 -4
- package/dist/react.js +46 -2
- package/dist/{signals-C05rIVey.d.ts → signals-C4JSE_4X.d.ts} +37 -1
- package/package.json +1 -1
|
@@ -345,8 +345,127 @@ async function initializeVault(apiBase, userHandle, credentialId, spendPolicy, l
|
|
|
345
345
|
|
|
346
346
|
// src/relay.ts
|
|
347
347
|
import { startAuthentication, browserSupportsWebAuthn } from "@simplewebauthn/browser";
|
|
348
|
+
|
|
349
|
+
// src/base64.ts
|
|
350
|
+
function base64ToBytes(s) {
|
|
351
|
+
const bin = atob(s);
|
|
352
|
+
const out = new Uint8Array(bin.length);
|
|
353
|
+
for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);
|
|
354
|
+
return out;
|
|
355
|
+
}
|
|
356
|
+
function base64urlToBytes(s) {
|
|
357
|
+
const pad = s.length % 4 === 0 ? "" : "=".repeat(4 - s.length % 4);
|
|
358
|
+
const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
359
|
+
return base64ToBytes(b64);
|
|
360
|
+
}
|
|
361
|
+
function bytesToBase64(bytes) {
|
|
362
|
+
let bin = "";
|
|
363
|
+
for (let i = 0; i < bytes.length; i += 1) bin += String.fromCharCode(bytes[i]);
|
|
364
|
+
return btoa(bin);
|
|
365
|
+
}
|
|
366
|
+
function bytesToBase64url(bytes) {
|
|
367
|
+
return bytesToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
368
|
+
}
|
|
369
|
+
function base64urlToBase64(s) {
|
|
370
|
+
const t = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
371
|
+
return t + "=".repeat((4 - t.length % 4) % 4);
|
|
372
|
+
}
|
|
373
|
+
function compactSignatureToDer(compact) {
|
|
374
|
+
if (compact.length !== 64) {
|
|
375
|
+
throw new Error(`expected 64-byte compact signature, got ${compact.length}`);
|
|
376
|
+
}
|
|
377
|
+
const r = derInteger(compact.subarray(0, 32));
|
|
378
|
+
const s = derInteger(compact.subarray(32, 64));
|
|
379
|
+
const body = new Uint8Array(r.length + s.length);
|
|
380
|
+
body.set(r, 0);
|
|
381
|
+
body.set(s, r.length);
|
|
382
|
+
const out = new Uint8Array(2 + body.length);
|
|
383
|
+
out[0] = 48;
|
|
384
|
+
out[1] = body.length;
|
|
385
|
+
out.set(body, 2);
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
function derInteger(component) {
|
|
389
|
+
let start = 0;
|
|
390
|
+
while (start < component.length - 1 && component[start] === 0) start += 1;
|
|
391
|
+
let content = component.subarray(start);
|
|
392
|
+
if (content[0] & 128) {
|
|
393
|
+
const padded = new Uint8Array(content.length + 1);
|
|
394
|
+
padded[0] = 0;
|
|
395
|
+
padded.set(content, 1);
|
|
396
|
+
content = padded;
|
|
397
|
+
}
|
|
398
|
+
const out = new Uint8Array(2 + content.length);
|
|
399
|
+
out[0] = 2;
|
|
400
|
+
out[1] = content.length;
|
|
401
|
+
out.set(content, 2);
|
|
402
|
+
return out;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/immediate.ts
|
|
406
|
+
var immediateCapPromise = null;
|
|
407
|
+
function immediateGetSupported() {
|
|
408
|
+
if (!immediateCapPromise) {
|
|
409
|
+
immediateCapPromise = (async () => {
|
|
410
|
+
try {
|
|
411
|
+
if (typeof window === "undefined") return false;
|
|
412
|
+
const pkc2 = window.PublicKeyCredential;
|
|
413
|
+
if (!pkc2 || typeof pkc2.getClientCapabilities !== "function") return false;
|
|
414
|
+
const caps = await pkc2.getClientCapabilities.call(pkc2);
|
|
415
|
+
return caps?.immediateGet === true;
|
|
416
|
+
} catch {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
})();
|
|
420
|
+
}
|
|
421
|
+
return immediateCapPromise;
|
|
422
|
+
}
|
|
423
|
+
function primeImmediateSupport() {
|
|
424
|
+
void immediateGetSupported();
|
|
425
|
+
}
|
|
426
|
+
async function immediateAuthentication(options) {
|
|
427
|
+
const getOptions = {
|
|
428
|
+
publicKey: {
|
|
429
|
+
challenge: base64urlToBytes(options.challenge),
|
|
430
|
+
rpId: options.rpId,
|
|
431
|
+
timeout: options.timeout,
|
|
432
|
+
userVerification: options.userVerification,
|
|
433
|
+
allowCredentials: options.allowCredentials?.map((c) => ({
|
|
434
|
+
id: base64urlToBytes(c.id),
|
|
435
|
+
type: c.type,
|
|
436
|
+
transports: c.transports
|
|
437
|
+
}))
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
getOptions.uiMode = "immediate";
|
|
441
|
+
const cred = await navigator.credentials.get(getOptions);
|
|
442
|
+
if (!cred) throw new DOMException("no credential", "NotAllowedError");
|
|
443
|
+
const a = cred.response;
|
|
444
|
+
return {
|
|
445
|
+
id: cred.id,
|
|
446
|
+
rawId: bytesToBase64url(new Uint8Array(cred.rawId)),
|
|
447
|
+
response: {
|
|
448
|
+
clientDataJSON: bytesToBase64url(new Uint8Array(a.clientDataJSON)),
|
|
449
|
+
authenticatorData: bytesToBase64url(new Uint8Array(a.authenticatorData)),
|
|
450
|
+
signature: bytesToBase64url(new Uint8Array(a.signature)),
|
|
451
|
+
userHandle: a.userHandle ? bytesToBase64url(new Uint8Array(a.userHandle)) : void 0
|
|
452
|
+
},
|
|
453
|
+
clientExtensionResults: cred.getClientExtensionResults?.() ?? {},
|
|
454
|
+
type: "public-key",
|
|
455
|
+
authenticatorAttachment: cred.authenticatorAttachment ?? void 0
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function classifyWebAuthnRejection(err) {
|
|
459
|
+
const e = err;
|
|
460
|
+
if (!e) return false;
|
|
461
|
+
const blob = [e.name, e.cause?.name, typeof e.code === "string" ? e.code : "", e.message].filter(Boolean).join(" ").toLowerCase();
|
|
462
|
+
return /notallowed|not ?allowed|abort|cancel|timed out|timeout|denied|ceremony/.test(blob);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/relay.ts
|
|
348
466
|
var DEFAULT_API_BASE2 = "https://api.dexter.cash";
|
|
349
467
|
var ANON_SIGN_BASE = "/api/passkey-anon/sign";
|
|
468
|
+
primeImmediateSupport();
|
|
350
469
|
async function passkeyLogin(config = {}, onPhase) {
|
|
351
470
|
if (shouldUsePopup(config.transport)) {
|
|
352
471
|
const result2 = await openCeremonyPopup("signin", {
|
|
@@ -380,24 +499,56 @@ async function passkeyLogin(config = {}, onPhase) {
|
|
|
380
499
|
}
|
|
381
500
|
async function continueWithDexter(config = {}, onPhase) {
|
|
382
501
|
if (shouldUsePopup(config.transport)) {
|
|
383
|
-
const
|
|
502
|
+
const result = await openCeremonyPopup("continue", {
|
|
384
503
|
connectHost: config.connectHost,
|
|
385
504
|
name: config.name,
|
|
386
505
|
apiBase: config.apiBase
|
|
387
506
|
});
|
|
388
|
-
if (
|
|
389
|
-
setActiveHandle(
|
|
390
|
-
} else if (
|
|
391
|
-
setActiveHandle(
|
|
507
|
+
if (result.kind === "create") {
|
|
508
|
+
setActiveHandle(result.handle, result.label ?? config.name, result.credentialId);
|
|
509
|
+
} else if (result.kind === "signin" && result.vault) {
|
|
510
|
+
setActiveHandle(result.vault.userHandle, result.vault.walletLabel ?? void 0, result.vault.credentialId);
|
|
392
511
|
}
|
|
393
|
-
return
|
|
512
|
+
return result;
|
|
513
|
+
}
|
|
514
|
+
if (await immediateGetSupported()) {
|
|
515
|
+
const probe = await immediatePasskeyLogin(config, onPhase);
|
|
516
|
+
if (probe.outcome === "signin") return { kind: "signin", ...probe.result };
|
|
517
|
+
if (probe.outcome === "cancelled") return { kind: "cancelled" };
|
|
518
|
+
if (!config.spendPolicy) return { kind: "needs_create" };
|
|
519
|
+
const created = await createWallet({ ...config, onPhase });
|
|
520
|
+
return { kind: "create", ...created };
|
|
394
521
|
}
|
|
395
522
|
if (getActiveHandle()) {
|
|
396
|
-
const
|
|
397
|
-
return { kind: "signin", ...
|
|
523
|
+
const result = await passkeyLogin(config, onPhase);
|
|
524
|
+
return { kind: "signin", ...result };
|
|
525
|
+
}
|
|
526
|
+
return { kind: "needs_choice" };
|
|
527
|
+
}
|
|
528
|
+
async function immediatePasskeyLogin(config, onPhase) {
|
|
529
|
+
const apiBase = (config.apiBase ?? DEFAULT_API_BASE2).replace(/\/$/, "");
|
|
530
|
+
onPhase?.("challenge");
|
|
531
|
+
const options = await fetchLoginChallenge(apiBase);
|
|
532
|
+
onPhase?.("passkey");
|
|
533
|
+
let response;
|
|
534
|
+
try {
|
|
535
|
+
response = await immediateAuthentication(options);
|
|
536
|
+
} catch (err) {
|
|
537
|
+
if (classifyWebAuthnRejection(err)) {
|
|
538
|
+
return { outcome: "no_credential" };
|
|
539
|
+
}
|
|
540
|
+
throw new ConnectError("webauthn_failed", err instanceof Error ? err.message : String(err));
|
|
541
|
+
}
|
|
542
|
+
onPhase?.("verifying");
|
|
543
|
+
const result = await submitLogin(apiBase, response);
|
|
544
|
+
if (result.vault) {
|
|
545
|
+
setActiveHandle(
|
|
546
|
+
result.vault.userHandle,
|
|
547
|
+
result.vault.walletLabel ?? void 0,
|
|
548
|
+
result.vault.credentialId
|
|
549
|
+
);
|
|
398
550
|
}
|
|
399
|
-
|
|
400
|
-
return { kind: "create", ...result };
|
|
551
|
+
return { outcome: "signin", result };
|
|
401
552
|
}
|
|
402
553
|
async function fetchLoginChallenge(apiBase) {
|
|
403
554
|
const res = await fetch(`${apiBase}${ANON_SIGN_BASE}/login-challenge`, {
|
|
@@ -434,62 +585,6 @@ async function submitLogin(apiBase, response) {
|
|
|
434
585
|
return data.vault ? { session, vault: data.vault } : { session };
|
|
435
586
|
}
|
|
436
587
|
|
|
437
|
-
// src/base64.ts
|
|
438
|
-
function base64ToBytes(s) {
|
|
439
|
-
const bin = atob(s);
|
|
440
|
-
const out = new Uint8Array(bin.length);
|
|
441
|
-
for (let i = 0; i < bin.length; i += 1) out[i] = bin.charCodeAt(i);
|
|
442
|
-
return out;
|
|
443
|
-
}
|
|
444
|
-
function base64urlToBytes(s) {
|
|
445
|
-
const pad = s.length % 4 === 0 ? "" : "=".repeat(4 - s.length % 4);
|
|
446
|
-
const b64 = s.replace(/-/g, "+").replace(/_/g, "/") + pad;
|
|
447
|
-
return base64ToBytes(b64);
|
|
448
|
-
}
|
|
449
|
-
function bytesToBase64(bytes) {
|
|
450
|
-
let bin = "";
|
|
451
|
-
for (let i = 0; i < bytes.length; i += 1) bin += String.fromCharCode(bytes[i]);
|
|
452
|
-
return btoa(bin);
|
|
453
|
-
}
|
|
454
|
-
function bytesToBase64url(bytes) {
|
|
455
|
-
return bytesToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
456
|
-
}
|
|
457
|
-
function base64urlToBase64(s) {
|
|
458
|
-
const t = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
459
|
-
return t + "=".repeat((4 - t.length % 4) % 4);
|
|
460
|
-
}
|
|
461
|
-
function compactSignatureToDer(compact) {
|
|
462
|
-
if (compact.length !== 64) {
|
|
463
|
-
throw new Error(`expected 64-byte compact signature, got ${compact.length}`);
|
|
464
|
-
}
|
|
465
|
-
const r = derInteger(compact.subarray(0, 32));
|
|
466
|
-
const s = derInteger(compact.subarray(32, 64));
|
|
467
|
-
const body = new Uint8Array(r.length + s.length);
|
|
468
|
-
body.set(r, 0);
|
|
469
|
-
body.set(s, r.length);
|
|
470
|
-
const out = new Uint8Array(2 + body.length);
|
|
471
|
-
out[0] = 48;
|
|
472
|
-
out[1] = body.length;
|
|
473
|
-
out.set(body, 2);
|
|
474
|
-
return out;
|
|
475
|
-
}
|
|
476
|
-
function derInteger(component) {
|
|
477
|
-
let start = 0;
|
|
478
|
-
while (start < component.length - 1 && component[start] === 0) start += 1;
|
|
479
|
-
let content = component.subarray(start);
|
|
480
|
-
if (content[0] & 128) {
|
|
481
|
-
const padded = new Uint8Array(content.length + 1);
|
|
482
|
-
padded[0] = 0;
|
|
483
|
-
padded.set(content, 1);
|
|
484
|
-
content = padded;
|
|
485
|
-
}
|
|
486
|
-
const out = new Uint8Array(2 + content.length);
|
|
487
|
-
out[0] = 2;
|
|
488
|
-
out[1] = content.length;
|
|
489
|
-
out.set(content, 2);
|
|
490
|
-
return out;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
588
|
// src/anon-policy.ts
|
|
494
589
|
var DEFAULT_API_BASE3 = "https://api.dexter.cash";
|
|
495
590
|
var ANON_SIGN_BASE2 = "/api/passkey-anon/sign";
|
|
@@ -579,68 +674,6 @@ function resolveIdentity(input) {
|
|
|
579
674
|
|
|
580
675
|
// src/recover.ts
|
|
581
676
|
import { startAuthentication as startAuthentication2, browserSupportsWebAuthn as browserSupportsWebAuthn2 } from "@simplewebauthn/browser";
|
|
582
|
-
|
|
583
|
-
// src/immediate.ts
|
|
584
|
-
var immediateCapPromise = null;
|
|
585
|
-
function immediateGetSupported() {
|
|
586
|
-
if (!immediateCapPromise) {
|
|
587
|
-
immediateCapPromise = (async () => {
|
|
588
|
-
try {
|
|
589
|
-
if (typeof window === "undefined") return false;
|
|
590
|
-
const pkc2 = window.PublicKeyCredential;
|
|
591
|
-
if (!pkc2 || typeof pkc2.getClientCapabilities !== "function") return false;
|
|
592
|
-
const caps = await pkc2.getClientCapabilities.call(pkc2);
|
|
593
|
-
return caps?.immediateGet === true;
|
|
594
|
-
} catch {
|
|
595
|
-
return false;
|
|
596
|
-
}
|
|
597
|
-
})();
|
|
598
|
-
}
|
|
599
|
-
return immediateCapPromise;
|
|
600
|
-
}
|
|
601
|
-
function primeImmediateSupport() {
|
|
602
|
-
void immediateGetSupported();
|
|
603
|
-
}
|
|
604
|
-
async function immediateAuthentication(options) {
|
|
605
|
-
const getOptions = {
|
|
606
|
-
publicKey: {
|
|
607
|
-
challenge: base64urlToBytes(options.challenge),
|
|
608
|
-
rpId: options.rpId,
|
|
609
|
-
timeout: options.timeout,
|
|
610
|
-
userVerification: options.userVerification,
|
|
611
|
-
allowCredentials: options.allowCredentials?.map((c) => ({
|
|
612
|
-
id: base64urlToBytes(c.id),
|
|
613
|
-
type: c.type,
|
|
614
|
-
transports: c.transports
|
|
615
|
-
}))
|
|
616
|
-
}
|
|
617
|
-
};
|
|
618
|
-
getOptions.uiMode = "immediate";
|
|
619
|
-
const cred = await navigator.credentials.get(getOptions);
|
|
620
|
-
if (!cred) throw new DOMException("no credential", "NotAllowedError");
|
|
621
|
-
const a = cred.response;
|
|
622
|
-
return {
|
|
623
|
-
id: cred.id,
|
|
624
|
-
rawId: bytesToBase64url(new Uint8Array(cred.rawId)),
|
|
625
|
-
response: {
|
|
626
|
-
clientDataJSON: bytesToBase64url(new Uint8Array(a.clientDataJSON)),
|
|
627
|
-
authenticatorData: bytesToBase64url(new Uint8Array(a.authenticatorData)),
|
|
628
|
-
signature: bytesToBase64url(new Uint8Array(a.signature)),
|
|
629
|
-
userHandle: a.userHandle ? bytesToBase64url(new Uint8Array(a.userHandle)) : void 0
|
|
630
|
-
},
|
|
631
|
-
clientExtensionResults: cred.getClientExtensionResults?.() ?? {},
|
|
632
|
-
type: "public-key",
|
|
633
|
-
authenticatorAttachment: cred.authenticatorAttachment ?? void 0
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function classifyWebAuthnRejection(err) {
|
|
637
|
-
const e = err;
|
|
638
|
-
if (!e) return false;
|
|
639
|
-
const blob = [e.name, e.cause?.name, typeof e.code === "string" ? e.code : "", e.message].filter(Boolean).join(" ").toLowerCase();
|
|
640
|
-
return /notallowed|not ?allowed|abort|cancel|timed out|timeout|denied|ceremony/.test(blob);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// src/recover.ts
|
|
644
677
|
var DEFAULT_API_BASE4 = "https://api.dexter.cash";
|
|
645
678
|
var ANON_SIGN_BASE3 = "/api/passkey-anon/sign";
|
|
646
679
|
primeImmediateSupport();
|
|
@@ -838,10 +871,10 @@ export {
|
|
|
838
871
|
usdToAtomic,
|
|
839
872
|
authoredPolicy,
|
|
840
873
|
createWallet,
|
|
841
|
-
passkeyLogin,
|
|
842
|
-
continueWithDexter,
|
|
843
874
|
bytesToBase64url,
|
|
844
875
|
base64urlToBase64,
|
|
876
|
+
passkeyLogin,
|
|
877
|
+
continueWithDexter,
|
|
845
878
|
createAnonServerPolicy,
|
|
846
879
|
createPasskeySigner,
|
|
847
880
|
resolveIdentity,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { A as ACTIVE_WALLET_STORAGE_KEY,
|
|
1
|
+
import { C as ConnectVault, R as RecoverWalletConfig, a as RecoverOutcome, b as CeremonyPhase, I as IdentityKind } from './signals-C4JSE_4X.js';
|
|
2
|
+
export { A as ACTIVE_WALLET_STORAGE_KEY, c as ConnectError, d as ContinueResult, e as CreateWalletConfig, f as CreateWalletResult, D as DexterConnectConfig, g as IdentityInput, P as PasskeyLoginTokens, h as PasskeySignalSupport, i as RecoverVault, j as ResolvedIdentity, S as SESSION_TTL_30D, k as SignInResult, l as SpendPolicy, m as StoredWallet, n as authoredPolicy, o as continueWithDexter, p as createWallet, q as ejectActiveWallet, r as forgetWallet, s as getActiveHandle, t as getCredentialId, u as listWallets, v as passkeyLogin, w as passkeySignalSupport, x as prunePasskey, y as renamePasskey, z as resolveIdentity, B as setActiveHandle, E as subscribeWallet, F as switchWallet, G as syncAcceptedPasskeys, H as usdToAtomic } from './signals-C4JSE_4X.js';
|
|
3
3
|
import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
|
|
4
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
5
|
/** What `issueChallenge` returns to the SDK signer. */
|
|
27
6
|
interface AnonChallengeResult {
|
|
28
7
|
/** Server-issued WebAuthn challenge (=== the supplied operationHash). */
|
|
@@ -223,4 +202,4 @@ interface EnableAgentSpendResult {
|
|
|
223
202
|
*/
|
|
224
203
|
declare function enableAgentSpend(id: AgentSpendIdentity, vaultPda: string, apiOrigin: string, credentialId?: string | null): Promise<EnableAgentSpendResult>;
|
|
225
204
|
|
|
226
|
-
export { AgentSpendError, type AgentSpendIdentity, type AgentSpendStatus, type AgentSpendTab, type AnonChallengeResult, type AnonServerPolicy, type AutomaticAgentSpend, CeremonyPhase, ConnectVault, type
|
|
205
|
+
export { AgentSpendError, type AgentSpendIdentity, type AgentSpendStatus, type AgentSpendTab, type AnonChallengeResult, type AnonServerPolicy, type AutomaticAgentSpend, CeremonyPhase, ConnectVault, type EnableAgentSpendResult, IdentityKind, type RawAgentSpendSession, type RawAgentSpendStatus, RecoverOutcome, RecoverWalletConfig, type RevokeAgentSpendResult, assembleAgentSpendStatus, ceremonyPhaseLabel, createAnonServerPolicy, createPasskeySigner, describeAgentSpendError, enableAgentSpend, recoverWallet, revokeAgentSpend };
|
package/dist/index.js
CHANGED
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DexterApiBrowserPasskeySigner } from '@dexterai/vault/signers/browser';
|
|
2
|
-
import { b as CeremonyPhase,
|
|
3
|
-
export {
|
|
2
|
+
import { b as CeremonyPhase, k as SignInResult, a as RecoverOutcome, d as ContinueResult, P as PasskeyLoginTokens, C as ConnectVault, c as ConnectError, m as StoredWallet, h as PasskeySignalSupport, j as ResolvedIdentity, f as CreateWalletResult } from './signals-C4JSE_4X.js';
|
|
3
|
+
export { i as RecoverVault } from './signals-C4JSE_4X.js';
|
|
4
4
|
import { ReactElement, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
type ConnectStatus = 'idle' | 'pending' | 'done' | 'error';
|
|
@@ -35,6 +35,10 @@ interface UseSignInWithDexter {
|
|
|
35
35
|
* light up via the wallet store; `session`/`vault` here stay null. Fire on
|
|
36
36
|
* tap only — never on mount (iOS gesture rule). */
|
|
37
37
|
recover: () => Promise<RecoverOutcome>;
|
|
38
|
+
/** One-button register-or-sign-in (keychain-first; see continueWithDexter).
|
|
39
|
+
* Terminal kinds update session/vault state; needs_create / needs_choice /
|
|
40
|
+
* cancelled return with status back at idle for the caller to route. */
|
|
41
|
+
continueWith: () => Promise<ContinueResult>;
|
|
38
42
|
/** Last recover outcome; null until recover() settles. */
|
|
39
43
|
recovered: RecoverOutcome | null;
|
|
40
44
|
disconnect: () => void;
|
|
@@ -68,14 +72,21 @@ interface SignInWithDexterProps extends UseSignInWithDexterConfig {
|
|
|
68
72
|
* 'recover' = wallet-only: re-points this browser at an existing wallet and
|
|
69
73
|
* mints NOTHING else (the wallet IS the sign-in). After a successful
|
|
70
74
|
* recover the element renders null — identity display belongs to
|
|
71
|
-
* DexterWalletChip/useIdentity, which light up via the wallet store.
|
|
72
|
-
|
|
75
|
+
* DexterWalletChip/useIdentity, which light up via the wallet store.
|
|
76
|
+
* 'continue' = the one-button register-or-sign-in (keychain-first): the
|
|
77
|
+
* hosted popup decides sign-in vs create; every settled outcome fires
|
|
78
|
+
* onContinue. */
|
|
79
|
+
mode?: 'signin' | 'recover' | 'continue';
|
|
73
80
|
/** Fired with the result the moment sign-in completes. */
|
|
74
81
|
onSuccess?: (result: SignInResult) => void;
|
|
75
82
|
/** Recover mode: fired with EVERY settled outcome (ok, no_credential,
|
|
76
83
|
* cancelled, error) — the single channel; onError is not used in this mode.
|
|
77
84
|
* Branch on `reason`: no_credential → offer create; cancelled → stay silent. */
|
|
78
85
|
onRecovered?: (outcome: RecoverOutcome) => void;
|
|
86
|
+
/** Continue mode: fired with EVERY settled ContinueResult (signin, create,
|
|
87
|
+
* needs_create, needs_choice, cancelled) — the single channel for routing.
|
|
88
|
+
* Real ceremony failures still go to onError. */
|
|
89
|
+
onContinue?: (result: ContinueResult) => void;
|
|
79
90
|
/** Fired with the typed error if the ceremony fails. */
|
|
80
91
|
onError?: (error: ConnectError) => void;
|
|
81
92
|
/** Button label when signed out. Default "Sign in with Dexter". */
|
package/dist/react.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
ConnectError,
|
|
3
3
|
authoredPolicy,
|
|
4
4
|
ceremonyPhaseLabel,
|
|
5
|
+
continueWithDexter,
|
|
5
6
|
createPasskeySigner,
|
|
6
7
|
createWallet,
|
|
7
8
|
ejectActiveWallet,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
setActiveHandle,
|
|
18
19
|
subscribe,
|
|
19
20
|
switchWallet
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-VGERNAQ3.js";
|
|
21
22
|
import {
|
|
22
23
|
DexterButton,
|
|
23
24
|
DexterMark,
|
|
@@ -130,6 +131,39 @@ function useSignInWithDexter(config = {}) {
|
|
|
130
131
|
}
|
|
131
132
|
return outcome;
|
|
132
133
|
}, [apiBase, transport, connectHost, preferImmediate]);
|
|
134
|
+
const continueWith = useCallback(async () => {
|
|
135
|
+
setError(null);
|
|
136
|
+
setPhase(null);
|
|
137
|
+
setStatus("pending");
|
|
138
|
+
try {
|
|
139
|
+
const result = await continueWithDexter(
|
|
140
|
+
{
|
|
141
|
+
...apiBase ? { apiBase } : {},
|
|
142
|
+
...transport ? { transport } : {},
|
|
143
|
+
...connectHost ? { connectHost } : {}
|
|
144
|
+
},
|
|
145
|
+
setPhase
|
|
146
|
+
);
|
|
147
|
+
setPhase(null);
|
|
148
|
+
if (result.kind === "signin") {
|
|
149
|
+
setSession(result.session);
|
|
150
|
+
setVault(result.vault ?? null);
|
|
151
|
+
setStatus("done");
|
|
152
|
+
} else if (result.kind === "create") {
|
|
153
|
+
setVault(result.vault);
|
|
154
|
+
setStatus("done");
|
|
155
|
+
} else {
|
|
156
|
+
setStatus("idle");
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
} catch (err) {
|
|
160
|
+
const e = err instanceof ConnectError ? err : new ConnectError("continue_failed", String(err));
|
|
161
|
+
setError(e);
|
|
162
|
+
setStatus("error");
|
|
163
|
+
setPhase(null);
|
|
164
|
+
throw e;
|
|
165
|
+
}
|
|
166
|
+
}, [apiBase, transport, connectHost]);
|
|
133
167
|
const disconnect = useCallback(() => {
|
|
134
168
|
setSession(null);
|
|
135
169
|
setVault(null);
|
|
@@ -151,6 +185,7 @@ function useSignInWithDexter(config = {}) {
|
|
|
151
185
|
isVaultConnected: status === "done" && vault !== null,
|
|
152
186
|
signIn,
|
|
153
187
|
recover,
|
|
188
|
+
continueWith,
|
|
154
189
|
recovered,
|
|
155
190
|
disconnect,
|
|
156
191
|
session,
|
|
@@ -180,6 +215,7 @@ function SignInWithDexter(props) {
|
|
|
180
215
|
onSuccess,
|
|
181
216
|
onError,
|
|
182
217
|
onRecovered,
|
|
218
|
+
onContinue,
|
|
183
219
|
label = "Sign in with Dexter",
|
|
184
220
|
variant = "primary",
|
|
185
221
|
block = false,
|
|
@@ -195,6 +231,14 @@ function SignInWithDexter(props) {
|
|
|
195
231
|
onRecovered?.(await c.recover());
|
|
196
232
|
return;
|
|
197
233
|
}
|
|
234
|
+
if (mode === "continue") {
|
|
235
|
+
try {
|
|
236
|
+
onContinue?.(await c.continueWith());
|
|
237
|
+
} catch (err) {
|
|
238
|
+
onError?.(err);
|
|
239
|
+
}
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
198
242
|
try {
|
|
199
243
|
onSuccess?.(await c.signIn());
|
|
200
244
|
} catch (err) {
|
|
@@ -687,7 +731,7 @@ function vscodeInstallUrl(name, mcpUrl) {
|
|
|
687
731
|
return `vscode:mcp/install?${encodeURIComponent(JSON.stringify({ name, type: "http", url: mcpUrl }))}`;
|
|
688
732
|
}
|
|
689
733
|
function hermesInstallCommand(name, mcpUrl) {
|
|
690
|
-
return `hermes mcp add ${name} --url ${mcpUrl}
|
|
734
|
+
return `hermes mcp add ${name} --url ${mcpUrl}`;
|
|
691
735
|
}
|
|
692
736
|
function claudeCodeInstallCommand(name, mcpUrl) {
|
|
693
737
|
return `claude mcp add --transport http ${name} ${mcpUrl}`;
|
|
@@ -159,6 +159,42 @@ interface CreateWalletResult {
|
|
|
159
159
|
*/
|
|
160
160
|
declare function createWallet(config?: CreateWalletConfig): Promise<CreateWalletResult>;
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* "Sign in with Dexter" — the discoverable-credential login ceremony.
|
|
164
|
+
*
|
|
165
|
+
* 1. POST /login-challenge → a server-issued challenge (no allow-list:
|
|
166
|
+
* the resident passkey itself identifies the user)
|
|
167
|
+
* 2. navigator.credentials.get over that challenge (no allowCredentials)
|
|
168
|
+
* 3. POST /passkey-login → the server resolves the credential + vault,
|
|
169
|
+
* verifies the assertion, and returns a Supabase session (+ the vault
|
|
170
|
+
* payload once vault-review ships the dexter-api change — ASK 1)
|
|
171
|
+
*
|
|
172
|
+
* Relays to dexter-api's ANON router — a first-time third-party user has no
|
|
173
|
+
* Supabase session, so the Supabase-gated router would 401.
|
|
174
|
+
*/
|
|
175
|
+
declare function passkeyLogin(config?: DexterConnectConfig, onPhase?: (phase: CeremonyPhase) => void): Promise<SignInResult>;
|
|
176
|
+
type ContinueResult = ({
|
|
177
|
+
kind: 'signin';
|
|
178
|
+
} & SignInResult) | ({
|
|
179
|
+
kind: 'create';
|
|
180
|
+
} & CreateWalletResult)
|
|
181
|
+
/** This device has no passkey (proven by an immediate fast-fail) but the
|
|
182
|
+
* caller supplied no authored spendPolicy — collect name + allowance,
|
|
183
|
+
* then call createWallet. */
|
|
184
|
+
| {
|
|
185
|
+
kind: 'needs_create';
|
|
186
|
+
}
|
|
187
|
+
/** Cannot silently probe (no immediate support, no local handle): render an
|
|
188
|
+
* explicit "Sign in" / "I'm new" choice. Never guess. */
|
|
189
|
+
| {
|
|
190
|
+
kind: 'needs_choice';
|
|
191
|
+
}
|
|
192
|
+
/** The user dismissed the passkey sheet. Not an error — stay quiet. */
|
|
193
|
+
| {
|
|
194
|
+
kind: 'cancelled';
|
|
195
|
+
};
|
|
196
|
+
declare function continueWithDexter(config?: CreateWalletConfig, onPhase?: (phase: CeremonyPhase) => void): Promise<ContinueResult>;
|
|
197
|
+
|
|
162
198
|
type IdentityKind = 'passkey-vault' | 'account' | 'none';
|
|
163
199
|
interface IdentityInput {
|
|
164
200
|
/** An account session token (e.g. Supabase access_token) when present, else null. */
|
|
@@ -286,4 +322,4 @@ declare function syncAcceptedPasskeys(args: {
|
|
|
286
322
|
rpId?: string;
|
|
287
323
|
}): Promise<boolean>;
|
|
288
324
|
|
|
289
|
-
export { ACTIVE_WALLET_STORAGE_KEY as A,
|
|
325
|
+
export { ACTIVE_WALLET_STORAGE_KEY as A, setActiveHandle as B, type ConnectVault as C, type DexterConnectConfig as D, subscribe as E, switchWallet as F, syncAcceptedPasskeys as G, usdToAtomic as H, type IdentityKind as I, type PasskeyLoginTokens as P, type RecoverWalletConfig as R, SESSION_TTL_30D as S, type RecoverOutcome as a, type CeremonyPhase as b, ConnectError as c, type ContinueResult as d, type CreateWalletConfig as e, type CreateWalletResult as f, type IdentityInput as g, type PasskeySignalSupport as h, type RecoverVault as i, type ResolvedIdentity as j, type SignInResult as k, type SpendPolicy as l, type StoredWallet as m, authoredPolicy as n, continueWithDexter as o, createWallet as p, ejectActiveWallet as q, forgetWallet as r, getActiveHandle as s, getCredentialId as t, listWallets as u, passkeyLogin as v, passkeySignalSupport as w, prunePasskey as x, renamePasskey as y, resolveIdentity as z };
|