@interop/wallet-core 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/descriptors/cipher.d.ts +9 -0
- package/dist/descriptors/cipher.d.ts.map +1 -1
- package/dist/descriptors/cipher.js.map +1 -1
- package/dist/genesis/accountGenesis.d.ts +206 -0
- package/dist/genesis/accountGenesis.d.ts.map +1 -0
- package/dist/genesis/accountGenesis.js +294 -0
- package/dist/genesis/accountGenesis.js.map +1 -0
- package/dist/genesis/index.d.ts +22 -0
- package/dist/genesis/index.d.ts.map +1 -0
- package/dist/genesis/index.js +21 -0
- package/dist/genesis/index.js.map +1 -0
- package/dist/keys/index.d.ts +3 -1
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +3 -1
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/spaceEpochs.d.ts +33 -2
- package/dist/keys/spaceEpochs.d.ts.map +1 -1
- package/dist/keys/spaceEpochs.js +42 -2
- package/dist/keys/spaceEpochs.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +15 -9
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +52 -31
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/revokeClient.d.ts +8 -6
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +40 -24
- package/dist/webvh/revokeClient.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -127,6 +127,17 @@ The subpaths:
|
|
|
127
127
|
(connect code, approval, completion) plus the onboarding-response envelope
|
|
128
128
|
that carries a connect code back over an exchange.
|
|
129
129
|
|
|
130
|
+
- **`@interop/wallet-core/genesis`** -- the account-genesis ceremony: the local
|
|
131
|
+
mint of a brand-new account's complete key set (`mintAccountKeySet`: Space id,
|
|
132
|
+
client identity seed, user key, did:webvh update keys) and the staged
|
|
133
|
+
provisioning both apps must encode identically (`ensureAccountGenesis`: Space
|
|
134
|
+
provisioning, the optional KMS key-map acquisition, did:webvh genesis,
|
|
135
|
+
user-key roster genesis after DID publication, epoch[0] on every encrypted
|
|
136
|
+
roster collection, and the Space-controller promotion, also exported standing
|
|
137
|
+
alone as `ensurePromotedSpaceController`). Idempotent end to end: a torn run
|
|
138
|
+
heals by re-running. The keyring bind is deliberately not a stage, so a wallet
|
|
139
|
+
with no unlock method bound at creation drives the same ceremony.
|
|
140
|
+
|
|
130
141
|
- **`@interop/wallet-core/recovery`** -- recovery codes on the roster identity
|
|
131
142
|
model: a code as a minimal always-enrolled wallet client (format and
|
|
132
143
|
derivation, the recovery record, the document half of issuance / revocation /
|
|
@@ -22,6 +22,15 @@
|
|
|
22
22
|
* epoch after the one refresh is spent) propagates. A refresh that itself
|
|
23
23
|
* fails does not count as spent -- the original `UnknownEpochError` is
|
|
24
24
|
* rethrown and a later decrypt may try again.
|
|
25
|
+
*
|
|
26
|
+
* Only `UnknownEpochError` drives that refresh, and by design. The client
|
|
27
|
+
* splits the two ways a decrypt can find no key: an epoch the descriptor does
|
|
28
|
+
* not list at all raises `UnknownEpochError`, because a fresher descriptor may
|
|
29
|
+
* well list it; an epoch the descriptor does list but this reader holds no key
|
|
30
|
+
* for raises `KeyUnwrapError` (never a recipient, or removed and the epoch
|
|
31
|
+
* rotated). The second is rethrown immediately, with the refresh left
|
|
32
|
+
* untouched, since re-reading the same descriptor cannot produce a key the
|
|
33
|
+
* reader was not given.
|
|
25
34
|
*/
|
|
26
35
|
import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
|
|
27
36
|
import { type DocCipher } from '@interop/was-client/edv';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAChC,MAAM,cAAc,CAAA;AAErB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,4BAA4B,CAAC,EACjD,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,YAAY,EACb,EAAE;IACD,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,MAAM,CAAC,EAAE,0BAA0B,CAAA;IACnC,KAAK,EAAE,yBAAyB,CAAA;IAChC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,GAAG,OAAO,CAAC,SAAS,CAAC,CAoFrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"AAsCA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,iBAAiB,EAGlB,MAAM,cAAc,CAAA;AAErB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,EACjD,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,YAAY,EASb;IACC,MAAM,KAAK,GAAG,KAAK,IAAwB,EAAE;QAC3C,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC;YACzC,MAAM;YACN,KAAK;YACL,YAAY;YACZ,YAAY;SACb,CAAC,CAAA;QACF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,2CAA2C;gBACpE,kEAAkE;gBAClE,oEAAoE,CACvE,CAAA;QACH,CAAC;QACD,OAAO,kBAAkB,CAAC;YACxB,eAAe;YACf,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,UAAU;SACX,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,IAAI,KAAK,GAAG,MAAM,KAAK,EAAE,CAAA;IACzB,0EAA0E;IAC1E,yEAAyE;IACzE,+CAA+C;IAC/C,IAAI,SAAS,GAAyB,IAAI,CAAA;IAE1C,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAE1C,aAAa,EAAE,OAAO,CAAC,EAAE;YACvB,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,kCAAkC,CAC9D,CAAA;YACH,CAAC;YACD,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QACrC,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE;YACxB,IAAI,CAAC;gBACH,OAAO,MAAM,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;YAC1C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,CAAC,GAAG,YAAY,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACnD,MAAM,GAAG,CAAA;gBACX,CAAC;gBACD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;wBACpC,KAAK,GAAG,MAAM,CAAA;oBAChB,CAAC,CAAC,CAAA;oBACF,SAAS,GAAG,OAAO,CAAA;oBACnB,qEAAqE;oBACrE,oEAAoE;oBACpE,qEAAqE;oBACrE,mEAAmE;oBACnE,iEAAiE;oBACjE,0BAA0B;oBAC1B,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;wBACjB,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;4BAC1B,SAAS,GAAG,IAAI,CAAA;wBAClB,CAAC;oBACH,CAAC,CAAC,CAAA;gBACJ,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,SAAS,CAAA;gBACjB,CAAC;gBAAC,MAAM,CAAC;oBACP,mEAAmE;oBACnE,gEAAgE;oBAChE,+DAA+D;oBAC/D,mDAAmD;oBACnD,MAAM,GAAG,CAAA;gBACX,CAAC;gBACD,iEAAiE;gBACjE,8DAA8D;gBAC9D,+DAA+D;gBAC/D,iEAAiE;gBACjE,2BAA2B;gBAC3B,OAAO,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import type { CollectionEncryption, WasClient } from '@interop/was-client';
|
|
2
|
+
import type { EncryptionDescriptorStore } from '@interop/was-client/edv';
|
|
3
|
+
import type { IKeyAgreementKey } from '@interop/data-integrity-core';
|
|
4
|
+
import { type ClientWebvhUpdateKeys, type DidWebKeyMapV2, type ICapabilityAgent, type WebvhIdStore } from '../webvh/index.js';
|
|
5
|
+
import { type UserKey, type WalletSpaceEpochsResult } from '../keys/index.js';
|
|
6
|
+
import type { ResourceLogPinStore } from '../resourceLog/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* The complete key set a brand-new account mints locally before anything
|
|
9
|
+
* touches the network: the data Space id, this founding client's identity
|
|
10
|
+
* seed, the account's user key, and the client-held did:webvh update-key
|
|
11
|
+
* seeds. Persisting the set durably (under the app's unlock layer) is the
|
|
12
|
+
* caller's job, and for the update keys it must happen BEFORE
|
|
13
|
+
* {@link ensureAccountGenesis} publishes anything -- the seeds are the only
|
|
14
|
+
* update authority the log will ever accept.
|
|
15
|
+
*/
|
|
16
|
+
export interface AccountKeySet {
|
|
17
|
+
spaceId: string;
|
|
18
|
+
clientSeed: Uint8Array;
|
|
19
|
+
userKey: Required<UserKey>;
|
|
20
|
+
updateKeys: ClientWebvhUpdateKeys;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Mints a fresh data-Space id: 32 random bytes, base64url without padding.
|
|
24
|
+
* Random rather than controller-derived on purpose: the Space's controller is
|
|
25
|
+
* promoted to a did:webvh whose id embeds this Space id, so a
|
|
26
|
+
* controller-derived id would be circular.
|
|
27
|
+
*
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export declare function mintSpaceId(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Mints the complete key set of a brand-new account: a fresh Space id, a
|
|
33
|
+
* 32-byte client identity seed (expanded to the founding client's agents via
|
|
34
|
+
* `agentsFromSeed`), the account's user key, and the did:webvh update-key
|
|
35
|
+
* pair. Pure minting -- nothing here touches the network or any store.
|
|
36
|
+
*
|
|
37
|
+
* @returns {Promise<AccountKeySet>}
|
|
38
|
+
*/
|
|
39
|
+
export declare function mintAccountKeySet(): Promise<AccountKeySet>;
|
|
40
|
+
/**
|
|
41
|
+
* What the promotion stage found and did: `promoted` (the Space Description
|
|
42
|
+
* named another controller -- on a fresh signup, this founding client's
|
|
43
|
+
* did:key -- and the ceremony moved it to the account DID), `confirmed` (the
|
|
44
|
+
* Space already names the account DID; nothing written), or `healed` (the
|
|
45
|
+
* Description was unreadable under the session's signing identity -- the torn
|
|
46
|
+
* state where the controller PUT never landed -- and the re-PUT signed as the
|
|
47
|
+
* stored did:key controller landed it).
|
|
48
|
+
*/
|
|
49
|
+
export type SpaceControllerPromotion = 'promoted' | 'confirmed' | 'healed';
|
|
50
|
+
/**
|
|
51
|
+
* Promotes the data Space's controller to the account's did:webvh, as a state
|
|
52
|
+
* machine over the Space Description so every state a torn earlier run can
|
|
53
|
+
* leave behind converges:
|
|
54
|
+
*
|
|
55
|
+
* - The Description reads and already names `did`: nothing to do.
|
|
56
|
+
* - The Description reads and names another controller (a fresh signup: this
|
|
57
|
+
* founding client's did:key, which `was` is then signing as): one configure
|
|
58
|
+
* PUT moves it to `did`.
|
|
59
|
+
* - The Description is unreadable (`null` covers both absent and
|
|
60
|
+
* unauthorized): the torn case, where the session already signs under the
|
|
61
|
+
* did:webvh but the controller PUT never landed, so the server still
|
|
62
|
+
* authorizes only the stored did:key controller. The re-PUT goes through
|
|
63
|
+
* `wasAsClient`, the handle signing under this client's plain did:key.
|
|
64
|
+
*
|
|
65
|
+
* The PUT always carries the full `{ name, controller }` description, so the
|
|
66
|
+
* unreadable-Description merge guard in was-client's `configure` never
|
|
67
|
+
* defaults anything from a state this ceremony cannot see.
|
|
68
|
+
*
|
|
69
|
+
* @param options {object}
|
|
70
|
+
* @param options.was {WasClient} signing as the session currently signs
|
|
71
|
+
* (this client's did:key on a fresh signup; the promoted did:webvh keyId on
|
|
72
|
+
* a heal re-run)
|
|
73
|
+
* @param [options.wasAsClient] {WasClient} signing under this client's
|
|
74
|
+
* plain did:key, for the torn-promotion heal; omitted, that branch refuses
|
|
75
|
+
* instead of healing
|
|
76
|
+
* @param options.spaceId {string}
|
|
77
|
+
* @param options.did {string} the account's did:webvh DID
|
|
78
|
+
* @returns {Promise<SpaceControllerPromotion>}
|
|
79
|
+
*/
|
|
80
|
+
export declare function ensurePromotedSpaceController({ was, wasAsClient, spaceId, did }: {
|
|
81
|
+
was: WasClient;
|
|
82
|
+
wasAsClient?: WasClient;
|
|
83
|
+
spaceId: string;
|
|
84
|
+
did: string;
|
|
85
|
+
}): Promise<SpaceControllerPromotion>;
|
|
86
|
+
/**
|
|
87
|
+
* The Space-provisioning stage of {@link ensureAccountGenesis} failed: the
|
|
88
|
+
* Space (or part of its collection roster) could not be ensured, so nothing
|
|
89
|
+
* downstream ran. Raised as its own class with a stable `name`, so a caller
|
|
90
|
+
* that treats the later stages as non-fatal can still let a missing Space
|
|
91
|
+
* propagate -- match it on `err.name === 'AccountGenesisSpaceError'`, never
|
|
92
|
+
* `instanceof` (the error can be raised by a linked or duplicated copy of
|
|
93
|
+
* this package).
|
|
94
|
+
*/
|
|
95
|
+
export declare class AccountGenesisSpaceError extends Error {
|
|
96
|
+
constructor(options: {
|
|
97
|
+
spaceId: string;
|
|
98
|
+
cause: unknown;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The stages whose failures the ceremony collects instead of throwing (see
|
|
103
|
+
* the module doc for the split).
|
|
104
|
+
*/
|
|
105
|
+
export type AccountGenesisStage = 'didWebKeys' | 'roster' | 'epochs' | 'promotion';
|
|
106
|
+
/**
|
|
107
|
+
* What a completed ceremony reports: the account DID, each collected stage's
|
|
108
|
+
* outcome where it ran (the roster descriptor, the per-collection epoch
|
|
109
|
+
* install -- whose own `failed` list stays inside it -- and what the
|
|
110
|
+
* promotion found), and the stages that failed on this run. A result with
|
|
111
|
+
* `failed` entries is a resumable success: the account exists and is
|
|
112
|
+
* identified, and a naive re-run of the whole ceremony finishes the rest.
|
|
113
|
+
*/
|
|
114
|
+
export interface AccountGenesisResult {
|
|
115
|
+
did: string;
|
|
116
|
+
rosterDescriptor?: CollectionEncryption;
|
|
117
|
+
epochs?: WalletSpaceEpochsResult;
|
|
118
|
+
promotion?: SpaceControllerPromotion;
|
|
119
|
+
failed: Array<{
|
|
120
|
+
stage: AccountGenesisStage;
|
|
121
|
+
error: unknown;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Runs the account-genesis ceremony against an already-minted
|
|
126
|
+
* {@link AccountKeySet} (whose update-key seeds the caller has already
|
|
127
|
+
* persisted durably). Idempotent end to end: every stage adopts what an
|
|
128
|
+
* earlier run landed, so a torn run -- and a lost create race against a
|
|
129
|
+
* concurrent provisioner -- heals by re-running.
|
|
130
|
+
*
|
|
131
|
+
* Stage order (the module doc has the why): Space provisioning, the optional
|
|
132
|
+
* KMS key-map acquisition, did:webvh genesis, user-key roster genesis, the
|
|
133
|
+
* encrypted collections' epoch[0] install, Space-controller promotion.
|
|
134
|
+
*
|
|
135
|
+
* @param options {object}
|
|
136
|
+
* @param options.was {WasClient} signing as the session currently signs:
|
|
137
|
+
* this client's did:key on a fresh signup, the promoted did:webvh keyId on
|
|
138
|
+
* a heal re-run over an already-promoted account
|
|
139
|
+
* @param [options.wasAsClient] {WasClient} signing under this client's
|
|
140
|
+
* plain did:key, for the torn-promotion heal (see
|
|
141
|
+
* {@link ensurePromotedSpaceController})
|
|
142
|
+
* @param options.wasServerUrl {string} the storage server the account
|
|
143
|
+
* lives on; the did:webvh id embeds its host
|
|
144
|
+
* @param options.spaceId {string}
|
|
145
|
+
* @param options.keyAgent {ICapabilityAgent} this founding client's signing
|
|
146
|
+
* key agent (`agentsFromSeed` over the key set's `clientSeed`); its did:key
|
|
147
|
+
* id is the Space's controller at creation
|
|
148
|
+
* @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
|
|
149
|
+
* (identity) key-agreement key -- its published `keyAgreement` verification
|
|
150
|
+
* method, and the roster's first recipient
|
|
151
|
+
* @param options.userKey {UserKey} the account's user key, recipient zero
|
|
152
|
+
* of every encrypted collection and the roster's first epoch
|
|
153
|
+
* @param options.updateKeys {ClientWebvhUpdateKeys} the client-held
|
|
154
|
+
* did:webvh update-key seeds, already durably persisted
|
|
155
|
+
* @param options.idStore {WebvhIdStore} the account's `id` collection
|
|
156
|
+
* store the did:webvh ceremony reads and publishes through
|
|
157
|
+
* @param options.rosterStoreFor {Function} `({ did }) =>
|
|
158
|
+
* EncryptionDescriptorStore` -- builds the user-key roster's descriptor
|
|
159
|
+
* store once the account DID is known (the log-governed store's controller
|
|
160
|
+
* view and chain-head pin are the app's wiring)
|
|
161
|
+
* @param [options.provideDidWebKeys] {Function} `() =>
|
|
162
|
+
* Promise<DidWebKeyMapV2 | undefined>` -- the KMS key-map acquisition (a
|
|
163
|
+
* wallet that keeps a KMS runs its did:web provisioning here, after the
|
|
164
|
+
* Space exists); absent or resolving `undefined`, the genesis is
|
|
165
|
+
* client-keys-only and no `keys.json` is ever written. A throw is
|
|
166
|
+
* collected, not fatal: the genesis proceeds client-keys-only and a later
|
|
167
|
+
* run heals the document with the convenience key
|
|
168
|
+
* @param [options.expectedDid] {string} the account's did:webvh from the
|
|
169
|
+
* caller's stored account pointer, when it already names one; the genesis
|
|
170
|
+
* read then refuses a published log resolving to any other account
|
|
171
|
+
* @param [options.accountLogPinStore] {ResourceLogPinStore} this client's
|
|
172
|
+
* chain-head pin for the account log
|
|
173
|
+
* @param [options.onDidPublished] {Function} `({ did }) => Promise<void>`
|
|
174
|
+
* -- runs between the DID publication and the roster genesis, so the app
|
|
175
|
+
* can adopt the DID (and drop any verified-log memo) before the roster
|
|
176
|
+
* store's controller view resolves against the published document
|
|
177
|
+
* @param [options.promoteController] {boolean} whether to run the
|
|
178
|
+
* promotion stage (default `true`). An app whose account pointer must
|
|
179
|
+
* durably name the DID BEFORE the controller PUT lands -- and whose
|
|
180
|
+
* pointer write lives outside this call (freewallet's keyring re-bind) --
|
|
181
|
+
* passes `false` and runs {@link ensurePromotedSpaceController} itself
|
|
182
|
+
* after that write
|
|
183
|
+
* @returns {Promise<AccountGenesisResult>}
|
|
184
|
+
*/
|
|
185
|
+
export declare function ensureAccountGenesis({ was, wasAsClient, wasServerUrl, spaceId, keyAgent, clientKeyAgreementKey, userKey, updateKeys, idStore, rosterStoreFor, provideDidWebKeys, expectedDid, accountLogPinStore, onDidPublished, promoteController }: {
|
|
186
|
+
was: WasClient;
|
|
187
|
+
wasAsClient?: WasClient;
|
|
188
|
+
wasServerUrl: string;
|
|
189
|
+
spaceId: string;
|
|
190
|
+
keyAgent: ICapabilityAgent;
|
|
191
|
+
clientKeyAgreementKey: IKeyAgreementKey;
|
|
192
|
+
userKey: UserKey;
|
|
193
|
+
updateKeys: ClientWebvhUpdateKeys;
|
|
194
|
+
idStore: WebvhIdStore;
|
|
195
|
+
rosterStoreFor: (options: {
|
|
196
|
+
did: string;
|
|
197
|
+
}) => EncryptionDescriptorStore;
|
|
198
|
+
provideDidWebKeys?: () => Promise<DidWebKeyMapV2 | undefined>;
|
|
199
|
+
expectedDid?: string;
|
|
200
|
+
accountLogPinStore?: ResourceLogPinStore;
|
|
201
|
+
onDidPublished?: (published: {
|
|
202
|
+
did: string;
|
|
203
|
+
}) => Promise<void>;
|
|
204
|
+
promoteController?: boolean;
|
|
205
|
+
}): Promise<AccountGenesisResult>;
|
|
206
|
+
//# sourceMappingURL=accountGenesis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accountGenesis.d.ts","sourceRoot":"","sources":["../../src/genesis/accountGenesis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The account-genesis ceremony: minting a brand-new wallet account's key set
|
|
6
|
+
* and provisioning its data Space, in the one stage order every wallet app
|
|
7
|
+
* must encode identically -- Space provisioning, did:webvh genesis, user-key
|
|
8
|
+
* roster genesis (after DID publication, so the roster log's entry proofs
|
|
9
|
+
* anchor in the published document), epoch[0] on every encrypted roster
|
|
10
|
+
* collection, and Space-controller promotion.
|
|
11
|
+
*
|
|
12
|
+
* Two callers, one ceremony. A wallet that keeps a KMS (freewallet) supplies
|
|
13
|
+
* `provideDidWebKeys` and gets the KMS-backed did:webvh genesis; a wallet
|
|
14
|
+
* with no KMS anywhere in the path (dcw) supplies nothing and gets the
|
|
15
|
+
* client-keys-only genesis. The keyring bind is deliberately NOT a stage:
|
|
16
|
+
* where an app binds an unlock method (and whether it binds one at all)
|
|
17
|
+
* stays app-side, as does the `userExists` probe -- that probe exists only
|
|
18
|
+
* because a passphrase signup can collide with an existing account, which is
|
|
19
|
+
* an unlock-layer concern, not an account-genesis one.
|
|
20
|
+
*
|
|
21
|
+
* Every stage detects its own completion from durable state alone (the
|
|
22
|
+
* cascade/sweep posture): the Space provisioning and the epoch install are
|
|
23
|
+
* create-if-absent and adopt what an earlier provisioner landed, the
|
|
24
|
+
* did:webvh genesis probes `did.jsonl` and adopts a log its seeds still
|
|
25
|
+
* authorize, the roster genesis returns an existing roster untouched, and
|
|
26
|
+
* the promotion is a state machine over the Space Description. So a torn run
|
|
27
|
+
* heals by naively re-running the whole ceremony, backstopped by the
|
|
28
|
+
* login-time sweeps.
|
|
29
|
+
*
|
|
30
|
+
* The essential identity chain -- Space provisioning and the did:webvh
|
|
31
|
+
* genesis -- throws on failure (nothing downstream can proceed without it);
|
|
32
|
+
* the stages after it are collected in `failed` instead, so a transient
|
|
33
|
+
* failure on one never costs the caller the others' outcomes -- a completed
|
|
34
|
+
* call with `failed` entries is a resumable success, finished by a re-run.
|
|
35
|
+
*/
|
|
36
|
+
import { base64urlnopad } from '@scure/base';
|
|
37
|
+
import { provisionWalletSpace, WALLET_SPACE_NAME } from '../space/index.js';
|
|
38
|
+
import { clientSigningKeyMultibase, ensureDidWebvh, mintClientWebvhUpdateKeys } from '../webvh/index.js';
|
|
39
|
+
import { ensureUserKeyRoster, ensureWalletSpaceEpochs, mintUserKey } from '../keys/index.js';
|
|
40
|
+
/**
|
|
41
|
+
* The byte length of a freshly minted data-Space id.
|
|
42
|
+
*/
|
|
43
|
+
const SPACE_ID_BYTES = 32;
|
|
44
|
+
/**
|
|
45
|
+
* Mints a fresh data-Space id: 32 random bytes, base64url without padding.
|
|
46
|
+
* Random rather than controller-derived on purpose: the Space's controller is
|
|
47
|
+
* promoted to a did:webvh whose id embeds this Space id, so a
|
|
48
|
+
* controller-derived id would be circular.
|
|
49
|
+
*
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
export function mintSpaceId() {
|
|
53
|
+
return base64urlnopad.encode(crypto.getRandomValues(new Uint8Array(SPACE_ID_BYTES)));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Mints the complete key set of a brand-new account: a fresh Space id, a
|
|
57
|
+
* 32-byte client identity seed (expanded to the founding client's agents via
|
|
58
|
+
* `agentsFromSeed`), the account's user key, and the did:webvh update-key
|
|
59
|
+
* pair. Pure minting -- nothing here touches the network or any store.
|
|
60
|
+
*
|
|
61
|
+
* @returns {Promise<AccountKeySet>}
|
|
62
|
+
*/
|
|
63
|
+
export async function mintAccountKeySet() {
|
|
64
|
+
const clientSeed = crypto.getRandomValues(new Uint8Array(32));
|
|
65
|
+
return {
|
|
66
|
+
spaceId: mintSpaceId(),
|
|
67
|
+
clientSeed,
|
|
68
|
+
userKey: await mintUserKey(),
|
|
69
|
+
updateKeys: await mintClientWebvhUpdateKeys()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Promotes the data Space's controller to the account's did:webvh, as a state
|
|
74
|
+
* machine over the Space Description so every state a torn earlier run can
|
|
75
|
+
* leave behind converges:
|
|
76
|
+
*
|
|
77
|
+
* - The Description reads and already names `did`: nothing to do.
|
|
78
|
+
* - The Description reads and names another controller (a fresh signup: this
|
|
79
|
+
* founding client's did:key, which `was` is then signing as): one configure
|
|
80
|
+
* PUT moves it to `did`.
|
|
81
|
+
* - The Description is unreadable (`null` covers both absent and
|
|
82
|
+
* unauthorized): the torn case, where the session already signs under the
|
|
83
|
+
* did:webvh but the controller PUT never landed, so the server still
|
|
84
|
+
* authorizes only the stored did:key controller. The re-PUT goes through
|
|
85
|
+
* `wasAsClient`, the handle signing under this client's plain did:key.
|
|
86
|
+
*
|
|
87
|
+
* The PUT always carries the full `{ name, controller }` description, so the
|
|
88
|
+
* unreadable-Description merge guard in was-client's `configure` never
|
|
89
|
+
* defaults anything from a state this ceremony cannot see.
|
|
90
|
+
*
|
|
91
|
+
* @param options {object}
|
|
92
|
+
* @param options.was {WasClient} signing as the session currently signs
|
|
93
|
+
* (this client's did:key on a fresh signup; the promoted did:webvh keyId on
|
|
94
|
+
* a heal re-run)
|
|
95
|
+
* @param [options.wasAsClient] {WasClient} signing under this client's
|
|
96
|
+
* plain did:key, for the torn-promotion heal; omitted, that branch refuses
|
|
97
|
+
* instead of healing
|
|
98
|
+
* @param options.spaceId {string}
|
|
99
|
+
* @param options.did {string} the account's did:webvh DID
|
|
100
|
+
* @returns {Promise<SpaceControllerPromotion>}
|
|
101
|
+
*/
|
|
102
|
+
export async function ensurePromotedSpaceController({ was, wasAsClient, spaceId, did }) {
|
|
103
|
+
const space = was.space(spaceId);
|
|
104
|
+
const description = await space.describe();
|
|
105
|
+
if (description !== null) {
|
|
106
|
+
if (description.controller === did) {
|
|
107
|
+
return 'confirmed';
|
|
108
|
+
}
|
|
109
|
+
await space.configure({ name: WALLET_SPACE_NAME, controller: did });
|
|
110
|
+
return 'promoted';
|
|
111
|
+
}
|
|
112
|
+
if (!wasAsClient) {
|
|
113
|
+
throw new Error('The Space Description is unreadable under the current signing ' +
|
|
114
|
+
'identity and no did:key-signed client was supplied to heal a torn ' +
|
|
115
|
+
'controller promotion.');
|
|
116
|
+
}
|
|
117
|
+
await wasAsClient
|
|
118
|
+
.space(spaceId)
|
|
119
|
+
.configure({ name: WALLET_SPACE_NAME, controller: did });
|
|
120
|
+
return 'healed';
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The Space-provisioning stage of {@link ensureAccountGenesis} failed: the
|
|
124
|
+
* Space (or part of its collection roster) could not be ensured, so nothing
|
|
125
|
+
* downstream ran. Raised as its own class with a stable `name`, so a caller
|
|
126
|
+
* that treats the later stages as non-fatal can still let a missing Space
|
|
127
|
+
* propagate -- match it on `err.name === 'AccountGenesisSpaceError'`, never
|
|
128
|
+
* `instanceof` (the error can be raised by a linked or duplicated copy of
|
|
129
|
+
* this package).
|
|
130
|
+
*/
|
|
131
|
+
export class AccountGenesisSpaceError extends Error {
|
|
132
|
+
constructor(options) {
|
|
133
|
+
super(`Provisioning the wallet Space "${options.spaceId}" failed; ` +
|
|
134
|
+
'the account-genesis ceremony did not proceed.', { cause: options.cause });
|
|
135
|
+
this.name = 'AccountGenesisSpaceError';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Runs the account-genesis ceremony against an already-minted
|
|
140
|
+
* {@link AccountKeySet} (whose update-key seeds the caller has already
|
|
141
|
+
* persisted durably). Idempotent end to end: every stage adopts what an
|
|
142
|
+
* earlier run landed, so a torn run -- and a lost create race against a
|
|
143
|
+
* concurrent provisioner -- heals by re-running.
|
|
144
|
+
*
|
|
145
|
+
* Stage order (the module doc has the why): Space provisioning, the optional
|
|
146
|
+
* KMS key-map acquisition, did:webvh genesis, user-key roster genesis, the
|
|
147
|
+
* encrypted collections' epoch[0] install, Space-controller promotion.
|
|
148
|
+
*
|
|
149
|
+
* @param options {object}
|
|
150
|
+
* @param options.was {WasClient} signing as the session currently signs:
|
|
151
|
+
* this client's did:key on a fresh signup, the promoted did:webvh keyId on
|
|
152
|
+
* a heal re-run over an already-promoted account
|
|
153
|
+
* @param [options.wasAsClient] {WasClient} signing under this client's
|
|
154
|
+
* plain did:key, for the torn-promotion heal (see
|
|
155
|
+
* {@link ensurePromotedSpaceController})
|
|
156
|
+
* @param options.wasServerUrl {string} the storage server the account
|
|
157
|
+
* lives on; the did:webvh id embeds its host
|
|
158
|
+
* @param options.spaceId {string}
|
|
159
|
+
* @param options.keyAgent {ICapabilityAgent} this founding client's signing
|
|
160
|
+
* key agent (`agentsFromSeed` over the key set's `clientSeed`); its did:key
|
|
161
|
+
* id is the Space's controller at creation
|
|
162
|
+
* @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
|
|
163
|
+
* (identity) key-agreement key -- its published `keyAgreement` verification
|
|
164
|
+
* method, and the roster's first recipient
|
|
165
|
+
* @param options.userKey {UserKey} the account's user key, recipient zero
|
|
166
|
+
* of every encrypted collection and the roster's first epoch
|
|
167
|
+
* @param options.updateKeys {ClientWebvhUpdateKeys} the client-held
|
|
168
|
+
* did:webvh update-key seeds, already durably persisted
|
|
169
|
+
* @param options.idStore {WebvhIdStore} the account's `id` collection
|
|
170
|
+
* store the did:webvh ceremony reads and publishes through
|
|
171
|
+
* @param options.rosterStoreFor {Function} `({ did }) =>
|
|
172
|
+
* EncryptionDescriptorStore` -- builds the user-key roster's descriptor
|
|
173
|
+
* store once the account DID is known (the log-governed store's controller
|
|
174
|
+
* view and chain-head pin are the app's wiring)
|
|
175
|
+
* @param [options.provideDidWebKeys] {Function} `() =>
|
|
176
|
+
* Promise<DidWebKeyMapV2 | undefined>` -- the KMS key-map acquisition (a
|
|
177
|
+
* wallet that keeps a KMS runs its did:web provisioning here, after the
|
|
178
|
+
* Space exists); absent or resolving `undefined`, the genesis is
|
|
179
|
+
* client-keys-only and no `keys.json` is ever written. A throw is
|
|
180
|
+
* collected, not fatal: the genesis proceeds client-keys-only and a later
|
|
181
|
+
* run heals the document with the convenience key
|
|
182
|
+
* @param [options.expectedDid] {string} the account's did:webvh from the
|
|
183
|
+
* caller's stored account pointer, when it already names one; the genesis
|
|
184
|
+
* read then refuses a published log resolving to any other account
|
|
185
|
+
* @param [options.accountLogPinStore] {ResourceLogPinStore} this client's
|
|
186
|
+
* chain-head pin for the account log
|
|
187
|
+
* @param [options.onDidPublished] {Function} `({ did }) => Promise<void>`
|
|
188
|
+
* -- runs between the DID publication and the roster genesis, so the app
|
|
189
|
+
* can adopt the DID (and drop any verified-log memo) before the roster
|
|
190
|
+
* store's controller view resolves against the published document
|
|
191
|
+
* @param [options.promoteController] {boolean} whether to run the
|
|
192
|
+
* promotion stage (default `true`). An app whose account pointer must
|
|
193
|
+
* durably name the DID BEFORE the controller PUT lands -- and whose
|
|
194
|
+
* pointer write lives outside this call (freewallet's keyring re-bind) --
|
|
195
|
+
* passes `false` and runs {@link ensurePromotedSpaceController} itself
|
|
196
|
+
* after that write
|
|
197
|
+
* @returns {Promise<AccountGenesisResult>}
|
|
198
|
+
*/
|
|
199
|
+
export async function ensureAccountGenesis({ was, wasAsClient, wasServerUrl, spaceId, keyAgent, clientKeyAgreementKey, userKey, updateKeys, idStore, rosterStoreFor, provideDidWebKeys, expectedDid, accountLogPinStore, onDidPublished, promoteController = true }) {
|
|
200
|
+
const failed = [];
|
|
201
|
+
// 1. The Space and its collection roster, create-if-absent under this
|
|
202
|
+
// founding client's did:key controller (adopted untouched when it exists).
|
|
203
|
+
// Raised as the typed refusal so a caller that treats the later stages as
|
|
204
|
+
// non-fatal can still propagate a Space that never came up.
|
|
205
|
+
try {
|
|
206
|
+
await provisionWalletSpace({ was, spaceId, controllerDid: keyAgent.id });
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
throw new AccountGenesisSpaceError({ spaceId, cause: err });
|
|
210
|
+
}
|
|
211
|
+
// 2. The optional KMS key map, acquired only once the Space exists (a
|
|
212
|
+
// KMS-keeping wallet writes keys.json and did.json into it here). A throw
|
|
213
|
+
// degrades to the client-keys-only genesis rather than aborting: every
|
|
214
|
+
// later ceremony anchors in client keys, and the first KMS-capable re-run
|
|
215
|
+
// heals the document with the convenience key.
|
|
216
|
+
let didWebKeys;
|
|
217
|
+
if (provideDidWebKeys) {
|
|
218
|
+
try {
|
|
219
|
+
didWebKeys = await provideDidWebKeys();
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
failed.push({ stage: 'didWebKeys', error: err });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 3. The did:webvh genesis -- probe, adopt, or create-and-publish. Fatal on
|
|
226
|
+
// failure: the account DID is what every remaining stage anchors in.
|
|
227
|
+
const { publicKeyMultibase: keyAgreementKeyMultibase } = clientKeyAgreementKey;
|
|
228
|
+
if (!keyAgreementKeyMultibase) {
|
|
229
|
+
throw new Error('The client key-agreement key has no public multibase.');
|
|
230
|
+
}
|
|
231
|
+
const { did } = await ensureDidWebvh({
|
|
232
|
+
idStore,
|
|
233
|
+
wasServerUrl,
|
|
234
|
+
spaceId,
|
|
235
|
+
...(didWebKeys ? { didWebKeys } : {}),
|
|
236
|
+
clientKeys: {
|
|
237
|
+
signingKeyMultibase: clientSigningKeyMultibase({ keyAgent }),
|
|
238
|
+
keyAgreementKeyMultibase
|
|
239
|
+
},
|
|
240
|
+
updateKeys,
|
|
241
|
+
...(expectedDid !== undefined ? { expectedDid } : {}),
|
|
242
|
+
...(accountLogPinStore ? { pinStore: accountLogPinStore } : {})
|
|
243
|
+
});
|
|
244
|
+
await onDidPublished?.({ did });
|
|
245
|
+
// 4. The user-key roster genesis, strictly after the DID publication: the
|
|
246
|
+
// roster log's entry proofs anchor in the published document, so a roster
|
|
247
|
+
// created first could never verify.
|
|
248
|
+
let rosterDescriptor;
|
|
249
|
+
try {
|
|
250
|
+
rosterDescriptor = await ensureUserKeyRoster({
|
|
251
|
+
store: rosterStoreFor({ did }),
|
|
252
|
+
userKey,
|
|
253
|
+
clientKeyAgreementKey
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
failed.push({ stage: 'roster', error: err });
|
|
258
|
+
}
|
|
259
|
+
// 5. Epoch[0] on every encrypted roster collection, wrapped to the user
|
|
260
|
+
// key. Its own per-collection failures stay inside the result (`epochs
|
|
261
|
+
// .failed`); only a fan-out that could not run at all lands here.
|
|
262
|
+
let epochs;
|
|
263
|
+
try {
|
|
264
|
+
epochs = await ensureWalletSpaceEpochs({ was, spaceId, userKey });
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
failed.push({ stage: 'epochs', error: err });
|
|
268
|
+
}
|
|
269
|
+
// 6. The controller promotion, last: every earlier stage ran under the
|
|
270
|
+
// signing identity the Space's stored controller authorizes. Skipped when
|
|
271
|
+
// the caller's account-pointer write must land first (see the JSDoc).
|
|
272
|
+
let promotion;
|
|
273
|
+
if (promoteController) {
|
|
274
|
+
try {
|
|
275
|
+
promotion = await ensurePromotedSpaceController({
|
|
276
|
+
was,
|
|
277
|
+
...(wasAsClient ? { wasAsClient } : {}),
|
|
278
|
+
spaceId,
|
|
279
|
+
did
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
failed.push({ stage: 'promotion', error: err });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
did,
|
|
288
|
+
...(rosterDescriptor ? { rosterDescriptor } : {}),
|
|
289
|
+
...(epochs ? { epochs } : {}),
|
|
290
|
+
...(promotion ? { promotion } : {}),
|
|
291
|
+
failed
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=accountGenesis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accountGenesis.js","sourceRoot":"","sources":["../../src/genesis/accountGenesis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/genesis` subpath: the account-genesis ceremony --
|
|
6
|
+
* minting a brand-new account's key set and provisioning its data Space in
|
|
7
|
+
* the one stage order both wallet apps must encode identically.
|
|
8
|
+
*
|
|
9
|
+
* - `mintAccountKeySet` / `mintSpaceId` -- the local mint of a new account's
|
|
10
|
+
* complete key set (Space id, client identity seed, user key, did:webvh
|
|
11
|
+
* update keys), before anything touches the network.
|
|
12
|
+
* - `ensureAccountGenesis` -- the ceremony itself: Space provisioning, the
|
|
13
|
+
* optional KMS key-map acquisition, did:webvh genesis, user-key roster
|
|
14
|
+
* genesis, epoch[0] on every encrypted roster collection, and
|
|
15
|
+
* Space-controller promotion; idempotent end to end, so a torn run heals
|
|
16
|
+
* by re-running.
|
|
17
|
+
* - `ensurePromotedSpaceController` -- the promotion stage standing alone,
|
|
18
|
+
* the state machine a login-time heal drives directly.
|
|
19
|
+
*/
|
|
20
|
+
export { AccountGenesisSpaceError, ensureAccountGenesis, ensurePromotedSpaceController, mintAccountKeySet, mintSpaceId } from './accountGenesis.js';
|
|
21
|
+
export type { AccountGenesisResult, AccountGenesisStage, AccountKeySet, SpaceControllerPromotion } from './accountGenesis.js';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/genesis/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,6BAA6B,EAC7B,iBAAiB,EACjB,WAAW,EACZ,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,wBAAwB,EACzB,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The `@interop/wallet-core/genesis` subpath: the account-genesis ceremony --
|
|
6
|
+
* minting a brand-new account's key set and provisioning its data Space in
|
|
7
|
+
* the one stage order both wallet apps must encode identically.
|
|
8
|
+
*
|
|
9
|
+
* - `mintAccountKeySet` / `mintSpaceId` -- the local mint of a new account's
|
|
10
|
+
* complete key set (Space id, client identity seed, user key, did:webvh
|
|
11
|
+
* update keys), before anything touches the network.
|
|
12
|
+
* - `ensureAccountGenesis` -- the ceremony itself: Space provisioning, the
|
|
13
|
+
* optional KMS key-map acquisition, did:webvh genesis, user-key roster
|
|
14
|
+
* genesis, epoch[0] on every encrypted roster collection, and
|
|
15
|
+
* Space-controller promotion; idempotent end to end, so a torn run heals
|
|
16
|
+
* by re-running.
|
|
17
|
+
* - `ensurePromotedSpaceController` -- the promotion stage standing alone,
|
|
18
|
+
* the state machine a login-time heal drives directly.
|
|
19
|
+
*/
|
|
20
|
+
export { AccountGenesisSpaceError, ensureAccountGenesis, ensurePromotedSpaceController, mintAccountKeySet, mintSpaceId } from './accountGenesis.js';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/genesis/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,6BAA6B,EAC7B,iBAAiB,EACjB,WAAW,EACZ,MAAM,qBAAqB,CAAA"}
|
package/dist/keys/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
* - `ensureWalletSpaceEpochs` -- the provision-time epoch[0] install for the
|
|
45
45
|
* wallet Space's encrypted collections, the EDV-bearing second step of
|
|
46
46
|
* `provisionWalletSpace`.
|
|
47
|
+
* - `ensureIndexedFirstEpoch` -- one collection's epoch[0] plus its
|
|
48
|
+
* blinded-index HMAC key, adopting a pre-blind-index roster as-is.
|
|
47
49
|
*/
|
|
48
50
|
export { mintUserKey, userKeyVaultKeys } from './userKey.js';
|
|
49
51
|
export type { UserKey } from './userKey.js';
|
|
@@ -56,7 +58,7 @@ export type { UserKeyRosterReadResult, RosterRecipientDocument } from './userKey
|
|
|
56
58
|
export { userKeyRosterDescriptorStore } from './rosterStore.js';
|
|
57
59
|
export { EPOCH_CONFIGURATION_STATE_TYPE, isSealableDescriptorStore, logGovernedDescriptorStore } from './rosterLogStore.js';
|
|
58
60
|
export type { SealableEncryptionDescriptorStore } from './rosterLogStore.js';
|
|
59
|
-
export { ensureWalletSpaceEpochs } from './spaceEpochs.js';
|
|
61
|
+
export { ensureIndexedFirstEpoch, ensureWalletSpaceEpochs } from './spaceEpochs.js';
|
|
60
62
|
export type { WalletSpaceEpochsResult } from './spaceEpochs.js';
|
|
61
63
|
export { readClientLabels, removeClientLabel, setClientLabel } from './clientLabels.js';
|
|
62
64
|
export type { ClientLabelsRecord, ClientLabelsStore } from './clientLabels.js';
|