@interop/was-client 0.27.2 → 0.28.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.
|
@@ -2,36 +2,49 @@
|
|
|
2
2
|
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
* Idempotent Space + Collection provisioning for a synced
|
|
6
|
-
* is
|
|
7
|
-
*
|
|
5
|
+
* Idempotent, non-clobbering Space + Collection provisioning for a synced
|
|
6
|
+
* collection. Everything is create-if-absent: an existing Space description,
|
|
7
|
+
* an existing encryption descriptor (which may carry a key-epoch roster other
|
|
8
|
+
* clients encrypt under), and an existing access policy are never overwritten,
|
|
9
|
+
* so ANY controller-tier client -- including one that joined a Space some
|
|
10
|
+
* other wallet provisioned -- can re-run it to heal a torn provisioning run.
|
|
11
|
+
* On a fully settled Space it issues only reads.
|
|
8
12
|
*/
|
|
9
13
|
import type { WasClient } from '../WasClient.js';
|
|
10
14
|
/**
|
|
11
15
|
* Ensures the controller's Space exists and one synced collection is
|
|
12
|
-
* configured
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* configured, without overwriting anything already there. The Space is
|
|
17
|
+
* described first and configured only when absent -- an existing Space keeps
|
|
18
|
+
* its name AND its controller, so `controllerDid` is used only at creation
|
|
19
|
+
* (a joined client re-running this never rewrites the description). The
|
|
20
|
+
* collection likewise: when absent, an `'edv'` collection is created with the
|
|
21
|
+
* encryption descriptor `{ scheme: 'edv', version: EDV_SCHEME_VERSION }`, so
|
|
22
|
+
* the server stores only ciphertext it can never decrypt and validates every
|
|
23
|
+
* write against the declared envelope wire format -- the same version the
|
|
24
|
+
* cipher binds into each envelope's AEAD-protected header, so descriptor and
|
|
25
|
+
* envelopes cannot drift; a `'plaintext'` collection is created without one,
|
|
26
|
+
* with `force` so the descriptor-less upsert can create a fresh collection
|
|
27
|
+
* (running full-tier, a 404 from the pre-merge describe really means absent).
|
|
28
|
+
* An existing collection that lacks a descriptor an `'edv'` spec calls for
|
|
29
|
+
* gets the late in-place declaration (set-once on the server); one that
|
|
30
|
+
* already carries a descriptor -- possibly with appended key epochs -- is
|
|
31
|
+
* left untouched, epochs and display name included. A public collection gets
|
|
32
|
+
* the collection-level world-read grant (`setPublic`, what makes a resource
|
|
33
|
+
* URL in it resolve for anyone) only when its policy does not already say so.
|
|
34
|
+
* Runs full-tier -- the client invokes its own root authority.
|
|
23
35
|
*
|
|
24
36
|
* @param options {object}
|
|
25
37
|
* @param options.was {WasClient}
|
|
26
38
|
* @param options.spaceId {string}
|
|
27
|
-
* @param options.controllerDid {string} the Space controller (e.g. `did:key`)
|
|
39
|
+
* @param options.controllerDid {string} the Space controller (e.g. `did:key`);
|
|
40
|
+
* used only when the Space does not exist yet
|
|
28
41
|
* @param options.collectionId {string} the WAS collection id
|
|
29
42
|
* @param [options.encryption] {'edv' | 'plaintext'} defaults to `'edv'`
|
|
30
43
|
* @param [options.isPublic] {boolean} grant collection-level world read
|
|
31
|
-
* @param [options.spaceName] {string} the Space display name
|
|
32
|
-
* `'WAS Space'`
|
|
33
|
-
* @param [options.collectionName] {string} the collection display name
|
|
34
|
-
* defaults to the collection id
|
|
44
|
+
* @param [options.spaceName] {string} the Space display name, applied only at
|
|
45
|
+
* Space creation; defaults to `'WAS Space'`
|
|
46
|
+
* @param [options.collectionName] {string} the collection display name,
|
|
47
|
+
* applied only at collection creation; defaults to the collection id
|
|
35
48
|
* @returns {Promise<void>}
|
|
36
49
|
*/
|
|
37
50
|
export declare function ensureSpaceAndCollection({ was, spaceId, controllerDid, collectionId, encryption, isPublic, spaceName, collectionName }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../src/sync/provisioning.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../src/sync/provisioning.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAKhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,wBAAwB,CAAC,EAC7C,GAAG,EACH,OAAO,EACP,aAAa,EACb,YAAY,EACZ,UAAkB,EAClB,QAAgB,EAChB,SAAuB,EACvB,cAA6B,EAC9B,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,GAAG,WAAW,CAAA;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ChB"}
|
|
@@ -3,48 +3,72 @@
|
|
|
3
3
|
import { EDV_SCHEME_VERSION } from '../edv/constants.js';
|
|
4
4
|
/**
|
|
5
5
|
* Ensures the controller's Space exists and one synced collection is
|
|
6
|
-
* configured
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
6
|
+
* configured, without overwriting anything already there. The Space is
|
|
7
|
+
* described first and configured only when absent -- an existing Space keeps
|
|
8
|
+
* its name AND its controller, so `controllerDid` is used only at creation
|
|
9
|
+
* (a joined client re-running this never rewrites the description). The
|
|
10
|
+
* collection likewise: when absent, an `'edv'` collection is created with the
|
|
11
|
+
* encryption descriptor `{ scheme: 'edv', version: EDV_SCHEME_VERSION }`, so
|
|
12
|
+
* the server stores only ciphertext it can never decrypt and validates every
|
|
13
|
+
* write against the declared envelope wire format -- the same version the
|
|
14
|
+
* cipher binds into each envelope's AEAD-protected header, so descriptor and
|
|
15
|
+
* envelopes cannot drift; a `'plaintext'` collection is created without one,
|
|
16
|
+
* with `force` so the descriptor-less upsert can create a fresh collection
|
|
17
|
+
* (running full-tier, a 404 from the pre-merge describe really means absent).
|
|
18
|
+
* An existing collection that lacks a descriptor an `'edv'` spec calls for
|
|
19
|
+
* gets the late in-place declaration (set-once on the server); one that
|
|
20
|
+
* already carries a descriptor -- possibly with appended key epochs -- is
|
|
21
|
+
* left untouched, epochs and display name included. A public collection gets
|
|
22
|
+
* the collection-level world-read grant (`setPublic`, what makes a resource
|
|
23
|
+
* URL in it resolve for anyone) only when its policy does not already say so.
|
|
24
|
+
* Runs full-tier -- the client invokes its own root authority.
|
|
17
25
|
*
|
|
18
26
|
* @param options {object}
|
|
19
27
|
* @param options.was {WasClient}
|
|
20
28
|
* @param options.spaceId {string}
|
|
21
|
-
* @param options.controllerDid {string} the Space controller (e.g. `did:key`)
|
|
29
|
+
* @param options.controllerDid {string} the Space controller (e.g. `did:key`);
|
|
30
|
+
* used only when the Space does not exist yet
|
|
22
31
|
* @param options.collectionId {string} the WAS collection id
|
|
23
32
|
* @param [options.encryption] {'edv' | 'plaintext'} defaults to `'edv'`
|
|
24
33
|
* @param [options.isPublic] {boolean} grant collection-level world read
|
|
25
|
-
* @param [options.spaceName] {string} the Space display name
|
|
26
|
-
* `'WAS Space'`
|
|
27
|
-
* @param [options.collectionName] {string} the collection display name
|
|
28
|
-
* defaults to the collection id
|
|
34
|
+
* @param [options.spaceName] {string} the Space display name, applied only at
|
|
35
|
+
* Space creation; defaults to `'WAS Space'`
|
|
36
|
+
* @param [options.collectionName] {string} the collection display name,
|
|
37
|
+
* applied only at collection creation; defaults to the collection id
|
|
29
38
|
* @returns {Promise<void>}
|
|
30
39
|
*/
|
|
31
40
|
export async function ensureSpaceAndCollection({ was, spaceId, controllerDid, collectionId, encryption = 'edv', isPublic = false, spaceName = 'WAS Space', collectionName = collectionId }) {
|
|
32
41
|
const space = was.space(spaceId);
|
|
33
42
|
try {
|
|
34
|
-
await space.
|
|
43
|
+
if ((await space.describe()) === null) {
|
|
44
|
+
await space.configure({ name: spaceName, controller: controllerDid });
|
|
45
|
+
}
|
|
35
46
|
}
|
|
36
47
|
catch (err) {
|
|
37
48
|
throw new Error(`Failed to configure WAS space "${spaceId}" for "${controllerDid}".`, { cause: err });
|
|
38
49
|
}
|
|
39
50
|
try {
|
|
40
51
|
const collection = space.collection(collectionId);
|
|
41
|
-
await collection.
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
const current = await collection.describe();
|
|
53
|
+
if (current === null) {
|
|
54
|
+
await collection.configure(encryption === 'edv'
|
|
55
|
+
? {
|
|
56
|
+
name: collectionName,
|
|
57
|
+
encryption: { scheme: 'edv', version: EDV_SCHEME_VERSION }
|
|
58
|
+
}
|
|
59
|
+
: { name: collectionName, force: true });
|
|
60
|
+
}
|
|
61
|
+
else if (encryption === 'edv' && current.encryption === undefined) {
|
|
62
|
+
// The late in-place declaration: adding a descriptor to a collection
|
|
63
|
+
// that lacks one is allowed (set-once), while re-sending one over an
|
|
64
|
+
// existing descriptor would drop its appended key epochs -- which is
|
|
65
|
+
// exactly why an existing descriptor is never touched.
|
|
66
|
+
await collection.configure({
|
|
67
|
+
name: current.name ?? collectionName,
|
|
44
68
|
encryption: { scheme: 'edv', version: EDV_SCHEME_VERSION }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (isPublic) {
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (isPublic && !(await collection.isPublic())) {
|
|
48
72
|
await collection.setPublic();
|
|
49
73
|
}
|
|
50
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioning.js","sourceRoot":"","sources":["../../src/sync/provisioning.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provisioning.js","sourceRoot":"","sources":["../../src/sync/provisioning.ts"],"names":[],"mappings":"AAaA,6EAA6E;AAC7E,iEAAiE;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,EAC7C,GAAG,EACH,OAAO,EACP,aAAa,EACb,YAAY,EACZ,UAAU,GAAG,KAAK,EAClB,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,WAAW,EACvB,cAAc,GAAG,YAAY,EAU9B;IACC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEhC,IAAI,CAAC;QACH,IAAI,CAAC,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,kCAAkC,OAAO,UAAU,aAAa,IAAI,EACpE,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;QACjD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,CAAA;QAC3C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,UAAU,CAAC,SAAS,CACxB,UAAU,KAAK,KAAK;gBAClB,CAAC,CAAC;oBACE,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE;iBAC3D;gBACH,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,CAC1C,CAAA;QACH,CAAC;aAAM,IAAI,UAAU,KAAK,KAAK,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACpE,qEAAqE;YACrE,qEAAqE;YACrE,qEAAqE;YACrE,uDAAuD;YACvD,MAAM,UAAU,CAAC,SAAS,CAAC;gBACzB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,cAAc;gBACpC,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE;aAC3D,CAAC,CAAA;QACJ,CAAC;QACD,IAAI,QAAQ,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;YAC/C,MAAM,UAAU,CAAC,SAAS,EAAE,CAAA;QAC9B,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,mCAAmC,YAAY,eAAe,OAAO,IAAI,EACzE,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED