@interop/wallet-core 0.4.1 → 0.6.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 (73) hide show
  1. package/dist/enrollment/enrollment.d.ts +144 -0
  2. package/dist/enrollment/enrollment.d.ts.map +1 -0
  3. package/dist/enrollment/enrollment.js +296 -0
  4. package/dist/enrollment/enrollment.js.map +1 -0
  5. package/dist/enrollment/index.d.ts +20 -0
  6. package/dist/enrollment/index.d.ts.map +1 -0
  7. package/dist/enrollment/index.js +19 -0
  8. package/dist/enrollment/index.js.map +1 -0
  9. package/dist/index.d.ts +13 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +13 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/keyring/fetch.d.ts +22 -0
  14. package/dist/keyring/fetch.d.ts.map +1 -0
  15. package/dist/keyring/fetch.js +35 -0
  16. package/dist/keyring/fetch.js.map +1 -0
  17. package/dist/keyring/index.d.ts +30 -0
  18. package/dist/keyring/index.d.ts.map +1 -0
  19. package/dist/keyring/index.js +28 -0
  20. package/dist/keyring/index.js.map +1 -0
  21. package/dist/keyring/kdf.d.ts +102 -0
  22. package/dist/keyring/kdf.d.ts.map +1 -0
  23. package/dist/keyring/kdf.js +148 -0
  24. package/dist/keyring/kdf.js.map +1 -0
  25. package/dist/keyring/record.d.ts +98 -0
  26. package/dist/keyring/record.d.ts.map +1 -0
  27. package/dist/keyring/record.js +119 -0
  28. package/dist/keyring/record.js.map +1 -0
  29. package/dist/keyring/unlockSpace.d.ts +101 -0
  30. package/dist/keyring/unlockSpace.d.ts.map +1 -0
  31. package/dist/keyring/unlockSpace.js +226 -0
  32. package/dist/keyring/unlockSpace.js.map +1 -0
  33. package/dist/keys/index.d.ts +24 -0
  34. package/dist/keys/index.d.ts.map +1 -0
  35. package/dist/keys/index.js +22 -0
  36. package/dist/keys/index.js.map +1 -0
  37. package/dist/keys/puk.d.ts +42 -0
  38. package/dist/keys/puk.d.ts.map +1 -0
  39. package/dist/keys/puk.js +56 -0
  40. package/dist/keys/puk.js.map +1 -0
  41. package/dist/keys/pukRoster.d.ts +210 -0
  42. package/dist/keys/pukRoster.d.ts.map +1 -0
  43. package/dist/keys/pukRoster.js +263 -0
  44. package/dist/keys/pukRoster.js.map +1 -0
  45. package/dist/keys/rosterStore.d.ts +18 -0
  46. package/dist/keys/rosterStore.d.ts.map +1 -0
  47. package/dist/keys/rosterStore.js +38 -0
  48. package/dist/keys/rosterStore.js.map +1 -0
  49. package/dist/space/collections.d.ts +57 -0
  50. package/dist/space/collections.d.ts.map +1 -1
  51. package/dist/space/collections.js +48 -0
  52. package/dist/space/collections.js.map +1 -1
  53. package/dist/space/index.d.ts +4 -0
  54. package/dist/space/index.d.ts.map +1 -1
  55. package/dist/space/index.js +4 -0
  56. package/dist/space/index.js.map +1 -1
  57. package/dist/webvh/didWeb.d.ts +41 -0
  58. package/dist/webvh/didWeb.d.ts.map +1 -0
  59. package/dist/webvh/didWeb.js +24 -0
  60. package/dist/webvh/didWeb.js.map +1 -0
  61. package/dist/webvh/didWebvh.d.ts +251 -0
  62. package/dist/webvh/didWebvh.d.ts.map +1 -0
  63. package/dist/webvh/didWebvh.js +775 -0
  64. package/dist/webvh/didWebvh.js.map +1 -0
  65. package/dist/webvh/index.d.ts +27 -0
  66. package/dist/webvh/index.d.ts.map +1 -0
  67. package/dist/webvh/index.js +24 -0
  68. package/dist/webvh/index.js.map +1 -0
  69. package/dist/webvh/zcap.d.ts +104 -0
  70. package/dist/webvh/zcap.d.ts.map +1 -0
  71. package/dist/webvh/zcap.js +117 -0
  72. package/dist/webvh/zcap.js.map +1 -0
  73. package/package.json +30 -4
@@ -0,0 +1,30 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `@interop/wallet-core/keyring` subpath: the unlock layer -- how an
6
+ * unlock secret (a passphrase, a passkey PRF output) locates an account
7
+ * without authorizing anything against it.
8
+ *
9
+ * - `deriveUnlockIdentity` / `KEYRING_KDF` / `unlockSpaceIdFor` -- the
10
+ * wire-level unlock derivation (implemented over `@noble/hashes`, so it runs
11
+ * unchanged where WebCrypto's `deriveBits` is unavailable) and the unlock
12
+ * Space addressing convention.
13
+ * - `wrapKeyringRecord` / `unwrapKeyringRecord` -- the `{ version, wrapped }`
14
+ * account-pointer record codec.
15
+ * - `ensureUnlockSpace` / `getUnlockKeyring` / `putUnlockKeyring` /
16
+ * `deleteUnlockSpace` / `deleteUnlockSpaceWithCapability` -- the unlock
17
+ * Space's lifecycle and its one resource.
18
+ * - `fetchKeyringRecord` -- the composed lookup (derive, read, unwrap); an
19
+ * app's caching, pinning, and client-key persistence wrap around it.
20
+ *
21
+ * Kept out of the root export: this subpath pulls the webkms-client / ezcap /
22
+ * was-client dependency graph (the same isolation pattern as `./identity`).
23
+ */
24
+ export { deriveUnlockIdentity, KEYRING_KDF, UNLOCK_HANDLE, UNLOCK_KEY_NAME, unlockSpaceIdFor } from './kdf.js';
25
+ export type { UnlockIdentity, UnlockKdf } from './kdf.js';
26
+ export { KEYRING_RECORD_VERSION, parseRecordPointer, unwrapKeyringRecord, wrapKeyringRecord } from './record.js';
27
+ export type { AccountPointer, KeyringRecordContents } from './record.js';
28
+ export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, UNLOCK_SPACE_NAME } from './unlockSpace.js';
29
+ export { fetchKeyringRecord } from './fetch.js';
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,28 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The `@interop/wallet-core/keyring` subpath: the unlock layer -- how an
6
+ * unlock secret (a passphrase, a passkey PRF output) locates an account
7
+ * without authorizing anything against it.
8
+ *
9
+ * - `deriveUnlockIdentity` / `KEYRING_KDF` / `unlockSpaceIdFor` -- the
10
+ * wire-level unlock derivation (implemented over `@noble/hashes`, so it runs
11
+ * unchanged where WebCrypto's `deriveBits` is unavailable) and the unlock
12
+ * Space addressing convention.
13
+ * - `wrapKeyringRecord` / `unwrapKeyringRecord` -- the `{ version, wrapped }`
14
+ * account-pointer record codec.
15
+ * - `ensureUnlockSpace` / `getUnlockKeyring` / `putUnlockKeyring` /
16
+ * `deleteUnlockSpace` / `deleteUnlockSpaceWithCapability` -- the unlock
17
+ * Space's lifecycle and its one resource.
18
+ * - `fetchKeyringRecord` -- the composed lookup (derive, read, unwrap); an
19
+ * app's caching, pinning, and client-key persistence wrap around it.
20
+ *
21
+ * Kept out of the root export: this subpath pulls the webkms-client / ezcap /
22
+ * was-client dependency graph (the same isolation pattern as `./identity`).
23
+ */
24
+ export { deriveUnlockIdentity, KEYRING_KDF, UNLOCK_HANDLE, UNLOCK_KEY_NAME, unlockSpaceIdFor } from './kdf.js';
25
+ export { KEYRING_RECORD_VERSION, parseRecordPointer, unwrapKeyringRecord, wrapKeyringRecord } from './record.js';
26
+ export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, UNLOCK_SPACE_NAME } from './unlockSpace.js';
27
+ export { fetchKeyringRecord } from './fetch.js';
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAGjB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,102 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The unlock derivation: an unlock secret (a passphrase, or a passkey PRF
6
+ * output) to the unlock identity that locates an account's keyring record and
7
+ * wraps/unwraps it. Nothing about the account is derivable from the secret --
8
+ * the identity's only jobs are addressing the minimal unlock Space and holding
9
+ * the key-agreement key the keyring record is encrypted to.
10
+ *
11
+ * The derivation is wire-level: two wallet apps must produce byte-identical
12
+ * output for the same secret and parameter set, or the same passphrase would
13
+ * address two different unlock Spaces. It is therefore implemented over
14
+ * `@noble/hashes` rather than WebCrypto's `crypto.subtle.deriveBits`, which
15
+ * React Native does not provide; PBKDF2 and HKDF are both fully specified
16
+ * (RFC 8018 / RFC 5869), so the two implementations agree bit for bit.
17
+ */
18
+ import { CapabilityAgent } from '@interop/webkms-client';
19
+ import { ZcapClient } from '@interop/ezcap';
20
+ import { X25519KeyAgreementKey2020 } from '@interop/x25519-key-agreement-key';
21
+ import type { IKeyResolver } from '@interop/data-integrity-core';
22
+ /**
23
+ * The load-bearing `CapabilityAgent` derivation names for an unlock identity
24
+ * (the counterpart of the data identity's bootstrap names): every unlock
25
+ * derivation runs through these exact strings, so they can never change
26
+ * without stranding existing accounts.
27
+ */
28
+ export declare const UNLOCK_HANDLE = "unlock";
29
+ export declare const UNLOCK_KEY_NAME = "unlock-key";
30
+ /**
31
+ * Unlock-derivation parameters, one variant per KDF family: PBKDF2 stretches
32
+ * a low-entropy passphrase; HKDF expands already-uniform key material (e.g. a
33
+ * passkey PRF output). Each unlock method pins its own parameter set -- and
34
+ * its own salt, so two methods can never derive the same unlock identity.
35
+ * The `version` records which parameter set produced a derivation; the
36
+ * keyring record's own `version` is stamped separately.
37
+ */
38
+ export type UnlockKdf = {
39
+ version: number;
40
+ algorithm: 'PBKDF2';
41
+ iterations: number;
42
+ hash: string;
43
+ salt: string;
44
+ } | {
45
+ version: number;
46
+ algorithm: 'HKDF';
47
+ hash: string;
48
+ salt: string;
49
+ info: string;
50
+ };
51
+ /**
52
+ * PBKDF2 parameters for the passphrase unlock derivation
53
+ * (`unlockSeed = PBKDF2(passphrase)`). Version 1 pins exactly these
54
+ * parameters; the keyring record's `version` field records which set produced
55
+ * it, so changing any of them (iterations, hash, salt) requires minting a new
56
+ * record version rather than silently breaking existing unlock derivations.
57
+ * The salt is a fixed app-wide constant -- login stays passphrase-only, with
58
+ * no email (or other) input mixed into the derivation. Every unlock method's
59
+ * KDF carries a distinct salt, so two methods can never derive the same
60
+ * unlock Space.
61
+ */
62
+ export declare const KEYRING_KDF: UnlockKdf;
63
+ /**
64
+ * Derives the full unlock identity from an unlock secret: the unlock
65
+ * CapabilityAgent, a ZcapClient that can both invoke and delegate (the
66
+ * unlock agent delegates a management zcap on its own Space to the account
67
+ * controller at bind time), the unlock KAK + resolver for wrap/unwrap, and the
68
+ * unlock Space id. Performs no I/O -- the derivation seam for tests and future
69
+ * unlock methods.
70
+ *
71
+ * @param options {object}
72
+ * @param options.secret {string | Uint8Array}
73
+ * @param options.kdf {UnlockKdf}
74
+ * @returns {Promise<object>}
75
+ */
76
+ export declare function deriveUnlockIdentity({ secret, kdf }: {
77
+ secret: string | Uint8Array;
78
+ kdf: UnlockKdf;
79
+ }): Promise<{
80
+ agent: CapabilityAgent;
81
+ zcapClient: ZcapClient;
82
+ keyAgreementKey: X25519KeyAgreementKey2020;
83
+ keyResolver: IKeyResolver;
84
+ spaceId: string;
85
+ }>;
86
+ /**
87
+ * The unlock Space id an unlock identity addresses:
88
+ * `base64url(SHA-256(did))`, unpadded -- a discovery convention, not an
89
+ * authorization one (holding the id grants nothing).
90
+ *
91
+ * @param options {object}
92
+ * @param options.did {string} the unlock identity's did:key
93
+ * @returns {string}
94
+ */
95
+ export declare function unlockSpaceIdFor({ did }: {
96
+ did: string;
97
+ }): string;
98
+ /**
99
+ * The derived unlock identity, as `deriveUnlockIdentity` returns it.
100
+ */
101
+ export type UnlockIdentity = Awaited<ReturnType<typeof deriveUnlockIdentity>>;
102
+ //# sourceMappingURL=kdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.d.ts","sourceRoot":"","sources":["../../src/keyring/kdf.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAOhE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAW,CAAA;AACrC,eAAO,MAAM,eAAe,eAAe,CAAA;AAQ3C;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GACjB;IACE,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,QAAQ,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAEL;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,EAAE,SAMzB,CAAA;AA2DD;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,MAAM,EACN,GAAG,EACJ,EAAE;IACD,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;IAC3B,GAAG,EAAE,SAAS,CAAA;CACf;;;;;;GAyBA;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,148 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The unlock derivation: an unlock secret (a passphrase, or a passkey PRF
6
+ * output) to the unlock identity that locates an account's keyring record and
7
+ * wraps/unwraps it. Nothing about the account is derivable from the secret --
8
+ * the identity's only jobs are addressing the minimal unlock Space and holding
9
+ * the key-agreement key the keyring record is encrypted to.
10
+ *
11
+ * The derivation is wire-level: two wallet apps must produce byte-identical
12
+ * output for the same secret and parameter set, or the same passphrase would
13
+ * address two different unlock Spaces. It is therefore implemented over
14
+ * `@noble/hashes` rather than WebCrypto's `crypto.subtle.deriveBits`, which
15
+ * React Native does not provide; PBKDF2 and HKDF are both fully specified
16
+ * (RFC 8018 / RFC 5869), so the two implementations agree bit for bit.
17
+ */
18
+ import { CapabilityAgent } from '@interop/webkms-client';
19
+ import { Ed25519Signature2020 } from '@interop/ed25519-signature';
20
+ import { ZcapClient } from '@interop/ezcap';
21
+ import { X25519KeyAgreementKey2020 } from '@interop/x25519-key-agreement-key';
22
+ import { base64urlnopad } from '@scure/base';
23
+ import { hkdf } from '@noble/hashes/hkdf.js';
24
+ import { pbkdf2Async } from '@noble/hashes/pbkdf2.js';
25
+ import { sha256, sha512 } from '@noble/hashes/sha2.js';
26
+ import { singleKeyResolver } from '../identity/keyResolver.js';
27
+ /**
28
+ * The load-bearing `CapabilityAgent` derivation names for an unlock identity
29
+ * (the counterpart of the data identity's bootstrap names): every unlock
30
+ * derivation runs through these exact strings, so they can never change
31
+ * without stranding existing accounts.
32
+ */
33
+ export const UNLOCK_HANDLE = 'unlock';
34
+ export const UNLOCK_KEY_NAME = 'unlock-key';
35
+ /**
36
+ * The number of bytes an unlock derivation produces (a 32-byte seed, which is
37
+ * what `CapabilityAgent.fromSeed` takes).
38
+ */
39
+ const UNLOCK_SEED_BYTES = 32;
40
+ /**
41
+ * PBKDF2 parameters for the passphrase unlock derivation
42
+ * (`unlockSeed = PBKDF2(passphrase)`). Version 1 pins exactly these
43
+ * parameters; the keyring record's `version` field records which set produced
44
+ * it, so changing any of them (iterations, hash, salt) requires minting a new
45
+ * record version rather than silently breaking existing unlock derivations.
46
+ * The salt is a fixed app-wide constant -- login stays passphrase-only, with
47
+ * no email (or other) input mixed into the derivation. Every unlock method's
48
+ * KDF carries a distinct salt, so two methods can never derive the same
49
+ * unlock Space.
50
+ */
51
+ export const KEYRING_KDF = {
52
+ version: 1,
53
+ algorithm: 'PBKDF2',
54
+ iterations: 600_000,
55
+ hash: 'SHA-256',
56
+ salt: 'freewallet/keyring/unlock/v1'
57
+ };
58
+ /**
59
+ * The noble hash constructor a WebCrypto hash name selects, so the derivation
60
+ * matches `crypto.subtle.deriveBits` for the same parameters.
61
+ *
62
+ * @param hash {string} a WebCrypto digest name (`SHA-256`, `SHA-512`)
63
+ * @returns {object} the noble hash
64
+ */
65
+ function nobleHash(hash) {
66
+ if (hash === 'SHA-256') {
67
+ return sha256;
68
+ }
69
+ if (hash === 'SHA-512') {
70
+ return sha512;
71
+ }
72
+ throw new Error(`Unsupported unlock KDF hash "${hash}".`);
73
+ }
74
+ /**
75
+ * Derives the 32-byte unlock seed from an unlock secret, branching on the KDF
76
+ * family: PBKDF2 stretches a passphrase, HKDF expands already-uniform key
77
+ * material such as a passkey PRF output.
78
+ *
79
+ * @param options {object}
80
+ * @param options.secret {string | Uint8Array}
81
+ * @param options.kdf {UnlockKdf}
82
+ * @returns {Promise<Uint8Array>}
83
+ */
84
+ async function deriveUnlockSeed({ secret, kdf }) {
85
+ // Copy a bytes secret into a fresh buffer: a caller's slice may be a view
86
+ // into a larger buffer, and the codecs below read the whole view.
87
+ const secretBytes = typeof secret === 'string'
88
+ ? new TextEncoder().encode(secret)
89
+ : new Uint8Array(secret);
90
+ const hash = nobleHash(kdf.hash);
91
+ const salt = new TextEncoder().encode(kdf.salt);
92
+ if (kdf.algorithm === 'PBKDF2') {
93
+ return pbkdf2Async(hash, secretBytes, salt, {
94
+ c: kdf.iterations,
95
+ dkLen: UNLOCK_SEED_BYTES
96
+ });
97
+ }
98
+ return hkdf(hash, secretBytes, salt, new TextEncoder().encode(kdf.info), UNLOCK_SEED_BYTES);
99
+ }
100
+ /**
101
+ * Derives the full unlock identity from an unlock secret: the unlock
102
+ * CapabilityAgent, a ZcapClient that can both invoke and delegate (the
103
+ * unlock agent delegates a management zcap on its own Space to the account
104
+ * controller at bind time), the unlock KAK + resolver for wrap/unwrap, and the
105
+ * unlock Space id. Performs no I/O -- the derivation seam for tests and future
106
+ * unlock methods.
107
+ *
108
+ * @param options {object}
109
+ * @param options.secret {string | Uint8Array}
110
+ * @param options.kdf {UnlockKdf}
111
+ * @returns {Promise<object>}
112
+ */
113
+ export async function deriveUnlockIdentity({ secret, kdf }) {
114
+ const seed = await deriveUnlockSeed({ secret, kdf });
115
+ const agent = await CapabilityAgent.fromSeed({
116
+ seed,
117
+ handle: UNLOCK_HANDLE,
118
+ keyName: UNLOCK_KEY_NAME
119
+ });
120
+ const signer = agent.getSigner();
121
+ const zcapClient = new ZcapClient({
122
+ SuiteClass: Ed25519Signature2020,
123
+ invocationSigner: signer,
124
+ delegationSigner: signer
125
+ });
126
+ // The unlock KAK is the Montgomery form of the unlock signing key -- the same
127
+ // derivation the client side uses (`agentsFromSeed`), so a returning user
128
+ // reconstitutes the exact key that wrapped the keyring record.
129
+ const keyAgreementKey = X25519KeyAgreementKey2020.fromEd25519VerificationKey2020({
130
+ keyPair: agent.getVerificationKeyPair()
131
+ });
132
+ const keyResolver = singleKeyResolver({ keyAgreementKey });
133
+ const spaceId = unlockSpaceIdFor({ did: agent.id });
134
+ return { agent, zcapClient, keyAgreementKey, keyResolver, spaceId };
135
+ }
136
+ /**
137
+ * The unlock Space id an unlock identity addresses:
138
+ * `base64url(SHA-256(did))`, unpadded -- a discovery convention, not an
139
+ * authorization one (holding the id grants nothing).
140
+ *
141
+ * @param options {object}
142
+ * @param options.did {string} the unlock identity's did:key
143
+ * @returns {string}
144
+ */
145
+ export function unlockSpaceIdFor({ did }) {
146
+ return base64urlnopad.encode(sha256(new TextEncoder().encode(did)));
147
+ }
148
+ //# sourceMappingURL=kdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.js","sourceRoot":"","sources":["../../src/keyring/kdf.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAE7E,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAA;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAA;AAE3C;;;GAGG;AACH,MAAM,iBAAiB,GAAG,EAAE,CAAA;AA0B5B;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,WAAW,GAAc;IACpC,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,OAAO;IACnB,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,8BAA8B;CACrC,CAAA;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,IAAI,CAAC,CAAA;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,gBAAgB,CAAC,EAC9B,MAAM,EACN,GAAG,EAIJ;IACC,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,WAAW,GACf,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QAClC,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC/C,IAAI,GAAG,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE;YAC1C,CAAC,EAAE,GAAG,CAAC,UAAU;YACjB,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,IAAI,CACT,IAAI,EACJ,WAAW,EACX,IAAI,EACJ,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAClC,iBAAiB,CAClB,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EACzC,MAAM,EACN,GAAG,EAIJ;IACC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC;QAC3C,IAAI;QACJ,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,eAAe;KACzB,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;IAChC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC;QAChC,UAAU,EAAE,oBAAoB;QAChC,gBAAgB,EAAE,MAAM;QACxB,gBAAgB,EAAE,MAAM;KACzB,CAAC,CAAA;IAEF,8EAA8E;IAC9E,0EAA0E;IAC1E,+DAA+D;IAC/D,MAAM,eAAe,GACnB,yBAAyB,CAAC,8BAA8B,CAAC;QACvD,OAAO,EAAE,KAAK,CAAC,sBAAsB,EAAE;KACxC,CAAC,CAAA;IACJ,MAAM,WAAW,GAAiB,iBAAiB,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IAExE,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;IACnD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,CAAA;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAE,GAAG,EAAmB;IACvD,OAAO,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AACrE,CAAC"}
@@ -0,0 +1,98 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The keyring record codec: the `{ version, wrapped }` envelope stored as the
6
+ * one resource of an account's unlock Space. Its plaintext carries the account
7
+ * controller, the email captured at bind time, and the account pointer -- and
8
+ * deliberately no key material of any kind, so the record locates an account
9
+ * without authorizing anything against it.
10
+ *
11
+ * The wrap is an EDV document envelope under the unlock key-agreement key,
12
+ * bound to the `keyring` cipher context, so a keyring envelope can never be
13
+ * mistaken for (or swapped with) any other wrapped record.
14
+ */
15
+ import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
16
+ /**
17
+ * The version stamped on the stored `{ version, wrapped }` keyring envelope.
18
+ * Version 2 is the account-pointer record; version-1 records (which carried a
19
+ * wrapped account-wide data seed) are refused as unusable -- such accounts are
20
+ * re-provisioned, not migrated.
21
+ */
22
+ export declare const KEYRING_RECORD_VERSION = 2;
23
+ /**
24
+ * The account pointer a keyring record carries in place of the retired data
25
+ * seed: where the account lives (`spaceId` + `host`, the WAS server origin)
26
+ * and, once provisioning has published it, the account's stable did:webvh id.
27
+ * Discovery only -- holding the pointer authorizes nothing.
28
+ */
29
+ export interface AccountPointer {
30
+ did?: string;
31
+ spaceId: string;
32
+ host: string;
33
+ }
34
+ /**
35
+ * The unwrapped contents of a keyring record: the account controller (the
36
+ * first enrolled client's did:key today), the account email captured at bind
37
+ * time (when one was given -- carried so any unlock method recovers it; a
38
+ * passkey login has no login form to ask on), and the account pointer (absent
39
+ * only on no-WAS deployments, where there is no Space to point at).
40
+ */
41
+ export interface KeyringRecordContents {
42
+ controller: string;
43
+ email?: string;
44
+ pointer?: AccountPointer;
45
+ }
46
+ /**
47
+ * Wraps the account-pointer contents into a keyring record: the controller,
48
+ * email, and pointer (+ timestamp) encrypted under the unlock KAK via the EDV
49
+ * cipher. Deliberately carries no key material of any kind.
50
+ *
51
+ * @param options {object}
52
+ * @param options.controller {string} the account did:key
53
+ * @param [options.email] {string} the account email, when known
54
+ * @param [options.pointer] {AccountPointer} the account pointer (absent on
55
+ * no-WAS deployments)
56
+ * @param options.keyAgreementKey {IKeyAgreementKey} the unlock KAK
57
+ * @param options.keyResolver {IKeyResolver}
58
+ * @returns {Promise<{ version: number, wrapped: unknown }>}
59
+ */
60
+ export declare function wrapKeyringRecord({ controller, email, pointer, keyAgreementKey, keyResolver }: {
61
+ controller: string;
62
+ email?: string;
63
+ pointer?: AccountPointer;
64
+ keyAgreementKey: IKeyAgreementKey;
65
+ keyResolver: IKeyResolver;
66
+ }): Promise<{
67
+ version: number;
68
+ wrapped: unknown;
69
+ }>;
70
+ /**
71
+ * Unwraps and validates a keyring record. Rejects a record whose `version` is
72
+ * not the current one (version-1 records carried the retired wrapped data
73
+ * seed and are refused -- accounts are re-provisioned, not migrated), and
74
+ * sanity-checks the decrypted plaintext (non-empty controller, well-formed
75
+ * pointer when present).
76
+ *
77
+ * @param options {object}
78
+ * @param options.record {unknown}
79
+ * @param options.keyAgreementKey {IKeyAgreementKey} the unlock KAK
80
+ * @param options.keyResolver {IKeyResolver}
81
+ * @returns {Promise<KeyringRecordContents>}
82
+ */
83
+ export declare function unwrapKeyringRecord({ record, keyAgreementKey, keyResolver }: {
84
+ record: unknown;
85
+ keyAgreementKey: IKeyAgreementKey;
86
+ keyResolver: IKeyResolver;
87
+ }): Promise<KeyringRecordContents>;
88
+ /**
89
+ * Parses and validates the optional `pointer` member of a keyring record
90
+ * plaintext. An absent member is a no-WAS record (returns undefined); a
91
+ * present-but-malformed one throws -- a record that claims a pointer but
92
+ * cannot state where the account lives is unusable.
93
+ *
94
+ * @param value {unknown} the record's `pointer` member
95
+ * @returns {AccountPointer | undefined}
96
+ */
97
+ export declare function parseRecordPointer(value: unknown): AccountPointer | undefined;
98
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/keyring/record.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AAIrC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,UAAU,EACV,KAAK,EACL,OAAO,EACP,eAAe,EACf,WAAW,EACZ,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;CAC1B,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAuBjD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,MAAM,EACN,eAAe,EACf,WAAW,EACZ,EAAE;IACD,MAAM,EAAE,OAAO,CAAA;IACf,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;CAC1B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAsCjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAsB7E"}
@@ -0,0 +1,119 @@
1
+ import { createEdvDocCipher } from '@interop/was-client/edv';
2
+ import { KEYRING_COLLECTION } from '../space/collections.js';
3
+ /**
4
+ * The version stamped on the stored `{ version, wrapped }` keyring envelope.
5
+ * Version 2 is the account-pointer record; version-1 records (which carried a
6
+ * wrapped account-wide data seed) are refused as unusable -- such accounts are
7
+ * re-provisioned, not migrated.
8
+ */
9
+ export const KEYRING_RECORD_VERSION = 2;
10
+ /**
11
+ * Wraps the account-pointer contents into a keyring record: the controller,
12
+ * email, and pointer (+ timestamp) encrypted under the unlock KAK via the EDV
13
+ * cipher. Deliberately carries no key material of any kind.
14
+ *
15
+ * @param options {object}
16
+ * @param options.controller {string} the account did:key
17
+ * @param [options.email] {string} the account email, when known
18
+ * @param [options.pointer] {AccountPointer} the account pointer (absent on
19
+ * no-WAS deployments)
20
+ * @param options.keyAgreementKey {IKeyAgreementKey} the unlock KAK
21
+ * @param options.keyResolver {IKeyResolver}
22
+ * @returns {Promise<{ version: number, wrapped: unknown }>}
23
+ */
24
+ export async function wrapKeyringRecord({ controller, email, pointer, keyAgreementKey, keyResolver }) {
25
+ const cipher = await createEdvDocCipher({
26
+ keyAgreementKey,
27
+ keyResolver,
28
+ collectionId: KEYRING_COLLECTION.id
29
+ });
30
+ const { envelope } = await cipher.encrypt({
31
+ data: {
32
+ controller,
33
+ ...(email ? { email } : {}),
34
+ ...(pointer
35
+ ? {
36
+ pointer: {
37
+ ...(pointer.did ? { did: pointer.did } : {}),
38
+ spaceId: pointer.spaceId,
39
+ host: pointer.host
40
+ }
41
+ }
42
+ : {}),
43
+ createdAt: new Date().toISOString()
44
+ }
45
+ });
46
+ return { version: KEYRING_RECORD_VERSION, wrapped: envelope };
47
+ }
48
+ /**
49
+ * Unwraps and validates a keyring record. Rejects a record whose `version` is
50
+ * not the current one (version-1 records carried the retired wrapped data
51
+ * seed and are refused -- accounts are re-provisioned, not migrated), and
52
+ * sanity-checks the decrypted plaintext (non-empty controller, well-formed
53
+ * pointer when present).
54
+ *
55
+ * @param options {object}
56
+ * @param options.record {unknown}
57
+ * @param options.keyAgreementKey {IKeyAgreementKey} the unlock KAK
58
+ * @param options.keyResolver {IKeyResolver}
59
+ * @returns {Promise<KeyringRecordContents>}
60
+ */
61
+ export async function unwrapKeyringRecord({ record, keyAgreementKey, keyResolver }) {
62
+ if (record === null || typeof record !== 'object') {
63
+ throw new Error('Malformed keyring record.');
64
+ }
65
+ const { version, wrapped } = record;
66
+ if (version !== KEYRING_RECORD_VERSION) {
67
+ throw new Error(`Unsupported keyring record version "${String(version)}".`);
68
+ }
69
+ const cipher = await createEdvDocCipher({
70
+ keyAgreementKey,
71
+ keyResolver,
72
+ collectionId: KEYRING_COLLECTION.id
73
+ });
74
+ const plaintext = (await cipher.decrypt({
75
+ envelope: wrapped
76
+ }));
77
+ if (typeof plaintext.controller !== 'string' || !plaintext.controller) {
78
+ throw new Error('Keyring record is missing a controller.');
79
+ }
80
+ const pointer = parseRecordPointer(plaintext.pointer);
81
+ return {
82
+ controller: plaintext.controller,
83
+ // A record bound without an email simply has no email; anything
84
+ // non-string is ignored, not fatal.
85
+ ...(typeof plaintext.email === 'string' && plaintext.email
86
+ ? { email: plaintext.email }
87
+ : {}),
88
+ ...(pointer ? { pointer } : {})
89
+ };
90
+ }
91
+ /**
92
+ * Parses and validates the optional `pointer` member of a keyring record
93
+ * plaintext. An absent member is a no-WAS record (returns undefined); a
94
+ * present-but-malformed one throws -- a record that claims a pointer but
95
+ * cannot state where the account lives is unusable.
96
+ *
97
+ * @param value {unknown} the record's `pointer` member
98
+ * @returns {AccountPointer | undefined}
99
+ */
100
+ export function parseRecordPointer(value) {
101
+ if (value === undefined) {
102
+ return undefined;
103
+ }
104
+ if (value === null || typeof value !== 'object') {
105
+ throw new Error('Keyring record has a malformed account pointer.');
106
+ }
107
+ const { did, spaceId, host } = value;
108
+ if (typeof spaceId !== 'string' || !spaceId) {
109
+ throw new Error('Keyring record account pointer is missing its spaceId.');
110
+ }
111
+ if (typeof host !== 'string' || !host) {
112
+ throw new Error('Keyring record account pointer is missing its host.');
113
+ }
114
+ if (did !== undefined && (typeof did !== 'string' || !did)) {
115
+ throw new Error('Keyring record account pointer has a malformed did.');
116
+ }
117
+ return { ...(did ? { did } : {}), spaceId, host };
118
+ }
119
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/keyring/record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import type { IZcap } from '@interop/data-integrity-core';
2
+ import type { ZcapClient } from '@interop/ezcap';
3
+ /**
4
+ * The default Space Description name an unlock Space is configured with.
5
+ * Wire-visible (it is the Space's stored name), so it stays stable across
6
+ * apps unless a caller deliberately overrides it.
7
+ */
8
+ export declare const UNLOCK_SPACE_NAME = "Freewallet Keyring";
9
+ /**
10
+ * Ensures the unlock Space and its single `keyring` collection exist
11
+ * (upsert -- idempotent). Runs with the unlock root capability, so `force`
12
+ * lets the collection upsert treat a 404 from the pre-merge describe as
13
+ * genuinely absent rather than unreadable.
14
+ *
15
+ * @param options {object}
16
+ * @param options.storageServerUrl {string}
17
+ * @param options.zcapClient {ZcapClient}
18
+ * @param options.spaceId {string} the unlock Space id
19
+ * @param options.controller {string} the unlock did:key
20
+ * @param [options.name] {string} the Space Description name
21
+ * @returns {Promise<void>}
22
+ */
23
+ export declare function ensureUnlockSpace({ storageServerUrl, zcapClient, spaceId, controller, name }: {
24
+ storageServerUrl: string;
25
+ zcapClient: ZcapClient;
26
+ spaceId: string;
27
+ controller: string;
28
+ name?: string;
29
+ }): Promise<void>;
30
+ /**
31
+ * Reads the keyring record from the unlock Space, or returns `null` when it
32
+ * does not exist yet. A network / unreachable error propagates, so callers can
33
+ * distinguish "no keyring" from "could not check".
34
+ *
35
+ * @param options {object}
36
+ * @param options.storageServerUrl {string}
37
+ * @param options.zcapClient {ZcapClient}
38
+ * @param options.spaceId {string} the unlock Space id
39
+ * @returns {Promise<unknown | null>}
40
+ */
41
+ export declare function getUnlockKeyring({ storageServerUrl, zcapClient, spaceId }: {
42
+ storageServerUrl: string;
43
+ zcapClient: ZcapClient;
44
+ spaceId: string;
45
+ }): Promise<unknown | null>;
46
+ /**
47
+ * Writes (upserts) the keyring record into the unlock Space as a JSON document.
48
+ *
49
+ * @param options {object}
50
+ * @param options.storageServerUrl {string}
51
+ * @param options.zcapClient {ZcapClient}
52
+ * @param options.spaceId {string} the unlock Space id
53
+ * @param options.record {object} the keyring record
54
+ * @returns {Promise<void>}
55
+ */
56
+ export declare function putUnlockKeyring({ storageServerUrl, zcapClient, spaceId, record }: {
57
+ storageServerUrl: string;
58
+ zcapClient: ZcapClient;
59
+ spaceId: string;
60
+ record: object;
61
+ }): Promise<void>;
62
+ /**
63
+ * Deletes the whole unlock Space (what retires an old passphrase on a
64
+ * passphrase change). `space.delete()` is idempotent, so an already-absent
65
+ * Space is a success.
66
+ *
67
+ * @param options {object}
68
+ * @param options.storageServerUrl {string}
69
+ * @param options.zcapClient {ZcapClient}
70
+ * @param options.spaceId {string} the unlock Space id
71
+ * @returns {Promise<void>}
72
+ */
73
+ export declare function deleteUnlockSpace({ storageServerUrl, zcapClient, spaceId }: {
74
+ storageServerUrl: string;
75
+ zcapClient: ZcapClient;
76
+ spaceId: string;
77
+ }): Promise<void>;
78
+ /**
79
+ * Deletes an unlock Space with an explicitly attached management capability,
80
+ * rather than by root invocation. The `zcapClient` here is the DATA identity's
81
+ * (not the unlock identity's); the attached `capability` -- the management zcap
82
+ * the unlock identity delegated to the data identity at bind time -- is what
83
+ * authorizes the DELETE against the unlock Space. This is the tap-free
84
+ * revocation path for a lost unlock method: the data identity can retire it
85
+ * without re-deriving the unlock identity from the (possibly lost) secret. A
86
+ * 404 is treated as success (idempotent -- the Space is already gone).
87
+ *
88
+ * @param options {object}
89
+ * @param options.storageServerUrl {string}
90
+ * @param options.zcapClient {ZcapClient} the data identity's client
91
+ * @param options.spaceId {string} the unlock Space id
92
+ * @param options.capability {IZcap} the delegated management zcap
93
+ * @returns {Promise<void>}
94
+ */
95
+ export declare function deleteUnlockSpaceWithCapability({ storageServerUrl, zcapClient, spaceId, capability }: {
96
+ storageServerUrl: string;
97
+ zcapClient: ZcapClient;
98
+ spaceId: string;
99
+ capability: IZcap;
100
+ }): Promise<void>;
101
+ //# sourceMappingURL=unlockSpace.d.ts.map