@interop/was-react 0.1.11 → 0.2.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.
@@ -28,18 +28,4 @@ export declare function chapiGet({ vpr, mediatorBase }: {
28
28
  vpr: IVPRDetails;
29
29
  mediatorBase?: string;
30
30
  }): Promise<IVerifiablePresentation | null>;
31
- /**
32
- * Offers a VP (wrapping a credential) to the wallet via CHAPI
33
- * `credentials.store()`. Returns true when the wallet confirmed the store,
34
- * false when the user cancelled/dismissed.
35
- *
36
- * @param options {object}
37
- * @param options.presentation {IVerifiablePresentation}
38
- * @param [options.mediatorBase] {string}
39
- * @returns {Promise<boolean>}
40
- */
41
- export declare function chapiStore({ presentation, mediatorBase }: {
42
- presentation: IVerifiablePresentation;
43
- mediatorBase?: string;
44
- }): Promise<boolean>;
45
31
  //# sourceMappingURL=chapi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chapi.d.ts","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D;;GAEG;AACH,eAAO,MAAM,qBAAqB,sCAAsC,CAAA;AAuDxE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,EAC9B,YAAoC,EACrC,GAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EACb,EAAE;IACD,GAAG,EAAE,WAAW,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgB1C;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,EAC/B,YAAY,EACZ,YAAY,EACb,EAAE;IACD,YAAY,EAAE,uBAAuB,CAAA;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB"}
1
+ {"version":3,"file":"chapi.d.ts","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D;;GAEG;AACH,eAAO,MAAM,qBAAqB,sCAAsC,CAAA;AAuDxE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,EAC9B,YAAoC,EACrC,GAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EACb,EAAE;IACD,GAAG,EAAE,WAAW,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgB1C"}
@@ -4,7 +4,9 @@
4
4
  /// <reference types="vite/client" />
5
5
  /**
6
6
  * The CHAPI transport: credential-handler-polyfill loading (authn.io mediator)
7
- * plus thin `get()` / `store()` wrappers around `navigator.credentials`.
7
+ * plus a thin `get()` wrapper around `navigator.credentials`. The one-popup App
8
+ * Connect login rides `get()` alone -- both the app key and the grants come back
9
+ * in a single response VP -- so there is no `store()` wrapper.
8
10
  *
9
11
  * E2E seam (non-production builds only): the real CHAPI channel needs the
10
12
  * mediator's cross-origin handshake, which a test harness cannot perform.
@@ -15,7 +17,7 @@
15
17
  * response into `window.__WAS_REACT_E2E_CHAPI_RESPONSES__[id]`. Responses use
16
18
  * the CHAPI WebCredential wire shape `{ dataType, data } | null`.
17
19
  */
18
- import { loadOnce, WebCredential } from 'credential-handler-polyfill';
20
+ import { loadOnce } from 'credential-handler-polyfill';
19
21
  /**
20
22
  * The default CHAPI mediator base; the requesting origin is appended at load.
21
23
  */
@@ -88,24 +90,4 @@ export async function chapiGet({ vpr, mediatorBase }) {
88
90
  }
89
91
  return wire.data;
90
92
  }
91
- /**
92
- * Offers a VP (wrapping a credential) to the wallet via CHAPI
93
- * `credentials.store()`. Returns true when the wallet confirmed the store,
94
- * false when the user cancelled/dismissed.
95
- *
96
- * @param options {object}
97
- * @param options.presentation {IVerifiablePresentation}
98
- * @param [options.mediatorBase] {string}
99
- * @returns {Promise<boolean>}
100
- */
101
- export async function chapiStore({ presentation, mediatorBase }) {
102
- if (e2eBridgeActive()) {
103
- const wire = await e2eRoundTrip('store', presentation);
104
- return wire !== null && wire.data !== undefined && wire.data !== null;
105
- }
106
- await loadChapi(mediatorBase !== undefined ? { mediatorBase } : {});
107
- const credential = new WebCredential('VerifiablePresentation', presentation);
108
- const result = (await navigator.credentials.store(credential));
109
- return result !== null && result !== undefined;
110
- }
111
93
  //# sourceMappingURL=chapi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chapi.js","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chapi.js","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qCAAqC;AACrC;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAItD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,mCAAmC,CAAA;AAoBxE,SAAS,eAAe;IACtB,OAAO,CACL,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;QACpC,MAA0B,CAAC,uBAAuB,KAAK,IAAI,CAC7D,CAAA;AACH,CAAC;AAED,IAAI,YAAY,GAAG,CAAC,CAAA;AAEpB;;GAEG;AACH,KAAK,UAAU,YAAY,CACzB,IAAqB,EACrB,IAAa;IAEb,MAAM,GAAG,GAAG,MAAyB,CAAA;IACrC,GAAG,CAAC,gCAAgC,KAAK,EAAE,CAAA;IAC3C,GAAG,CAAC,iCAAiC,KAAK,EAAE,CAAA;IAC5C,MAAM,EAAE,GAAG,EAAE,YAAY,CAAA;IACzB,GAAG,CAAC,gCAAgC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;IACrC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,EAAE,IAAI,GAAG,CAAC,iCAAiC,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,GAAG,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAA;YACvD,OAAO,GAAG,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAA;YAChD,OAAO,KAAK,IAAI,IAAI,CAAA;QACtB,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IACxD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;AACvE,CAAC;AAED,IAAI,cAAc,GAAG,KAAK,CAAA;AAE1B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAC9B,YAAY,GAAG,qBAAqB,KAGlC,EAAE;IACJ,IAAI,cAAc,IAAI,eAAe,EAAE,EAAE,CAAC;QACxC,OAAM;IACR,CAAC;IACD,MAAM,QAAQ,CAAC,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IACzE,cAAc,GAAG,IAAI,CAAA;AACvB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EAIb;IACC,IAAI,IAA8B,CAAA;IAClC,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,IAAI,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACvC,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACnE,MAAM,MAAM,GAAG,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC;YAC9C,uEAAuE;YACvE,GAAG,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE;SACT,CAAC,CAAwC,CAAA;QACtE,IAAI,GAAG,MAAM,CAAA;IACf,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3D,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,IAAI,CAAC,IAA+B,CAAA;AAC7C,CAAC"}
@@ -2,15 +2,22 @@
2
2
  * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
3
  */
4
4
  /**
5
- * The Login-With-Wallet orchestration:
5
+ * The Login-With-Wallet orchestration: one-popup App Connect.
6
6
  *
7
- * - First run (the wallet holds no app key): generate a fresh 32-byte master
8
- * seed, self-issue the credential, and BLOCK until the wallet confirms
9
- * storing it (a dismissed store would silently break cross-device recovery),
10
- * then request the storage grants.
11
- * - Returning (the wallet returns the credential): recover the seed, verify
12
- * the credential's self-issue/origin/DID binding, then request grants for
13
- * the same stable controller DID.
7
+ * A single CHAPI `get` carries the {@link buildAppConnectVpr} request. The
8
+ * wallet -- in the same round -- matches an existing app key or mints a fresh
9
+ * one (the first-run branch is wallet-internal now), then returns the app-key
10
+ * credential and the delegated zcaps embedded in one signed response VP. So
11
+ * there is no second store popup and no separate grants popup:
12
+ *
13
+ * - Returning: the wallet returns the credential; we recover the seed and
14
+ * verify its self-issue/origin/DID binding.
15
+ * - First run: the wallet mints the seed, self-issues the same-shaped
16
+ * credential, and marks `presentation.appConnect.firstRun`.
17
+ *
18
+ * A wallet that predates `AppConnectQuery` cannot satisfy it and returns no
19
+ * app-key credential; that surfaces as {@link WalletUnsupportedError} (fail
20
+ * closed, legibly), distinct from a user cancel (a null CHAPI response).
14
21
  *
15
22
  * Hot restore (seed + grants already persisted locally) never reaches this
16
23
  * module -- the caller's session restore short-circuits it.
@@ -55,9 +62,11 @@ export interface LoginConfig {
55
62
  mediatorBase?: string;
56
63
  }
57
64
  /**
58
- * A user-facing progress phase, for the login page's status line.
65
+ * A user-facing progress phase, for the login page's status line. The one-popup
66
+ * App Connect flow has just two: `connecting` (building the request and awaiting
67
+ * the wallet) and `verifying` (checking the wallet's response).
59
68
  */
60
- export type LoginPhase = 'probing' | 'storing-key' | 'requesting-grants' | 'verifying';
69
+ export type LoginPhase = 'connecting' | 'verifying';
61
70
  export interface LoginOutcome {
62
71
  seed: Uint8Array;
63
72
  identity: IdentityAgents;
@@ -79,8 +88,19 @@ export declare class LoginCancelledError extends Error {
79
88
  constructor(step: string);
80
89
  }
81
90
  /**
82
- * Requests storage grants for `identity` and validates them. Shared by the
83
- * login flow and the expired-access reconnect path.
91
+ * Thrown when the wallet answered but returned no app-key credential -- the
92
+ * fail-closed signal that the wallet predates `AppConnectQuery` (it rendered the
93
+ * query unsatisfiable). Distinct from a user cancel so the UI can prompt an
94
+ * update instead of showing a generic verification error.
95
+ */
96
+ export declare class WalletUnsupportedError extends Error {
97
+ constructor();
98
+ }
99
+ /**
100
+ * Re-requests storage grants for `identity` over a fresh App Connect popup and
101
+ * validates them. The expired-access reconnect path: the seed already exists, so
102
+ * only the grants need renewing. The wallet matches the same app key and
103
+ * re-delegates; the returned credential/`appConnect` marker are ignored here.
84
104
  *
85
105
  * @param options {object}
86
106
  * @param options.identity {IdentityAgents}
@@ -94,9 +114,13 @@ export declare function requestGrants({ identity, config, onPhase }: {
94
114
  onPhase?: (phase: LoginPhase) => void;
95
115
  }): Promise<CheckedGrants>;
96
116
  /**
97
- * Runs the full Login-With-Wallet flow (first-run or returning, decided by
98
- * the seed probe). Throws `LoginCancelledError` on dismissal and `Error` on
99
- * verification failures; nothing is persisted here (the caller persists).
117
+ * Runs the one-popup Login-With-Wallet (App Connect) flow. A single CHAPI `get`
118
+ * returns the app-key credential (matched or minted wallet-side) plus the
119
+ * delegated grants in one signed VP. Throws `LoginCancelledError` on a user
120
+ * cancel (a null CHAPI response), `WalletUnsupportedError` when the wallet
121
+ * answered but returned no app key (an old wallet that could not satisfy
122
+ * `AppConnectQuery`), and `Error` on any verification failure. Nothing is
123
+ * persisted here (the caller persists).
100
124
  *
101
125
  * @param options {object}
102
126
  * @param options.config {LoginConfig}
@@ -1 +1 @@
1
- {"version":3,"file":"loginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC;;OAEG;IACH,UAAU,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,cAAc,EAAE,cAAc,CAAA;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GACpB,SAAS,GAAG,aAAa,GAAG,mBAAmB,GAAG,WAAW,CAAA;AAE/D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,EACR,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,aAAa,CAAC,CA+BzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,OAAO,EACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,YAAY,CAAC,CAiFxB"}
1
+ {"version":3,"file":"loginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAEV,KAAK,EACN,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC;;OAEG;IACH,UAAU,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,cAAc,EAAE,cAAc,CAAA;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAQhD;AAwDD;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,EACR,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,aAAa,CAAC,CA+BzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,OAAO,EACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,YAAY,CAAC,CAgExB"}
@@ -1,7 +1,7 @@
1
- import { findSeedCredential, issueSeedCredential, parseSeedCredential, wrapCredentialForStore } from '../identity/seedCredential.js';
1
+ import { findSeedCredential, parseSeedCredential } from '../identity/seedCredential.js';
2
2
  import { initAppSession } from '../identity/initAppSession.js';
3
- import { chapiGet, chapiStore } from './chapi.js';
4
- import { buildGrantsVpr, buildSeedProbeVpr, newChallenge } from './loginRequest.js';
3
+ import { chapiGet } from './chapi.js';
4
+ import { buildAppConnectVpr, newChallenge } from './loginRequest.js';
5
5
  import { checkGrants, grantsOf, verifyLoginPresentation } from './verifyResponse.js';
6
6
  /**
7
7
  * Thrown when the user cancels/dismisses a wallet popup.
@@ -13,8 +13,66 @@ export class LoginCancelledError extends Error {
13
13
  }
14
14
  }
15
15
  /**
16
- * Requests storage grants for `identity` and validates them. Shared by the
17
- * login flow and the expired-access reconnect path.
16
+ * Thrown when the wallet answered but returned no app-key credential -- the
17
+ * fail-closed signal that the wallet predates `AppConnectQuery` (it rendered the
18
+ * query unsatisfiable). Distinct from a user cancel so the UI can prompt an
19
+ * update instead of showing a generic verification error.
20
+ */
21
+ export class WalletUnsupportedError extends Error {
22
+ constructor() {
23
+ super('Your wallet does not support App Connect yet; update Freewallet to ' +
24
+ 'log in.');
25
+ this.name = 'WalletUnsupportedError';
26
+ }
27
+ }
28
+ /**
29
+ * A nominal far-future expiry (ms) used when an app requests no collections (so
30
+ * there are no grants and thus no earliest-expiry to report).
31
+ */
32
+ const NO_GRANTS_EXPIRY_MS = 100 * 365 * 24 * 60 * 60 * 1000;
33
+ /**
34
+ * Reads the wallet-provided `presentation.appConnect.firstRun` boolean. Anything
35
+ * other than boolean `true` (including an absent member -- a returning login) is
36
+ * treated as `false`.
37
+ */
38
+ function appConnectFirstRun(presentation) {
39
+ const appConnect = presentation
40
+ .appConnect;
41
+ return appConnect?.firstRun === true;
42
+ }
43
+ /**
44
+ * Structurally validates the grants embedded in the wallet response against the
45
+ * requested collections. When the app requested NO collections there is nothing
46
+ * to delegate: `checkGrants` (which rejects an empty grant set) is skipped and
47
+ * an empty grant set with a far-future expiry is returned instead.
48
+ *
49
+ * @param options {object}
50
+ * @param options.presentation {IVerifiablePresentation}
51
+ * @param options.controllerDid {string} the app-key subject DID grants must
52
+ * be controlled by
53
+ * @param options.collections {GrantRequestCollection[]}
54
+ * @returns {CheckedGrants}
55
+ */
56
+ function checkGrantsForCollections({ presentation, controllerDid, collections }) {
57
+ const collectionIds = collections.map(collection => collection.id);
58
+ if (collectionIds.length === 0) {
59
+ return {
60
+ grants: [],
61
+ parsed: { serverUrl: '', spaceId: '', byCollectionId: {} },
62
+ expires: new Date(Date.now() + NO_GRANTS_EXPIRY_MS).toISOString()
63
+ };
64
+ }
65
+ return checkGrants({
66
+ grants: grantsOf(presentation),
67
+ controllerDid,
68
+ collections: collectionIds
69
+ });
70
+ }
71
+ /**
72
+ * Re-requests storage grants for `identity` over a fresh App Connect popup and
73
+ * validates them. The expired-access reconnect path: the seed already exists, so
74
+ * only the grants need renewing. The wallet matches the same app key and
75
+ * re-delegates; the returned credential/`appConnect` marker are ignored here.
18
76
  *
19
77
  * @param options {object}
20
78
  * @param options.identity {IdentityAgents}
@@ -23,14 +81,14 @@ export class LoginCancelledError extends Error {
23
81
  * @returns {Promise<CheckedGrants>}
24
82
  */
25
83
  export async function requestGrants({ identity, config, onPhase }) {
26
- onPhase?.('requesting-grants');
84
+ onPhase?.('connecting');
27
85
  const challenge = newChallenge();
28
- const vpr = buildGrantsVpr({
86
+ const vpr = buildAppConnectVpr({
29
87
  challenge,
30
88
  domain: window.location.origin,
31
- controllerDid: identity.controllerDid,
32
- collections: config.collections,
33
- appName: config.appName
89
+ appName: config.appName,
90
+ credential: config.credential,
91
+ collections: config.collections
34
92
  });
35
93
  const presentation = await chapiGet({
36
94
  vpr,
@@ -48,16 +106,20 @@ export async function requestGrants({ identity, config, onPhase }) {
48
106
  domain: window.location.origin,
49
107
  documentLoader: config.documentLoader
50
108
  });
51
- return checkGrants({
52
- grants: grantsOf(presentation),
109
+ return checkGrantsForCollections({
110
+ presentation,
53
111
  controllerDid: identity.controllerDid,
54
- collections: config.collections.map(collection => collection.id)
112
+ collections: config.collections
55
113
  });
56
114
  }
57
115
  /**
58
- * Runs the full Login-With-Wallet flow (first-run or returning, decided by
59
- * the seed probe). Throws `LoginCancelledError` on dismissal and `Error` on
60
- * verification failures; nothing is persisted here (the caller persists).
116
+ * Runs the one-popup Login-With-Wallet (App Connect) flow. A single CHAPI `get`
117
+ * returns the app-key credential (matched or minted wallet-side) plus the
118
+ * delegated grants in one signed VP. Throws `LoginCancelledError` on a user
119
+ * cancel (a null CHAPI response), `WalletUnsupportedError` when the wallet
120
+ * answered but returned no app key (an old wallet that could not satisfy
121
+ * `AppConnectQuery`), and `Error` on any verification failure. Nothing is
122
+ * persisted here (the caller persists).
61
123
  *
62
124
  * @param options {object}
63
125
  * @param options.config {LoginConfig}
@@ -65,76 +127,58 @@ export async function requestGrants({ identity, config, onPhase }) {
65
127
  * @returns {Promise<LoginOutcome>}
66
128
  */
67
129
  export async function loginWithWallet({ config, onPhase }) {
68
- // Popup #1: probe the wallet for an existing app key.
69
- onPhase?.('probing');
70
- const probeChallenge = newChallenge();
71
- const probeVpr = buildSeedProbeVpr({
72
- challenge: probeChallenge,
130
+ onPhase?.('connecting');
131
+ const challenge = newChallenge();
132
+ const vpr = buildAppConnectVpr({
133
+ challenge,
73
134
  domain: window.location.origin,
74
- credentialType: config.credential.credentialType,
75
- appName: config.appName
135
+ appName: config.appName,
136
+ credential: config.credential,
137
+ collections: config.collections
76
138
  });
77
- const probeVp = await chapiGet({
78
- vpr: probeVpr,
139
+ const presentation = await chapiGet({
140
+ vpr,
79
141
  ...(config.mediatorBase !== undefined && {
80
142
  mediatorBase: config.mediatorBase
81
143
  })
82
144
  });
83
- if (!probeVp) {
145
+ if (!presentation) {
84
146
  throw new LoginCancelledError('wallet login');
85
147
  }
148
+ onPhase?.('verifying');
86
149
  await verifyLoginPresentation({
87
- presentation: probeVp,
88
- challenge: probeChallenge,
150
+ presentation,
151
+ challenge,
89
152
  domain: window.location.origin,
90
153
  documentLoader: config.documentLoader
91
154
  });
92
- let seed;
93
- let firstRun;
155
+ // The wallet mints the app key on first run, so a response with no app-key
156
+ // credential is not first run -- it is a wallet that could not satisfy
157
+ // `AppConnectQuery` at all. Fail closed, legibly, rather than as a generic
158
+ // verification error.
94
159
  const credential = findSeedCredential({
95
- presentation: probeVp,
160
+ presentation,
96
161
  credentialType: config.credential.credentialType
97
162
  });
98
- if (credential) {
99
- // Returning login: recover the seed, enforce self-issue + origin + the
100
- // seed-to-DID binding.
101
- const parsed = await parseSeedCredential({
102
- credential,
103
- origin: config.appOrigin,
104
- config: config.credential
105
- });
106
- seed = parsed.seed;
107
- firstRun = false;
108
- }
109
- else {
110
- // First run: mint a fresh master seed and store its credential in the
111
- // wallet. Block until the store succeeds -- without it, cross-device
112
- // recovery is silently broken.
113
- seed = crypto.getRandomValues(new Uint8Array(32));
114
- firstRun = true;
115
- onPhase?.('storing-key');
116
- const issued = await issueSeedCredential({
117
- seed,
118
- origin: config.appOrigin,
119
- config: config.credential,
120
- documentLoader: config.documentLoader
121
- });
122
- const stored = await chapiStore({
123
- presentation: wrapCredentialForStore(issued),
124
- ...(config.mediatorBase !== undefined && {
125
- mediatorBase: config.mediatorBase
126
- })
127
- });
128
- if (!stored) {
129
- throw new LoginCancelledError('saving your app key to the wallet');
130
- }
163
+ if (!credential) {
164
+ throw new WalletUnsupportedError();
131
165
  }
166
+ // Recover the seed, enforcing self-issue + origin + the seed-to-DID binding
167
+ // (the same contract whether the wallet matched or minted the credential).
168
+ const parsedCredential = await parseSeedCredential({
169
+ credential,
170
+ origin: config.appOrigin,
171
+ config: config.credential
172
+ });
173
+ const seed = parsedCredential.seed;
174
+ const firstRun = appConnectFirstRun(presentation);
132
175
  const identity = await initAppSession({ seed });
133
- // Popup #2: request the storage grants for the stable controller DID.
134
- const checked = await requestGrants({
135
- identity,
136
- config,
137
- ...(onPhase && { onPhase })
176
+ // Grants ride in the SAME response; validate them against the app-key subject
177
+ // DID the wallet delegated to.
178
+ const checked = checkGrantsForCollections({
179
+ presentation,
180
+ controllerDid: parsedCredential.controllerDid,
181
+ collections: config.collections
138
182
  });
139
183
  return {
140
184
  seed,
@@ -1 +1 @@
1
- {"version":3,"file":"loginFlow.js","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loginFlow.js","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"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"}
@@ -2,27 +2,32 @@
2
2
  * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
3
  */
4
4
  /**
5
- * RP-side VPR construction for Login With Wallet. Two requests:
5
+ * RP-side VPR construction for Login With Wallet: the one-popup App Connect
6
+ * request.
6
7
  *
7
- * 1. The seed probe: DIDAuthentication + QueryByExample for the app-key
8
- * credential. An empty result is the first-run signal; a hit recovers the
9
- * master seed on a new device.
10
- * 2. The grants request: DIDAuthentication + AuthorizationCapabilityQuery with
11
- * one capabilityQuery per collection (descriptor-object targets, which the
12
- * wallet resolves against the user's one Space and auto-provisions). Only
13
- * collection-scoped capabilities are requested -- no whole-space grant.
14
- * A `visibility: 'public'` collection is requested with the distinct
15
- * descriptor type `urn:was:public-collection` (the wallet provisions it
16
- * plaintext with a collection-level public-read policy and renders a
17
- * world-readable consent warning); wallets that predate the type render it
18
- * UNSATISFIABLE, which is the intended fail-closed behavior -- an older
19
- * wallet must not silently provision a private collection the app believes
20
- * is public.
8
+ * A single CHAPI `get` carries DIDAuthentication plus an `AppConnectQuery` that
9
+ * names the app (for the wallet's consent screen), the seed-credential naming
10
+ * the wallet needs to MATCH an existing app key or MINT a fresh one, and one
11
+ * collection-scoped capabilityQuery per requested collection. The wallet
12
+ * responds -- in the same round -- with the app-key credential and the
13
+ * delegated zcaps embedded in the response VP, so first-run and returning are a
14
+ * single request/response with no store popup and no separate grants popup.
15
+ *
16
+ * Only collection-scoped capabilities are requested (no whole-space grant). A
17
+ * `visibility: 'public'` collection is requested with the distinct descriptor
18
+ * type `urn:was:public-collection` (the wallet provisions it plaintext with a
19
+ * collection-level public-read policy and renders a world-readable consent
20
+ * warning); wallets that predate the type render it UNSATISFIABLE, which is the
21
+ * intended fail-closed behavior -- an older wallet must not silently provision a
22
+ * private collection the app believes is public. The App Connect query as a
23
+ * whole is likewise unsatisfiable on a wallet that predates it, so an old wallet
24
+ * fails closed rather than degrading into a partial generic flow.
21
25
  *
22
26
  * `domain` must host-match the CHAPI requesting origin or the wallet refuses
23
27
  * to sign; `challenge` must be fresh per request (echoed into the DIDAuth
24
28
  * proof and checked in verifyResponse).
25
29
  */
30
+ import type { SeedCredentialConfig } from '../identity/seedCredential.js';
26
31
  import type { IVPRDetails } from './walletRequestTypes.js';
27
32
  /**
28
33
  * Default read/write actions requested on each app collection.
@@ -49,45 +54,37 @@ export interface GrantRequestCollection {
49
54
  */
50
55
  export declare function newChallenge(): string;
51
56
  /**
52
- * VPR #1: DIDAuthentication + QueryByExample for the app-key credential.
57
+ * The one-popup App Connect VPR: DIDAuthentication + a single `AppConnectQuery`.
53
58
  *
54
- * @param options {object}
55
- * @param options.challenge {string}
56
- * @param options.domain {string}
57
- * @param options.credentialType {string} the app's seed-credential type name
58
- * @param options.appName {string} human-readable app name for the reason line
59
- * @returns {IVPRDetails}
60
- */
61
- export declare function buildSeedProbeVpr({ challenge, domain, credentialType, appName }: {
62
- challenge: string;
63
- domain: string;
64
- credentialType: string;
65
- appName: string;
66
- }): IVPRDetails;
67
- /**
68
- * VPR #2: DIDAuthentication + AuthorizationCapabilityQuery -- one read/write
69
- * capabilityQuery per app collection (delegated to `controllerDid`). Only
70
- * collection-scoped capabilities are requested. A `visibility: 'public'`
71
- * collection uses the `urn:was:public-collection` descriptor type; everything
72
- * else uses `urn:was:collection`.
59
+ * The `app` block names the app (for the wallet's consent screen) and carries
60
+ * the seed-credential naming (`credentialType`/`vocabBase`) the wallet needs to
61
+ * MATCH an existing app key or MINT a fresh one. `capabilityQuery` holds one
62
+ * collection-scoped grant request per app collection -- the existing capability
63
+ * shape MINUS `controller` (the wallet fills it with the app-key subject DID)
64
+ * and MINUS `reason` (the App Connect consent screen supersedes per-grant
65
+ * reasons). A `visibility: 'public'` collection uses the
66
+ * `urn:was:public-collection` descriptor type; everything else uses
67
+ * `urn:was:collection`.
73
68
  *
74
69
  * @param options {object}
75
70
  * @param options.challenge {string}
76
71
  * @param options.domain {string}
77
- * @param options.controllerDid {string}
72
+ * @param options.appName {string} human-readable app name for the consent
73
+ * screen
74
+ * @param options.credential {SeedCredentialConfig} the app's seed-credential
75
+ * type name + vocabulary namespace (match / mint)
78
76
  * @param options.collections {GrantRequestCollection[]} the collections to
79
77
  * request (WAS collection id + visibility)
80
- * @param options.appName {string} human-readable app name for the reason line
81
78
  * @param [options.actions] {string[]} the RW action set (defaults to
82
79
  * `RW_ACTIONS`)
83
80
  * @returns {IVPRDetails}
84
81
  */
85
- export declare function buildGrantsVpr({ challenge, domain, controllerDid, collections, appName, actions }: {
82
+ export declare function buildAppConnectVpr({ challenge, domain, appName, credential, collections, actions }: {
86
83
  challenge: string;
87
84
  domain: string;
88
- controllerDid: string;
89
- collections: GrantRequestCollection[];
90
85
  appName: string;
86
+ credential: SeedCredentialConfig;
87
+ collections: GrantRequestCollection[];
91
88
  actions?: string[];
92
89
  }): IVPRDetails;
93
90
  //# sourceMappingURL=loginRequest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loginRequest.d.ts","sourceRoot":"","sources":["../../src/auth/loginRequest.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,yBAAyB,CAAA;AAEhC;;GAEG;AACH,eAAO,MAAM,UAAU,UAA2C,CAAA;AAElE;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;CAClC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,MAAM,EACN,cAAc,EACd,OAAO,EACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,WAAW,CAkBd;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,MAAM,EACN,aAAa,EACb,WAAW,EACX,OAAO,EACP,OAAoB,EACrB,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB,GAAG,WAAW,CA8Bd"}
1
+ {"version":3,"file":"loginRequest.d.ts","sourceRoot":"","sources":["../../src/auth/loginRequest.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,yBAAyB,CAAA;AAEhC;;GAEG;AACH,eAAO,MAAM,UAAU,UAA2C,CAAA;AAElE;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;CAClC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,MAAM,EACN,OAAO,EACP,UAAU,EACV,WAAW,EACX,OAAoB,EACrB,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,oBAAoB,CAAA;IAChC,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB,GAAG,WAAW,CAiCd"}