@openvtc/pnm-core 0.1.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.
Files changed (250) hide show
  1. package/README.md +129 -0
  2. package/dist/did/derive-signing-key.d.ts +19 -0
  3. package/dist/did/derive-signing-key.d.ts.map +1 -0
  4. package/dist/did/derive-signing-key.js +96 -0
  5. package/dist/did/derive-signing-key.js.map +1 -0
  6. package/dist/did/index.d.ts +5 -0
  7. package/dist/did/index.d.ts.map +1 -0
  8. package/dist/did/index.js +5 -0
  9. package/dist/did/index.js.map +1 -0
  10. package/dist/did/peer.d.ts +37 -0
  11. package/dist/did/peer.d.ts.map +1 -0
  12. package/dist/did/peer.js +49 -0
  13. package/dist/did/peer.js.map +1 -0
  14. package/dist/did/verification-method.d.ts +43 -0
  15. package/dist/did/verification-method.d.ts.map +1 -0
  16. package/dist/did/verification-method.js +32 -0
  17. package/dist/did/verification-method.js.map +1 -0
  18. package/dist/did/verify.d.ts +49 -0
  19. package/dist/did/verify.d.ts.map +1 -0
  20. package/dist/did/verify.js +89 -0
  21. package/dist/did/verify.js.map +1 -0
  22. package/dist/didcomm/index.d.ts +235 -0
  23. package/dist/didcomm/index.d.ts.map +1 -0
  24. package/dist/didcomm/index.js +415 -0
  25. package/dist/didcomm/index.js.map +1 -0
  26. package/dist/inbound/confirm.d.ts +50 -0
  27. package/dist/inbound/confirm.d.ts.map +1 -0
  28. package/dist/inbound/confirm.js +64 -0
  29. package/dist/inbound/confirm.js.map +1 -0
  30. package/dist/inbound/dedup.d.ts +9 -0
  31. package/dist/inbound/dedup.d.ts.map +1 -0
  32. package/dist/inbound/dedup.js +31 -0
  33. package/dist/inbound/dedup.js.map +1 -0
  34. package/dist/inbound/index.d.ts +3 -0
  35. package/dist/inbound/index.d.ts.map +1 -0
  36. package/dist/inbound/index.js +3 -0
  37. package/dist/inbound/index.js.map +1 -0
  38. package/dist/index.d.ts +14 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +14 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/onboarding/index.d.ts +2 -0
  43. package/dist/onboarding/index.d.ts.map +1 -0
  44. package/dist/onboarding/index.js +2 -0
  45. package/dist/onboarding/index.js.map +1 -0
  46. package/dist/onboarding/swap.d.ts +60 -0
  47. package/dist/onboarding/swap.d.ts.map +1 -0
  48. package/dist/onboarding/swap.js +148 -0
  49. package/dist/onboarding/swap.js.map +1 -0
  50. package/dist/provision/adopt.d.ts +31 -0
  51. package/dist/provision/adopt.d.ts.map +1 -0
  52. package/dist/provision/adopt.js +114 -0
  53. package/dist/provision/adopt.js.map +1 -0
  54. package/dist/provision/armor.d.ts +19 -0
  55. package/dist/provision/armor.d.ts.map +1 -0
  56. package/dist/provision/armor.js +243 -0
  57. package/dist/provision/armor.js.map +1 -0
  58. package/dist/provision/crc24.d.ts +5 -0
  59. package/dist/provision/crc24.d.ts.map +1 -0
  60. package/dist/provision/crc24.js +30 -0
  61. package/dist/provision/crc24.js.map +1 -0
  62. package/dist/provision/hpke.d.ts +17 -0
  63. package/dist/provision/hpke.d.ts.map +1 -0
  64. package/dist/provision/hpke.js +60 -0
  65. package/dist/provision/hpke.js.map +1 -0
  66. package/dist/provision/index.d.ts +10 -0
  67. package/dist/provision/index.d.ts.map +1 -0
  68. package/dist/provision/index.js +16 -0
  69. package/dist/provision/index.js.map +1 -0
  70. package/dist/provision/open.d.ts +28 -0
  71. package/dist/provision/open.d.ts.map +1 -0
  72. package/dist/provision/open.js +224 -0
  73. package/dist/provision/open.js.map +1 -0
  74. package/dist/provision/request.d.ts +65 -0
  75. package/dist/provision/request.d.ts.map +1 -0
  76. package/dist/provision/request.js +53 -0
  77. package/dist/provision/request.js.map +1 -0
  78. package/dist/provision/run.d.ts +76 -0
  79. package/dist/provision/run.d.ts.map +1 -0
  80. package/dist/provision/run.js +110 -0
  81. package/dist/provision/run.js.map +1 -0
  82. package/dist/provision/send.d.ts +85 -0
  83. package/dist/provision/send.d.ts.map +1 -0
  84. package/dist/provision/send.js +87 -0
  85. package/dist/provision/send.js.map +1 -0
  86. package/dist/provision/types.d.ts +110 -0
  87. package/dist/provision/types.d.ts.map +1 -0
  88. package/dist/provision/types.js +17 -0
  89. package/dist/provision/types.js.map +1 -0
  90. package/dist/rp-login/didcomm.d.ts +34 -0
  91. package/dist/rp-login/didcomm.d.ts.map +1 -0
  92. package/dist/rp-login/didcomm.js +72 -0
  93. package/dist/rp-login/didcomm.js.map +1 -0
  94. package/dist/rp-login/index.d.ts +3 -0
  95. package/dist/rp-login/index.d.ts.map +1 -0
  96. package/dist/rp-login/index.js +3 -0
  97. package/dist/rp-login/index.js.map +1 -0
  98. package/dist/rp-login/step-up.d.ts +43 -0
  99. package/dist/rp-login/step-up.d.ts.map +1 -0
  100. package/dist/rp-login/step-up.js +118 -0
  101. package/dist/rp-login/step-up.js.map +1 -0
  102. package/dist/siop/index.d.ts +3 -0
  103. package/dist/siop/index.d.ts.map +1 -0
  104. package/dist/siop/index.js +3 -0
  105. package/dist/siop/index.js.map +1 -0
  106. package/dist/siop/login-client.d.ts +29 -0
  107. package/dist/siop/login-client.d.ts.map +1 -0
  108. package/dist/siop/login-client.js +79 -0
  109. package/dist/siop/login-client.js.map +1 -0
  110. package/dist/siop/self-issued.d.ts +96 -0
  111. package/dist/siop/self-issued.d.ts.map +1 -0
  112. package/dist/siop/self-issued.js +162 -0
  113. package/dist/siop/self-issued.js.map +1 -0
  114. package/dist/store/holder-identity.d.ts +241 -0
  115. package/dist/store/holder-identity.d.ts.map +1 -0
  116. package/dist/store/holder-identity.js +441 -0
  117. package/dist/store/holder-identity.js.map +1 -0
  118. package/dist/store/index.d.ts +4 -0
  119. package/dist/store/index.d.ts.map +1 -0
  120. package/dist/store/index.js +4 -0
  121. package/dist/store/index.js.map +1 -0
  122. package/dist/store/kv-store.d.ts +51 -0
  123. package/dist/store/kv-store.d.ts.map +1 -0
  124. package/dist/store/kv-store.js +100 -0
  125. package/dist/store/kv-store.js.map +1 -0
  126. package/dist/store/secret-wrap.d.ts +109 -0
  127. package/dist/store/secret-wrap.d.ts.map +1 -0
  128. package/dist/store/secret-wrap.js +85 -0
  129. package/dist/store/secret-wrap.js.map +1 -0
  130. package/dist/trust-tasks/index.d.ts +2 -0
  131. package/dist/trust-tasks/index.d.ts.map +1 -0
  132. package/dist/trust-tasks/index.js +2 -0
  133. package/dist/trust-tasks/index.js.map +1 -0
  134. package/dist/trust-tasks/sign.d.ts +31 -0
  135. package/dist/trust-tasks/sign.d.ts.map +1 -0
  136. package/dist/trust-tasks/sign.js +141 -0
  137. package/dist/trust-tasks/sign.js.map +1 -0
  138. package/dist/util/timing.d.ts +14 -0
  139. package/dist/util/timing.d.ts.map +1 -0
  140. package/dist/util/timing.js +20 -0
  141. package/dist/util/timing.js.map +1 -0
  142. package/dist/vault/delete.d.ts +19 -0
  143. package/dist/vault/delete.d.ts.map +1 -0
  144. package/dist/vault/delete.js +35 -0
  145. package/dist/vault/delete.js.map +1 -0
  146. package/dist/vault/index.d.ts +8 -0
  147. package/dist/vault/index.d.ts.map +1 -0
  148. package/dist/vault/index.js +7 -0
  149. package/dist/vault/index.js.map +1 -0
  150. package/dist/vault/list.d.ts +96 -0
  151. package/dist/vault/list.d.ts.map +1 -0
  152. package/dist/vault/list.js +106 -0
  153. package/dist/vault/list.js.map +1 -0
  154. package/dist/vault/proxy-login.d.ts +100 -0
  155. package/dist/vault/proxy-login.d.ts.map +1 -0
  156. package/dist/vault/proxy-login.js +106 -0
  157. package/dist/vault/proxy-login.js.map +1 -0
  158. package/dist/vault/release.d.ts +33 -0
  159. package/dist/vault/release.d.ts.map +1 -0
  160. package/dist/vault/release.js +83 -0
  161. package/dist/vault/release.js.map +1 -0
  162. package/dist/vault/sign-trust-task.d.ts +26 -0
  163. package/dist/vault/sign-trust-task.d.ts.map +1 -0
  164. package/dist/vault/sign-trust-task.js +53 -0
  165. package/dist/vault/sign-trust-task.js.map +1 -0
  166. package/dist/vault/transport.d.ts +50 -0
  167. package/dist/vault/transport.d.ts.map +1 -0
  168. package/dist/vault/transport.js +118 -0
  169. package/dist/vault/transport.js.map +1 -0
  170. package/dist/vault/upsert.d.ts +102 -0
  171. package/dist/vault/upsert.d.ts.map +1 -0
  172. package/dist/vault/upsert.js +92 -0
  173. package/dist/vault/upsert.js.map +1 -0
  174. package/dist/vta/bridge-mediator-session.d.ts +26 -0
  175. package/dist/vta/bridge-mediator-session.d.ts.map +1 -0
  176. package/dist/vta/bridge-mediator-session.js +37 -0
  177. package/dist/vta/bridge-mediator-session.js.map +1 -0
  178. package/dist/vta/bridge-memory.d.ts +80 -0
  179. package/dist/vta/bridge-memory.d.ts.map +1 -0
  180. package/dist/vta/bridge-memory.js +162 -0
  181. package/dist/vta/bridge-memory.js.map +1 -0
  182. package/dist/vta/client.d.ts +40 -0
  183. package/dist/vta/client.d.ts.map +1 -0
  184. package/dist/vta/client.js +91 -0
  185. package/dist/vta/client.js.map +1 -0
  186. package/dist/vta/contexts.d.ts +60 -0
  187. package/dist/vta/contexts.d.ts.map +1 -0
  188. package/dist/vta/contexts.js +118 -0
  189. package/dist/vta/contexts.js.map +1 -0
  190. package/dist/vta/didcomm.d.ts +57 -0
  191. package/dist/vta/didcomm.d.ts.map +1 -0
  192. package/dist/vta/didcomm.js +138 -0
  193. package/dist/vta/didcomm.js.map +1 -0
  194. package/dist/vta/errors.d.ts +20 -0
  195. package/dist/vta/errors.d.ts.map +1 -0
  196. package/dist/vta/errors.js +64 -0
  197. package/dist/vta/errors.js.map +1 -0
  198. package/dist/vta/index.d.ts +15 -0
  199. package/dist/vta/index.d.ts.map +1 -0
  200. package/dist/vta/index.js +15 -0
  201. package/dist/vta/index.js.map +1 -0
  202. package/dist/vta/mediation.d.ts +80 -0
  203. package/dist/vta/mediation.d.ts.map +1 -0
  204. package/dist/vta/mediation.js +29 -0
  205. package/dist/vta/mediation.js.map +1 -0
  206. package/dist/vta/mediator-client.d.ts +66 -0
  207. package/dist/vta/mediator-client.d.ts.map +1 -0
  208. package/dist/vta/mediator-client.js +139 -0
  209. package/dist/vta/mediator-client.js.map +1 -0
  210. package/dist/vta/pickup.d.ts +81 -0
  211. package/dist/vta/pickup.d.ts.map +1 -0
  212. package/dist/vta/pickup.js +30 -0
  213. package/dist/vta/pickup.js.map +1 -0
  214. package/dist/vta/protocol.d.ts +76 -0
  215. package/dist/vta/protocol.d.ts.map +1 -0
  216. package/dist/vta/protocol.js +30 -0
  217. package/dist/vta/protocol.js.map +1 -0
  218. package/dist/vta/smoke.d.ts +59 -0
  219. package/dist/vta/smoke.d.ts.map +1 -0
  220. package/dist/vta/smoke.js +408 -0
  221. package/dist/vta/smoke.js.map +1 -0
  222. package/dist/vta/transport.d.ts +55 -0
  223. package/dist/vta/transport.d.ts.map +1 -0
  224. package/dist/vta/transport.js +2 -0
  225. package/dist/vta/transport.js.map +1 -0
  226. package/dist/vta/types.d.ts +50 -0
  227. package/dist/vta/types.d.ts.map +1 -0
  228. package/dist/vta/types.js +2 -0
  229. package/dist/vta/types.js.map +1 -0
  230. package/dist/vta/wallet-session.d.ts +87 -0
  231. package/dist/vta/wallet-session.d.ts.map +1 -0
  232. package/dist/vta/wallet-session.js +106 -0
  233. package/dist/vta/wallet-session.js.map +1 -0
  234. package/dist/webauthn/base64url.d.ts +3 -0
  235. package/dist/webauthn/base64url.d.ts.map +1 -0
  236. package/dist/webauthn/base64url.js +17 -0
  237. package/dist/webauthn/base64url.js.map +1 -0
  238. package/dist/webauthn/index.d.ts +4 -0
  239. package/dist/webauthn/index.d.ts.map +1 -0
  240. package/dist/webauthn/index.js +4 -0
  241. package/dist/webauthn/index.js.map +1 -0
  242. package/dist/webauthn/multikey.d.ts +26 -0
  243. package/dist/webauthn/multikey.d.ts.map +1 -0
  244. package/dist/webauthn/multikey.js +91 -0
  245. package/dist/webauthn/multikey.js.map +1 -0
  246. package/dist/webauthn/register.d.ts +36 -0
  247. package/dist/webauthn/register.d.ts.map +1 -0
  248. package/dist/webauthn/register.js +77 -0
  249. package/dist/webauthn/register.js.map +1 -0
  250. package/package.json +56 -0
@@ -0,0 +1,118 @@
1
+ // Shared transport for the vault/* Trust Task REST surface.
2
+ //
3
+ // Two helpers, reused by every vault/* operation (upsert, delete, release,
4
+ // and — eventually — list/get when they're migrated off the inlined auth
5
+ // flow in `list.ts`):
6
+ //
7
+ // - `getVtaBearer` — runs the canonical /auth/challenge → DIDComm
8
+ // authcrypt → /auth/ → bearer-token round-trip. Same auth primitive
9
+ // `swapAclRest` and `vaultListRest` already use.
10
+ // - `postTrustTask` — POSTs an authenticated Trust Task envelope to
11
+ // /api/trust-tasks and validates the response shape.
12
+ //
13
+ // Token caching is NOT done here. Each vault op currently does a fresh
14
+ // auth round-trip — adding session-token caching is a separate concern
15
+ // that lands when sync/event/0.1 (M5) needs a long-lived authenticated
16
+ // connection anyway.
17
+ import { packAuthcrypt } from "../didcomm/index.js";
18
+ const VTA_AUTHENTICATE = "https://affinidi.com/atm/1.0/authenticate";
19
+ /**
20
+ * Run /auth/challenge → authcrypt /auth/ → bearer token. The token's
21
+ * 15-minute TTL is more than enough for a single trust-task POST; we
22
+ * don't cache because the next vault op happens whenever the user
23
+ * clicks something and would likely fall outside the cache window.
24
+ */
25
+ export async function getVtaBearer(opts) {
26
+ const f = opts.fetch ?? fetch.bind(globalThis);
27
+ const base = opts.baseUrl.replace(/\/+$/, "");
28
+ // 1. /auth/challenge → flat { challenge, sessionId, expiresAt }.
29
+ const cRes = await f(`${base}/auth/challenge`, {
30
+ method: "POST",
31
+ headers: { "content-type": "application/json" },
32
+ body: JSON.stringify({ did: opts.holder.did }),
33
+ });
34
+ if (!cRes.ok) {
35
+ throw new Error(`vta /auth/challenge failed (${cRes.status}): ${await cRes.text()}`);
36
+ }
37
+ const cBody = (await cRes.json());
38
+ if (!cBody.sessionId || !cBody.challenge) {
39
+ throw new Error(`vta /auth/challenge: malformed response: ${JSON.stringify(cBody)}`);
40
+ }
41
+ // 2. Authcrypt an `atm/1.0/authenticate` message to the VTA.
42
+ const authMsg = {
43
+ id: globalThis.crypto.randomUUID(),
44
+ type: VTA_AUTHENTICATE,
45
+ from: opts.holder.did,
46
+ to: [opts.service.did],
47
+ body: { challenge: cBody.challenge, session_id: cBody.sessionId },
48
+ };
49
+ const packed = await packAuthcrypt(authMsg, opts.holder, [
50
+ {
51
+ kid: opts.service.keyAgreementKid,
52
+ jwk: opts.service.keyAgreementPublicJwk,
53
+ },
54
+ ]);
55
+ // 3. POST → AuthenticateResponse { session, tokens: { accessToken, ... } }.
56
+ const aRes = await f(`${base}/auth/`, {
57
+ method: "POST",
58
+ headers: { "content-type": "application/didcomm-encrypted+json" },
59
+ body: packed,
60
+ });
61
+ if (!aRes.ok) {
62
+ throw new Error(`vta /auth/ failed (${aRes.status}): ${await aRes.text()}`);
63
+ }
64
+ const aBody = (await aRes.json());
65
+ const accessToken = aBody.tokens?.accessToken;
66
+ if (!accessToken) {
67
+ throw new Error(`vta /auth/: malformed response: ${JSON.stringify(aBody)}`);
68
+ }
69
+ return accessToken;
70
+ }
71
+ /**
72
+ * POST an authenticated Trust Task envelope to /api/trust-tasks. The
73
+ * framework's dispatcher returns either a `<task>#response` document
74
+ * (success) or a `trust-task-error/0.1` document (reject). This helper
75
+ * differentiates the two: success returns the parsed `payload` cast as
76
+ * `R`; reject throws an `Error` carrying the framework's error code +
77
+ * comment so callers see "vault/upsert:version_conflict — ..." rather
78
+ * than a raw 400.
79
+ */
80
+ export async function postTrustTask(opts) {
81
+ const f = opts.fetch ?? fetch.bind(globalThis);
82
+ const base = opts.baseUrl.replace(/\/+$/, "");
83
+ const op = opts.operationLabel ?? opts.envelope.type;
84
+ const reqId = globalThis.crypto.randomUUID();
85
+ const fullEnvelope = {
86
+ id: reqId,
87
+ type: opts.envelope.type,
88
+ ...(opts.envelope.issuer ? { issuer: opts.envelope.issuer } : {}),
89
+ ...(opts.envelope.recipient ? { recipient: opts.envelope.recipient } : {}),
90
+ issuedAt: new Date().toISOString(),
91
+ payload: opts.envelope.payload,
92
+ };
93
+ const res = await f(`${base}/api/trust-tasks`, {
94
+ method: "POST",
95
+ headers: {
96
+ "content-type": "application/json",
97
+ authorization: `Bearer ${opts.bearer}`,
98
+ },
99
+ body: JSON.stringify(fullEnvelope),
100
+ });
101
+ if (!res.ok) {
102
+ throw new Error(`${op}: /api/trust-tasks failed (${res.status}): ${await res.text()}`);
103
+ }
104
+ const doc = (await res.json());
105
+ if (doc.type === opts.expectedResponseType) {
106
+ return doc.payload;
107
+ }
108
+ // Trust Task error envelope: type = trust-task-error/0.1 with
109
+ // payload.code = "<slug>:<error>" and payload.comment = explanation.
110
+ if (doc.type === "https://trusttasks.org/spec/trust-task-error/0.1") {
111
+ const errPayload = doc.payload;
112
+ const code = errPayload?.code ?? "unknown";
113
+ const comment = errPayload?.comment ?? "(no comment)";
114
+ throw new Error(`${code}: ${comment}`);
115
+ }
116
+ throw new Error(`${op}: unexpected response type ${doc.type ?? "(none)"} — ${JSON.stringify(doc)}`);
117
+ }
118
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/vault/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import type { SecretKind, SiteTarget, VaultEntry } from "./list.js";
2
+ import { type VtaAuthInputs } from "./transport.js";
3
+ /** Optional driver config on Password-kind entries — instructs the
4
+ * VTA to POST these credentials at a specific URL during
5
+ * `vault/proxy-login/0.1`. Mirrors
6
+ * `vault/_shared/0.1/vault-secret#/$defs/PasswordLoginConfig`. */
7
+ export interface PasswordLoginConfig {
8
+ loginUrl: string;
9
+ format?: "json" | "form-urlencoded";
10
+ usernameField?: string;
11
+ passwordField?: string;
12
+ totpField?: string;
13
+ extraFields?: Record<string, string>;
14
+ successStatus?: number[];
15
+ }
16
+ /** Cleartext shape of the inner DIDComm message body — matches the
17
+ * canonical `vault/_shared/0.1/vault-secret#/$defs/VaultSecret` tagged
18
+ * union. M2A ships Password / Passkey / OauthTokens / BearerToken /
19
+ * Custom; M2B.4 adds `did-self-issued`. `didcomm-peer` and `ssh-key`
20
+ * follow when the UI grows fields for them. */
21
+ export type VaultSecret = {
22
+ kind: "password";
23
+ username?: string;
24
+ password: string;
25
+ loginConfig?: PasswordLoginConfig;
26
+ secureNotes?: string;
27
+ } | {
28
+ kind: "passkey";
29
+ credentialId: string;
30
+ privateKey: string;
31
+ algorithm?: string;
32
+ rpId: string;
33
+ userHandle?: string;
34
+ secureNotes?: string;
35
+ } | {
36
+ kind: "oauth-tokens";
37
+ provider: string;
38
+ refreshToken: string;
39
+ accessToken?: string;
40
+ accessTokenExpiresAt?: string;
41
+ scopes?: string[];
42
+ secureNotes?: string;
43
+ } | {
44
+ kind: "did-self-issued";
45
+ /** The persona DID the entry acts AS (becomes the SIOP `iss`
46
+ * + `sub`). */
47
+ did: string;
48
+ /** Key the VTA uses to sign the id_token. References a key the
49
+ * VTA's keystore can resolve — typically `<did>#key-0`. */
50
+ signingKeyId: string;
51
+ secureNotes?: string;
52
+ } | {
53
+ kind: "bearer-token";
54
+ token: string;
55
+ headerName?: string;
56
+ headerPrefix?: string;
57
+ secureNotes?: string;
58
+ } | {
59
+ kind: "custom";
60
+ fields: Array<{
61
+ name: string;
62
+ value: string;
63
+ hidden?: boolean;
64
+ kind?: string;
65
+ }>;
66
+ secureNotes?: string;
67
+ };
68
+ export interface VaultUpsertRestOptions extends VtaAuthInputs {
69
+ /** Omit to create with a maintainer-assigned ULID; supply to update or
70
+ * upsert-with-id. */
71
+ id?: string;
72
+ /** REQUIRED on update — the consumer's last-observed `version`. */
73
+ expectedVersion?: number;
74
+ contextId: string;
75
+ targets: SiteTarget[];
76
+ label: string;
77
+ secretKind: SecretKind;
78
+ tags?: string[];
79
+ notes?: string;
80
+ favicon?: string;
81
+ selectors?: string[];
82
+ customFieldNames?: string[];
83
+ expiresAt?: string;
84
+ /** REQUIRED on create unless secretKind is `did-self-issued` or
85
+ * `didcomm-peer`. On update, supply to rotate the secret; omit to
86
+ * keep the existing secret untouched. */
87
+ secret?: VaultSecret;
88
+ /** Metadata fields to explicitly null out. */
89
+ clearFields?: Array<"notes" | "favicon" | "expiresAt" | "tags" | "selectors" | "customFieldNames">;
90
+ }
91
+ export interface VaultUpsertResponse {
92
+ entry: VaultEntry;
93
+ created: boolean;
94
+ }
95
+ /**
96
+ * Create or update a vault entry. The cleartext secret never crosses
97
+ * the wire in plain — it's authcrypt-packed to the VTA's keyAgreement
98
+ * key. The maintainer unseals server-side, validates the variant
99
+ * against `secretKind`, and persists.
100
+ */
101
+ export declare function vaultUpsertRest(opts: VaultUpsertRestOptions): Promise<VaultUpsertResponse>;
102
+ //# sourceMappingURL=upsert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../src/vault/upsert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ // Vault — upsert (M2A.5).
2
+ //
3
+ // Posts a `https://trusttasks.org/spec/vault/upsert/0.1` envelope to the
4
+ // VTA's trust-task dispatcher. The cleartext secret is wrapped in a
5
+ // DIDComm authcrypt envelope (the `didcomm-authcrypt` variant of the
6
+ // canonical SealedEnvelope schema), so the long-term credential rides
7
+ // the wire as ciphertext only — even the VTA's own logs see just the
8
+ // JWE.
9
+ //
10
+ // Flow:
11
+ // 1. Build the cleartext VaultSecret JSON.
12
+ // 2. Pack it as authcrypt: sender = holder's keyAgreement, recipient =
13
+ // VTA's keyAgreement (same primitive the auth handshake uses, just
14
+ // pointing the opposite direction with a different message body).
15
+ // 3. Bearer-auth via `getVtaBearer` (REST + DIDComm-authcrypt /auth/
16
+ // round-trip).
17
+ // 4. POST the upsert envelope with `sealedSecret: { envelope:
18
+ // "didcomm-authcrypt", jwe }`.
19
+ // 5. Return the maintainer's response (metadata view + `created` flag).
20
+ import { packAuthcrypt } from "../didcomm/index.js";
21
+ import { getVtaBearer, postTrustTask } from "./transport.js";
22
+ const TASK_VAULT_UPSERT = "https://trusttasks.org/spec/vault/upsert/0.1";
23
+ const TASK_VAULT_UPSERT_RESPONSE = "https://trusttasks.org/spec/vault/upsert/0.1#response";
24
+ const INNER_MSG_TYPE = "https://openvtc.org/vault/upsert/secret-envelope/1.0";
25
+ /**
26
+ * Create or update a vault entry. The cleartext secret never crosses
27
+ * the wire in plain — it's authcrypt-packed to the VTA's keyAgreement
28
+ * key. The maintainer unseals server-side, validates the variant
29
+ * against `secretKind`, and persists.
30
+ */
31
+ export async function vaultUpsertRest(opts) {
32
+ const bearer = await getVtaBearer({
33
+ baseUrl: opts.baseUrl,
34
+ holder: opts.holder,
35
+ service: opts.service,
36
+ ...(opts.fetch ? { fetch: opts.fetch } : {}),
37
+ });
38
+ // Build the sealedSecret envelope — only built when `secret` is
39
+ // supplied. Update paths that keep the existing secret pass no
40
+ // sealedSecret at all.
41
+ let sealedSecret;
42
+ if (opts.secret) {
43
+ const jwe = await packSecretAsAuthcrypt({
44
+ secret: opts.secret,
45
+ holder: opts.holder,
46
+ service: opts.service,
47
+ });
48
+ sealedSecret = { envelope: "didcomm-authcrypt", jwe };
49
+ }
50
+ const payload = {
51
+ ...(opts.id ? { id: opts.id } : {}),
52
+ ...(opts.expectedVersion !== undefined ? { expectedVersion: opts.expectedVersion } : {}),
53
+ contextId: opts.contextId,
54
+ targets: opts.targets,
55
+ label: opts.label,
56
+ secretKind: opts.secretKind,
57
+ ...(opts.tags ? { tags: opts.tags } : {}),
58
+ ...(opts.notes !== undefined ? { notes: opts.notes } : {}),
59
+ ...(opts.favicon ? { favicon: opts.favicon } : {}),
60
+ ...(opts.selectors ? { selectors: opts.selectors } : {}),
61
+ ...(opts.customFieldNames ? { customFieldNames: opts.customFieldNames } : {}),
62
+ ...(opts.expiresAt ? { expiresAt: opts.expiresAt } : {}),
63
+ ...(sealedSecret ? { sealedSecret } : {}),
64
+ ...(opts.clearFields ? { clearFields: opts.clearFields } : {}),
65
+ };
66
+ return postTrustTask({
67
+ baseUrl: opts.baseUrl,
68
+ bearer,
69
+ envelope: {
70
+ type: TASK_VAULT_UPSERT,
71
+ payload,
72
+ issuer: opts.holder.did,
73
+ recipient: opts.service.did,
74
+ },
75
+ expectedResponseType: TASK_VAULT_UPSERT_RESPONSE,
76
+ operationLabel: "vault/upsert/0.1",
77
+ ...(opts.fetch ? { fetch: opts.fetch } : {}),
78
+ });
79
+ }
80
+ async function packSecretAsAuthcrypt(opts) {
81
+ const innerMsg = {
82
+ id: globalThis.crypto.randomUUID(),
83
+ type: INNER_MSG_TYPE,
84
+ from: opts.holder.did,
85
+ to: [opts.service.did],
86
+ body: opts.secret,
87
+ };
88
+ return packAuthcrypt(innerMsg, opts.holder, [
89
+ { kid: opts.service.keyAgreementKid, jwk: opts.service.keyAgreementPublicJwk },
90
+ ]);
91
+ }
92
+ //# sourceMappingURL=upsert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsert.js","sourceRoot":"","sources":["../../src/vault/upsert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { MediatorConnection } from "../didcomm/index.js";
2
+ import type { DidcommMessageBridge, DidcommReply } from "./transport.js";
3
+ /**
4
+ * `DidcommMessageBridge` backed by the library's authenticated
5
+ * `MediatorSession` (via {@link connectMediatorSession}). The session
6
+ * owns the WebSocket, mediator auth, pickup live-delivery, inbound
7
+ * unpacking, and `thid` correlation — this class just adapts its
8
+ * `send` / `waitFor` to the bridge contract.
9
+ *
10
+ * Because the session only surfaces successfully sender-authenticated
11
+ * authcrypt frames (anoncrypt is dropped), every reply this bridge
12
+ * returns is already authenticated; callers validate `from` / `thid` /
13
+ * `type` on the decrypted message.
14
+ */
15
+ export declare class MediatorSessionBridge implements DidcommMessageBridge {
16
+ private readonly connection;
17
+ private readonly defaultTimeoutMs;
18
+ constructor(connection: MediatorConnection, timeoutMs?: number);
19
+ sendAndAwaitReply(outerPackedJwe: string, expectThreadId: string, options?: {
20
+ timeoutMs?: number;
21
+ }): Promise<DidcommReply>;
22
+ send(outerPackedJwe: string): Promise<void>;
23
+ /** Tear down the underlying session. */
24
+ close(): void;
25
+ }
26
+ //# sourceMappingURL=bridge-mediator-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-mediator-session.d.ts","sourceRoot":"","sources":["../../src/vta/bridge-mediator-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIzE;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,UAAU,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAE,MAAM;IAKxD,iBAAiB,CACrB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,YAAY,CAAC;IAYlB,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,wCAAwC;IACxC,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,37 @@
1
+ const DEFAULT_TIMEOUT_MS = 30_000;
2
+ /**
3
+ * `DidcommMessageBridge` backed by the library's authenticated
4
+ * `MediatorSession` (via {@link connectMediatorSession}). The session
5
+ * owns the WebSocket, mediator auth, pickup live-delivery, inbound
6
+ * unpacking, and `thid` correlation — this class just adapts its
7
+ * `send` / `waitFor` to the bridge contract.
8
+ *
9
+ * Because the session only surfaces successfully sender-authenticated
10
+ * authcrypt frames (anoncrypt is dropped), every reply this bridge
11
+ * returns is already authenticated; callers validate `from` / `thid` /
12
+ * `type` on the decrypted message.
13
+ */
14
+ export class MediatorSessionBridge {
15
+ connection;
16
+ defaultTimeoutMs;
17
+ constructor(connection, timeoutMs) {
18
+ this.connection = connection;
19
+ this.defaultTimeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
20
+ }
21
+ async sendAndAwaitReply(outerPackedJwe, expectThreadId, options) {
22
+ // Register the waiter before sending so a fast reply can't race
23
+ // ahead of the correlation (the session also buffers unclaimed
24
+ // frames, but registering first is unconditionally safe).
25
+ const reply = this.connection.waitFor(expectThreadId, options?.timeoutMs ?? this.defaultTimeoutMs);
26
+ this.connection.send(outerPackedJwe);
27
+ return (await reply);
28
+ }
29
+ async send(outerPackedJwe) {
30
+ this.connection.send(outerPackedJwe);
31
+ }
32
+ /** Tear down the underlying session. */
33
+ close() {
34
+ this.connection.close();
35
+ }
36
+ }
37
+ //# sourceMappingURL=bridge-mediator-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-mediator-session.js","sourceRoot":"","sources":["../../src/vta/bridge-mediator-session.ts"],"names":[],"mappings":"AAGA,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,qBAAqB;IACf,UAAU,CAAqB;IAC/B,gBAAgB,CAAS;IAE1C,YAAY,UAA8B,EAAE,SAAkB;QAC5D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,cAAsB,EACtB,cAAsB,EACtB,OAAgC;QAEhC,gEAAgE;QAChE,+DAA+D;QAC/D,0DAA0D;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CACnC,cAAc,EACd,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAC5C,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACrC,OAAO,CAAC,MAAM,KAAK,CAAiB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,cAAsB;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC;IAED,wCAAwC;IACxC,KAAK;QACH,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,80 @@
1
+ import { Identity, type PublicJwk } from "../didcomm/index.js";
2
+ import type { DidcommMessageBridge, DidcommReply } from "./transport.js";
3
+ /** Reply contract a fake-VTA or fake-mediator handler returns to the bridge.
4
+ * Returning `null` or `undefined` signals "no reply" — appropriate for
5
+ * DIDComm notifications like `pickup/3.0/live-delivery-change` and
6
+ * `pickup/3.0/messages-received`. */
7
+ export interface InMemoryHandlerReply {
8
+ type: string;
9
+ body: unknown;
10
+ }
11
+ export type InMemoryHandler = (request: {
12
+ type: string;
13
+ from?: string;
14
+ body: unknown;
15
+ id: string;
16
+ }) => Promise<InMemoryHandlerReply | null | undefined> | InMemoryHandlerReply | null | undefined;
17
+ export interface InMemoryDidcommBridgeOptions {
18
+ /** Fake VTA identity (unpacks inner authcrypt + signs replies). */
19
+ vta?: Identity;
20
+ /** Sender public JWK so VTA can authenticate inner authcrypt. */
21
+ holderPublicJwk: {
22
+ kid: string;
23
+ jwk: PublicJwk;
24
+ };
25
+ /**
26
+ * Fake mediator identity. When set, the bridge tries to unpack
27
+ * the outer message with the mediator first. If the result is a
28
+ * `routing/2.0/forward` envelope, the inner JWE is extracted from
29
+ * attachments and dispatched against `vtaHandlers`; otherwise the
30
+ * decrypted message is dispatched against `mediatorHandlers`.
31
+ *
32
+ * When omitted, the outer is treated as the inner authcrypt
33
+ * directly (VTA-only, mediator-less transport).
34
+ */
35
+ mediator?: Identity;
36
+ /** Handlers for messages that reached the (fake) VTA. */
37
+ vtaHandlers?: Record<string, InMemoryHandler>;
38
+ /** Handlers for direct-to-mediator messages (coordinate-mediation, pickup, …). */
39
+ mediatorHandlers?: Record<string, InMemoryHandler>;
40
+ }
41
+ /**
42
+ * Deterministic, single-process simulator covering two delivery
43
+ * patterns:
44
+ *
45
+ * 1. **Forward-wrapped to VTA** (passkey-management): outer anoncrypt
46
+ * to mediator → forward envelope → inner authcrypt holder→VTA.
47
+ * The bridge unwraps the forward, decrypts the inner as VTA,
48
+ * dispatches against `vtaHandlers`, and authcrypts the reply
49
+ * VTA→holder.
50
+ * 2. **Direct to mediator** (coordinate-mediation): outer authcrypt
51
+ * holder→mediator. The bridge decrypts as mediator, dispatches
52
+ * against `mediatorHandlers`, and authcrypts the reply
53
+ * mediator→holder.
54
+ *
55
+ * Pattern detection is runtime — try mediator-unpack first and
56
+ * inspect the decoded `type`. Falls back to direct VTA-unpack if no
57
+ * mediator is configured.
58
+ *
59
+ * Not for production. Drives the smokes in `./smoke.ts`.
60
+ */
61
+ export declare class InMemoryDidcommBridge implements DidcommMessageBridge {
62
+ private readonly vta?;
63
+ private readonly mediator?;
64
+ private readonly holderPublicJwk;
65
+ private readonly vtaHandlers;
66
+ private readonly mediatorHandlers;
67
+ constructor(opts: InMemoryDidcommBridgeOptions);
68
+ sendAndAwaitReply(outerPackedJwe: string, _expectThreadId: string, _options?: {
69
+ timeoutMs?: number;
70
+ }): Promise<DidcommReply>;
71
+ send(outerPackedJwe: string): Promise<void>;
72
+ /** Internal: route the outer envelope to the right pattern's
73
+ * handler and return its decrypted reply (or null for notifications). */
74
+ private process;
75
+ private handleForwarded;
76
+ private handleDirectVta;
77
+ private handleMediatorDirect;
78
+ private dispatch;
79
+ }
80
+ //# sourceMappingURL=bridge-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-memory.d.ts","sourceRoot":"","sources":["../../src/vta/bridge-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAER,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA2BzE;;;sCAGsC;AACtC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC;AAEjG,MAAM,WAAW,4BAA4B;IAC3C,mEAAmE;IACnE,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,iEAAiE;IACjE,eAAe,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,CAAA;KAAE,CAAC;IACjD;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACpD;AAeD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,qBAAsB,YAAW,oBAAoB;IAChE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAClE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkC;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;gBAEvD,IAAI,EAAE,4BAA4B;IAQxC,iBAAiB,CACrB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAChC,OAAO,CAAC,YAAY,CAAC;IAUlB,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD;8EAC0E;YAC5D,OAAO;YA+BP,eAAe;YAaf,eAAe;YAqBf,oBAAoB;YAOpB,QAAQ;CAgCvB"}
@@ -0,0 +1,162 @@
1
+ import { Identity, unpackMessage, } from "../didcomm/index.js";
2
+ /**
3
+ * Parse a JWE protected-header `skid` without decrypting. Authcrypt
4
+ * (ECDH-1PU) sets it; anoncrypt (ECDH-ES) doesn't — so its presence
5
+ * tells the in-memory bridge whether to expect a sender for unpack.
6
+ */
7
+ function readJweSenderKid(jwe) {
8
+ try {
9
+ const parsed = JSON.parse(jwe);
10
+ if (typeof parsed !== "object" || parsed === null)
11
+ return undefined;
12
+ const protectedB64 = parsed.protected;
13
+ if (typeof protectedB64 !== "string")
14
+ return undefined;
15
+ const headerJson = atob(protectedB64.replaceAll("-", "+").replaceAll("_", "/"));
16
+ const header = JSON.parse(headerJson);
17
+ if (typeof header !== "object" || header === null)
18
+ return undefined;
19
+ const skid = header.skid;
20
+ return typeof skid === "string" ? skid : undefined;
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ }
26
+ const FORWARD_TYPE = "https://didcomm.org/routing/2.0/forward";
27
+ /**
28
+ * Deterministic, single-process simulator covering two delivery
29
+ * patterns:
30
+ *
31
+ * 1. **Forward-wrapped to VTA** (passkey-management): outer anoncrypt
32
+ * to mediator → forward envelope → inner authcrypt holder→VTA.
33
+ * The bridge unwraps the forward, decrypts the inner as VTA,
34
+ * dispatches against `vtaHandlers`, and authcrypts the reply
35
+ * VTA→holder.
36
+ * 2. **Direct to mediator** (coordinate-mediation): outer authcrypt
37
+ * holder→mediator. The bridge decrypts as mediator, dispatches
38
+ * against `mediatorHandlers`, and authcrypts the reply
39
+ * mediator→holder.
40
+ *
41
+ * Pattern detection is runtime — try mediator-unpack first and
42
+ * inspect the decoded `type`. Falls back to direct VTA-unpack if no
43
+ * mediator is configured.
44
+ *
45
+ * Not for production. Drives the smokes in `./smoke.ts`.
46
+ */
47
+ export class InMemoryDidcommBridge {
48
+ vta;
49
+ mediator;
50
+ holderPublicJwk;
51
+ vtaHandlers;
52
+ mediatorHandlers;
53
+ constructor(opts) {
54
+ if (opts.vta !== undefined)
55
+ this.vta = opts.vta;
56
+ if (opts.mediator !== undefined)
57
+ this.mediator = opts.mediator;
58
+ this.holderPublicJwk = opts.holderPublicJwk;
59
+ this.vtaHandlers = opts.vtaHandlers ?? {};
60
+ this.mediatorHandlers = opts.mediatorHandlers ?? {};
61
+ }
62
+ async sendAndAwaitReply(outerPackedJwe, _expectThreadId, _options) {
63
+ const reply = await this.process(outerPackedJwe);
64
+ if (reply === null) {
65
+ throw new Error("bridge: handler returned no reply (notification) but caller awaited one");
66
+ }
67
+ return reply;
68
+ }
69
+ async send(outerPackedJwe) {
70
+ // Fire-and-forget. The in-memory bridge still routes through
71
+ // the same dispatch path so that handlers see notifications,
72
+ // but it discards any reply (which should be null for proper
73
+ // notification message types).
74
+ await this.process(outerPackedJwe);
75
+ }
76
+ /** Internal: route the outer envelope to the right pattern's
77
+ * handler and return its decrypted reply (or null for notifications). */
78
+ async process(outerPackedJwe) {
79
+ // ── Pattern 1 + 2: mediator configured → try mediator-unpack first
80
+ if (this.mediator) {
81
+ const outerIsAuthcrypt = readJweSenderKid(outerPackedJwe) !== undefined;
82
+ const outerView = await unpackMessage({
83
+ input: outerPackedJwe,
84
+ ...(outerIsAuthcrypt
85
+ ? { sender_public_jwk: this.holderPublicJwk.jwk }
86
+ : {}),
87
+ }, this.mediator);
88
+ if (outerView.kind !== "encrypted") {
89
+ throw new Error(`bridge: outer unpack returned ${outerView.kind}, expected encrypted`);
90
+ }
91
+ const outer = outerView.message;
92
+ if (outer.type === FORWARD_TYPE) {
93
+ return this.handleForwarded(outer);
94
+ }
95
+ return this.handleMediatorDirect(outer);
96
+ }
97
+ // ── Pattern 3: no mediator, outer IS the inner authcrypt to VTA
98
+ return this.handleDirectVta(outerPackedJwe);
99
+ }
100
+ async handleForwarded(outer) {
101
+ if (!this.vta) {
102
+ throw new Error("bridge: forward envelope received but no VTA identity configured");
103
+ }
104
+ const innerJson = outer.attachments?.[0]?.data?.json;
105
+ if (innerJson === undefined) {
106
+ throw new Error("bridge: forward envelope missing inner attachment");
107
+ }
108
+ const innerJwe = typeof innerJson === "string" ? innerJson : JSON.stringify(innerJson);
109
+ return this.handleDirectVta(innerJwe);
110
+ }
111
+ async handleDirectVta(innerJwe) {
112
+ if (!this.vta) {
113
+ throw new Error("bridge: direct-to-VTA path requires `vta` identity");
114
+ }
115
+ const inner = await unpackMessage({ input: innerJwe, sender_public_jwk: this.holderPublicJwk.jwk }, this.vta);
116
+ if (inner.kind !== "encrypted") {
117
+ throw new Error(`bridge: expected encrypted inner, got ${inner.kind}`);
118
+ }
119
+ if (!inner.authenticated) {
120
+ throw new Error("bridge: inner authcrypt failed sender authentication");
121
+ }
122
+ return this.dispatch(inner.message, this.vtaHandlers, this.vta);
123
+ }
124
+ async handleMediatorDirect(decrypted) {
125
+ if (!this.mediator) {
126
+ throw new Error("unreachable: mediator-direct without mediator");
127
+ }
128
+ return this.dispatch(decrypted, this.mediatorHandlers, this.mediator);
129
+ }
130
+ async dispatch(req, handlers, replier) {
131
+ if (!req.type)
132
+ throw new Error("bridge: message missing `type`");
133
+ if (!req.id)
134
+ throw new Error("bridge: message missing `id`");
135
+ if (!req.from) {
136
+ throw new Error("bridge: message missing `from` (cannot reply)");
137
+ }
138
+ const handler = handlers[req.type];
139
+ if (!handler) {
140
+ throw new Error(`bridge: no handler for ${req.type}`);
141
+ }
142
+ const reply = await handler({
143
+ type: req.type,
144
+ from: req.from,
145
+ body: req.body ?? {},
146
+ id: req.id,
147
+ });
148
+ if (reply == null)
149
+ return null;
150
+ // The real mediator-session bridge returns the *decrypted* reply, so
151
+ // this simulator returns the reply message directly rather than
152
+ // packing it (it holds only the holder's public key and couldn't
153
+ // unpack a self-packed reply anyway).
154
+ return {
155
+ type: reply.type,
156
+ from: replier.did,
157
+ thid: req.id,
158
+ body: reply.body,
159
+ };
160
+ }
161
+ }
162
+ //# sourceMappingURL=bridge-memory.js.map