cojson 0.7.0-alpha.7 → 0.7.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/.eslintrc.cjs +3 -2
- package/.prettierrc.js +9 -0
- package/.turbo/turbo-build.log +3 -30
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +1106 -0
- package/CHANGELOG.md +98 -0
- package/README.md +3 -1
- package/dist/base64url.test.js +25 -0
- package/dist/base64url.test.js.map +1 -0
- package/dist/coValueCore.js +60 -37
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/account.js +16 -15
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +1 -1
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +17 -8
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/group.js +13 -14
- package/dist/coValues/group.js.map +1 -1
- package/dist/coreToCoValue.js.map +1 -1
- package/dist/crypto/PureJSCrypto.js +89 -0
- package/dist/crypto/PureJSCrypto.js.map +1 -0
- package/dist/crypto/WasmCrypto.js +127 -0
- package/dist/crypto/WasmCrypto.js.map +1 -0
- package/dist/crypto/crypto.js +151 -0
- package/dist/crypto/crypto.js.map +1 -0
- package/dist/ids.js +4 -2
- package/dist/ids.js.map +1 -1
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/jsonStringify.js.map +1 -1
- package/dist/localNode.js +41 -38
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.js +6 -6
- package/dist/permissions.js.map +1 -1
- package/dist/storage/FileSystem.js +61 -0
- package/dist/storage/FileSystem.js.map +1 -0
- package/dist/storage/chunksAndKnownStates.js +97 -0
- package/dist/storage/chunksAndKnownStates.js.map +1 -0
- package/dist/storage/index.js +265 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/sync.js +29 -25
- package/dist/sync.js.map +1 -1
- package/dist/tests/account.test.js +58 -0
- package/dist/tests/account.test.js.map +1 -0
- package/dist/tests/coList.test.js +76 -0
- package/dist/tests/coList.test.js.map +1 -0
- package/dist/tests/coMap.test.js +136 -0
- package/dist/tests/coMap.test.js.map +1 -0
- package/dist/tests/coStream.test.js +172 -0
- package/dist/tests/coStream.test.js.map +1 -0
- package/dist/tests/coValueCore.test.js +114 -0
- package/dist/tests/coValueCore.test.js.map +1 -0
- package/dist/tests/crypto.test.js +118 -0
- package/dist/tests/crypto.test.js.map +1 -0
- package/dist/tests/cryptoImpl.test.js +113 -0
- package/dist/tests/cryptoImpl.test.js.map +1 -0
- package/dist/tests/group.test.js +34 -0
- package/dist/tests/group.test.js.map +1 -0
- package/dist/tests/permissions.test.js +1060 -0
- package/dist/tests/permissions.test.js.map +1 -0
- package/dist/tests/sync.test.js +816 -0
- package/dist/tests/sync.test.js.map +1 -0
- package/dist/tests/testUtils.js +12 -11
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -1
- package/dist/typeUtils/isAccountID.js.map +1 -1
- package/dist/typeUtils/isCoValue.js.map +1 -1
- package/package.json +14 -27
- package/src/base64url.test.ts +6 -5
- package/src/coValue.ts +1 -1
- package/src/coValueCore.ts +179 -126
- package/src/coValues/account.ts +30 -32
- package/src/coValues/coList.ts +11 -11
- package/src/coValues/coMap.ts +27 -17
- package/src/coValues/coStream.ts +17 -17
- package/src/coValues/group.ts +93 -109
- package/src/coreToCoValue.ts +5 -2
- package/src/crypto/PureJSCrypto.ts +200 -0
- package/src/crypto/WasmCrypto.ts +259 -0
- package/src/crypto/crypto.ts +336 -0
- package/src/ids.ts +8 -7
- package/src/index.ts +24 -24
- package/src/jsonStringify.ts +6 -4
- package/src/jsonValue.ts +2 -2
- package/src/localNode.ts +103 -109
- package/src/media.ts +3 -3
- package/src/permissions.ts +19 -21
- package/src/storage/FileSystem.ts +152 -0
- package/src/storage/chunksAndKnownStates.ts +139 -0
- package/src/storage/index.ts +479 -0
- package/src/streamUtils.ts +12 -12
- package/src/sync.ts +79 -63
- package/src/tests/account.test.ts +15 -15
- package/src/tests/coList.test.ts +94 -0
- package/src/tests/coMap.test.ts +162 -0
- package/src/tests/coStream.test.ts +246 -0
- package/src/tests/coValueCore.test.ts +36 -37
- package/src/tests/crypto.test.ts +66 -72
- package/src/tests/cryptoImpl.test.ts +183 -0
- package/src/tests/group.test.ts +16 -17
- package/src/tests/permissions.test.ts +269 -283
- package/src/tests/sync.test.ts +122 -123
- package/src/tests/testUtils.ts +24 -21
- package/src/typeUtils/accountOrAgentIDfromSessionID.ts +1 -2
- package/src/typeUtils/expectGroup.ts +1 -1
- package/src/typeUtils/isAccountID.ts +0 -1
- package/src/typeUtils/isCoValue.ts +1 -2
- package/tsconfig.json +0 -1
- package/dist/crypto.js +0 -254
- package/dist/crypto.js.map +0 -1
- package/src/crypto.ts +0 -484
- package/src/tests/coValue.test.ts +0 -497
package/src/localNode.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AgentSecret,
|
|
3
|
-
agentSecretFromSecretSeed,
|
|
4
|
-
createdNowUnique,
|
|
5
|
-
getAgentID,
|
|
6
|
-
getAgentSealerID,
|
|
7
|
-
getAgentSealerSecret,
|
|
8
|
-
newRandomAgentSecret,
|
|
9
|
-
newRandomKeySecret,
|
|
10
|
-
seal,
|
|
11
|
-
} from "./crypto.js";
|
|
1
|
+
import { AgentSecret, CryptoProvider } from "./crypto/crypto.js";
|
|
12
2
|
import {
|
|
13
3
|
CoValueCore,
|
|
14
4
|
CoValueHeader,
|
|
@@ -33,8 +23,7 @@ import {
|
|
|
33
23
|
RawProfile,
|
|
34
24
|
RawAccountMigration,
|
|
35
25
|
} from "./coValues/account.js";
|
|
36
|
-
import {
|
|
37
|
-
import { RawCoValue } from "./index.js";
|
|
26
|
+
import { Profile, RawCoValue } from "./index.js";
|
|
38
27
|
import { expectGroup } from "./typeUtils/expectGroup.js";
|
|
39
28
|
|
|
40
29
|
/** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
|
|
@@ -49,6 +38,8 @@ const { localNode } = useJazz();
|
|
|
49
38
|
```
|
|
50
39
|
*/
|
|
51
40
|
export class LocalNode {
|
|
41
|
+
/** @internal */
|
|
42
|
+
crypto: CryptoProvider;
|
|
52
43
|
/** @internal */
|
|
53
44
|
coValues: { [key: RawCoID]: CoValueState } = {};
|
|
54
45
|
/** @category 3. Low-level */
|
|
@@ -61,24 +52,28 @@ export class LocalNode {
|
|
|
61
52
|
/** @category 3. Low-level */
|
|
62
53
|
constructor(
|
|
63
54
|
account: ControlledAccountOrAgent,
|
|
64
|
-
currentSessionID: SessionID
|
|
55
|
+
currentSessionID: SessionID,
|
|
56
|
+
crypto: CryptoProvider,
|
|
65
57
|
) {
|
|
66
58
|
this.account = account;
|
|
67
59
|
this.currentSessionID = currentSessionID;
|
|
60
|
+
this.crypto = crypto;
|
|
68
61
|
}
|
|
69
62
|
|
|
70
63
|
/** @category 2. Node Creation */
|
|
71
64
|
static async withNewlyCreatedAccount<
|
|
72
|
-
Meta extends AccountMeta = AccountMeta
|
|
65
|
+
Meta extends AccountMeta = AccountMeta,
|
|
73
66
|
>({
|
|
74
|
-
|
|
67
|
+
creationProps,
|
|
75
68
|
peersToLoadFrom,
|
|
76
69
|
migration,
|
|
77
|
-
|
|
70
|
+
crypto,
|
|
71
|
+
initialAgentSecret = crypto.newRandomAgentSecret(),
|
|
78
72
|
}: {
|
|
79
|
-
name: string;
|
|
73
|
+
creationProps: { name: string };
|
|
80
74
|
peersToLoadFrom?: Peer[];
|
|
81
75
|
migration?: RawAccountMigration<Meta>;
|
|
76
|
+
crypto: CryptoProvider;
|
|
82
77
|
initialAgentSecret?: AgentSecret;
|
|
83
78
|
}): Promise<{
|
|
84
79
|
node: LocalNode;
|
|
@@ -86,27 +81,23 @@ export class LocalNode {
|
|
|
86
81
|
accountSecret: AgentSecret;
|
|
87
82
|
sessionID: SessionID;
|
|
88
83
|
}> {
|
|
89
|
-
const throwawayAgent = newRandomAgentSecret();
|
|
84
|
+
const throwawayAgent = crypto.newRandomAgentSecret();
|
|
90
85
|
const setupNode = new LocalNode(
|
|
91
|
-
new ControlledAgent(throwawayAgent),
|
|
92
|
-
newRandomSessionID(getAgentID(throwawayAgent))
|
|
86
|
+
new ControlledAgent(throwawayAgent, crypto),
|
|
87
|
+
newRandomSessionID(crypto.getAgentID(throwawayAgent)),
|
|
88
|
+
crypto,
|
|
93
89
|
);
|
|
94
90
|
|
|
95
|
-
const account = setupNode.createAccount(
|
|
91
|
+
const account = setupNode.createAccount(initialAgentSecret);
|
|
96
92
|
|
|
97
93
|
const nodeWithAccount = account.core.node.testWithDifferentAccount(
|
|
98
94
|
account,
|
|
99
|
-
newRandomSessionID(account.id)
|
|
95
|
+
newRandomSessionID(account.id),
|
|
100
96
|
);
|
|
101
97
|
|
|
102
98
|
const accountOnNodeWithAccount =
|
|
103
99
|
nodeWithAccount.account as RawControlledAccount<Meta>;
|
|
104
100
|
|
|
105
|
-
const profile = nodeWithAccount.expectProfileLoaded(
|
|
106
|
-
accountOnNodeWithAccount.id,
|
|
107
|
-
"After creating account"
|
|
108
|
-
);
|
|
109
|
-
|
|
110
101
|
if (peersToLoadFrom) {
|
|
111
102
|
for (const peer of peersToLoadFrom) {
|
|
112
103
|
nodeWithAccount.syncManager.addPeer(peer);
|
|
@@ -114,29 +105,44 @@ export class LocalNode {
|
|
|
114
105
|
}
|
|
115
106
|
|
|
116
107
|
if (migration) {
|
|
117
|
-
await migration(
|
|
108
|
+
await migration(
|
|
109
|
+
accountOnNodeWithAccount,
|
|
110
|
+
nodeWithAccount,
|
|
111
|
+
creationProps,
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
const profileGroup = accountOnNodeWithAccount.createGroup();
|
|
115
|
+
profileGroup.addMember("everyone", "reader");
|
|
116
|
+
const profile = profileGroup.createMap<Profile>({
|
|
117
|
+
name: creationProps.name,
|
|
118
|
+
});
|
|
119
|
+
accountOnNodeWithAccount.set("profile", profile.id, "trusting");
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
const controlledAccount = new RawControlledAccount(
|
|
121
123
|
accountOnNodeWithAccount.core,
|
|
122
|
-
accountOnNodeWithAccount.agentSecret
|
|
124
|
+
accountOnNodeWithAccount.agentSecret,
|
|
123
125
|
);
|
|
124
126
|
|
|
125
|
-
nodeWithAccount.account = controlledAccount
|
|
127
|
+
nodeWithAccount.account = controlledAccount;
|
|
126
128
|
nodeWithAccount.coValues[controlledAccount.id] = {
|
|
127
129
|
state: "loaded",
|
|
128
130
|
coValue: controlledAccount.core,
|
|
129
131
|
};
|
|
130
132
|
controlledAccount.core._cachedContent = undefined;
|
|
131
133
|
|
|
134
|
+
if (!controlledAccount.get("profile")) {
|
|
135
|
+
throw new Error("Must set account profile in initial migration");
|
|
136
|
+
}
|
|
137
|
+
|
|
132
138
|
// we shouldn't need this, but it fixes account data not syncing for new accounts
|
|
133
139
|
function syncAllCoValuesAfterCreateAccount() {
|
|
134
140
|
for (const coValueEntry of Object.values(
|
|
135
|
-
nodeWithAccount.coValues
|
|
141
|
+
nodeWithAccount.coValues,
|
|
136
142
|
)) {
|
|
137
143
|
if (coValueEntry.state === "loaded") {
|
|
138
144
|
void nodeWithAccount.syncManager.syncCoValue(
|
|
139
|
-
coValueEntry.coValue
|
|
145
|
+
coValueEntry.coValue,
|
|
140
146
|
);
|
|
141
147
|
}
|
|
142
148
|
}
|
|
@@ -160,17 +166,20 @@ export class LocalNode {
|
|
|
160
166
|
accountSecret,
|
|
161
167
|
sessionID,
|
|
162
168
|
peersToLoadFrom,
|
|
169
|
+
crypto,
|
|
163
170
|
migration,
|
|
164
171
|
}: {
|
|
165
172
|
accountID: AccountID;
|
|
166
173
|
accountSecret: AgentSecret;
|
|
167
|
-
sessionID: SessionID;
|
|
174
|
+
sessionID: SessionID | undefined;
|
|
168
175
|
peersToLoadFrom: Peer[];
|
|
176
|
+
crypto: CryptoProvider;
|
|
169
177
|
migration?: RawAccountMigration<Meta>;
|
|
170
178
|
}): Promise<LocalNode> {
|
|
171
179
|
const loadingNode = new LocalNode(
|
|
172
|
-
new ControlledAgent(accountSecret),
|
|
173
|
-
newRandomSessionID(accountID)
|
|
180
|
+
new ControlledAgent(accountSecret, crypto),
|
|
181
|
+
newRandomSessionID(accountID),
|
|
182
|
+
crypto,
|
|
174
183
|
);
|
|
175
184
|
|
|
176
185
|
for (const peer of peersToLoadFrom) {
|
|
@@ -187,13 +196,13 @@ export class LocalNode {
|
|
|
187
196
|
|
|
188
197
|
const controlledAccount = new RawControlledAccount(
|
|
189
198
|
account.core,
|
|
190
|
-
accountSecret
|
|
199
|
+
accountSecret,
|
|
191
200
|
);
|
|
192
201
|
|
|
193
202
|
// since this is all synchronous, we can just swap out nodes for the SyncManager
|
|
194
203
|
const node = loadingNode.testWithDifferentAccount(
|
|
195
204
|
controlledAccount,
|
|
196
|
-
sessionID
|
|
205
|
+
sessionID || newRandomSessionID(accountID),
|
|
197
206
|
);
|
|
198
207
|
node.syncManager = loadingNode.syncManager;
|
|
199
208
|
node.syncManager.local = node;
|
|
@@ -218,12 +227,11 @@ export class LocalNode {
|
|
|
218
227
|
if (migration) {
|
|
219
228
|
await migration(
|
|
220
229
|
controlledAccount as RawControlledAccount<Meta>,
|
|
221
|
-
|
|
222
|
-
node
|
|
230
|
+
node,
|
|
223
231
|
);
|
|
224
232
|
node.account = new RawControlledAccount(
|
|
225
233
|
controlledAccount.core,
|
|
226
|
-
controlledAccount.agentSecret
|
|
234
|
+
controlledAccount.agentSecret,
|
|
227
235
|
);
|
|
228
236
|
}
|
|
229
237
|
|
|
@@ -247,14 +255,14 @@ export class LocalNode {
|
|
|
247
255
|
dontLoadFrom?: PeerID;
|
|
248
256
|
dontWaitFor?: PeerID;
|
|
249
257
|
onProgress?: (progress: number) => void;
|
|
250
|
-
} = {}
|
|
258
|
+
} = {},
|
|
251
259
|
): Promise<CoValueCore | "unavailable"> {
|
|
252
260
|
let entry = this.coValues[id];
|
|
253
261
|
if (!entry) {
|
|
254
262
|
const peersToWaitFor = new Set(
|
|
255
263
|
Object.values(this.syncManager.peers)
|
|
256
264
|
.filter((peer) => peer.role === "server")
|
|
257
|
-
.map((peer) => peer.id)
|
|
265
|
+
.map((peer) => peer.id),
|
|
258
266
|
);
|
|
259
267
|
if (options.dontWaitFor) peersToWaitFor.delete(options.dontWaitFor);
|
|
260
268
|
entry = newLoadingState(peersToWaitFor, options.onProgress);
|
|
@@ -268,7 +276,7 @@ export class LocalNode {
|
|
|
268
276
|
"Error loading from peers",
|
|
269
277
|
id,
|
|
270
278
|
|
|
271
|
-
e
|
|
279
|
+
e,
|
|
272
280
|
);
|
|
273
281
|
});
|
|
274
282
|
}
|
|
@@ -287,7 +295,7 @@ export class LocalNode {
|
|
|
287
295
|
*/
|
|
288
296
|
async load<T extends RawCoValue>(
|
|
289
297
|
id: CoID<T>,
|
|
290
|
-
onProgress?: (progress: number) => void
|
|
298
|
+
onProgress?: (progress: number) => void,
|
|
291
299
|
): Promise<T | "unavailable"> {
|
|
292
300
|
const core = await this.loadCoValueCore(id, { onProgress });
|
|
293
301
|
|
|
@@ -312,7 +320,7 @@ export class LocalNode {
|
|
|
312
320
|
/** @category 3. Low-level */
|
|
313
321
|
subscribe<T extends RawCoValue>(
|
|
314
322
|
id: CoID<T>,
|
|
315
|
-
callback: (update: T | "unavailable") => void
|
|
323
|
+
callback: (update: T | "unavailable") => void,
|
|
316
324
|
): () => void {
|
|
317
325
|
let stopped = false;
|
|
318
326
|
let unsubscribe!: () => void;
|
|
@@ -344,20 +352,20 @@ export class LocalNode {
|
|
|
344
352
|
/** @deprecated Use Account.acceptInvite instead */
|
|
345
353
|
async acceptInvite<T extends RawCoValue>(
|
|
346
354
|
groupOrOwnedValueID: CoID<T>,
|
|
347
|
-
inviteSecret: InviteSecret
|
|
355
|
+
inviteSecret: InviteSecret,
|
|
348
356
|
): Promise<void> {
|
|
349
357
|
const groupOrOwnedValue = await this.load(groupOrOwnedValueID);
|
|
350
358
|
|
|
351
359
|
if (groupOrOwnedValue === "unavailable") {
|
|
352
360
|
throw new Error(
|
|
353
|
-
"Trying to accept invite: Group/owned value unavailable from all peers"
|
|
361
|
+
"Trying to accept invite: Group/owned value unavailable from all peers",
|
|
354
362
|
);
|
|
355
363
|
}
|
|
356
364
|
|
|
357
365
|
if (groupOrOwnedValue.core.header.ruleset.type === "ownedByGroup") {
|
|
358
366
|
return this.acceptInvite(
|
|
359
367
|
groupOrOwnedValue.core.header.ruleset.group as CoID<RawGroup>,
|
|
360
|
-
inviteSecret
|
|
368
|
+
inviteSecret,
|
|
361
369
|
);
|
|
362
370
|
} else if (groupOrOwnedValue.core.header.ruleset.type !== "group") {
|
|
363
371
|
throw new Error("Can only accept invites to groups");
|
|
@@ -365,10 +373,10 @@ export class LocalNode {
|
|
|
365
373
|
|
|
366
374
|
const group = expectGroup(groupOrOwnedValue);
|
|
367
375
|
|
|
368
|
-
const inviteAgentSecret = agentSecretFromSecretSeed(
|
|
369
|
-
secretSeedFromInviteSecret(inviteSecret)
|
|
376
|
+
const inviteAgentSecret = this.crypto.agentSecretFromSecretSeed(
|
|
377
|
+
secretSeedFromInviteSecret(inviteSecret),
|
|
370
378
|
);
|
|
371
|
-
const inviteAgentID = getAgentID(inviteAgentSecret);
|
|
379
|
+
const inviteAgentID = this.crypto.getAgentID(inviteAgentSecret);
|
|
372
380
|
|
|
373
381
|
const inviteRole = await new Promise((resolve, reject) => {
|
|
374
382
|
group.subscribe((groupUpdate) => {
|
|
@@ -379,7 +387,7 @@ export class LocalNode {
|
|
|
379
387
|
});
|
|
380
388
|
setTimeout(
|
|
381
389
|
() => reject(new Error("Couldn't find invite before timeout")),
|
|
382
|
-
2000
|
|
390
|
+
2000,
|
|
383
391
|
);
|
|
384
392
|
});
|
|
385
393
|
|
|
@@ -396,7 +404,7 @@ export class LocalNode {
|
|
|
396
404
|
(existingRole === "reader" && inviteRole === "readerInvite")
|
|
397
405
|
) {
|
|
398
406
|
console.debug(
|
|
399
|
-
"Not accepting invite that would replace or downgrade role"
|
|
407
|
+
"Not accepting invite that would replace or downgrade role",
|
|
400
408
|
);
|
|
401
409
|
return;
|
|
402
410
|
}
|
|
@@ -404,10 +412,10 @@ export class LocalNode {
|
|
|
404
412
|
const groupAsInvite = expectGroup(
|
|
405
413
|
group.core
|
|
406
414
|
.testWithDifferentAccount(
|
|
407
|
-
new ControlledAgent(inviteAgentSecret),
|
|
408
|
-
newRandomSessionID(inviteAgentID)
|
|
415
|
+
new ControlledAgent(inviteAgentSecret, this.crypto),
|
|
416
|
+
newRandomSessionID(inviteAgentID),
|
|
409
417
|
)
|
|
410
|
-
.getCurrentContent()
|
|
418
|
+
.getCurrentContent(),
|
|
411
419
|
);
|
|
412
420
|
|
|
413
421
|
groupAsInvite.addMemberInternal(
|
|
@@ -415,8 +423,8 @@ export class LocalNode {
|
|
|
415
423
|
inviteRole === "adminInvite"
|
|
416
424
|
? "admin"
|
|
417
425
|
: inviteRole === "writerInvite"
|
|
418
|
-
|
|
419
|
-
|
|
426
|
+
? "writer"
|
|
427
|
+
: "reader",
|
|
420
428
|
);
|
|
421
429
|
|
|
422
430
|
group.core._sessionLogs = groupAsInvite.core.sessionLogs;
|
|
@@ -432,14 +440,14 @@ export class LocalNode {
|
|
|
432
440
|
const entry = this.coValues[id];
|
|
433
441
|
if (!entry) {
|
|
434
442
|
throw new Error(
|
|
435
|
-
`${expectation ? expectation + ": " : ""}Unknown CoValue ${id}
|
|
443
|
+
`${expectation ? expectation + ": " : ""}Unknown CoValue ${id}`,
|
|
436
444
|
);
|
|
437
445
|
}
|
|
438
446
|
if (entry.state === "loading") {
|
|
439
447
|
throw new Error(
|
|
440
448
|
`${
|
|
441
449
|
expectation ? expectation + ": " : ""
|
|
442
|
-
}CoValue ${id} not yet loaded
|
|
450
|
+
}CoValue ${id} not yet loaded`,
|
|
443
451
|
);
|
|
444
452
|
}
|
|
445
453
|
return entry.coValue;
|
|
@@ -449,44 +457,45 @@ export class LocalNode {
|
|
|
449
457
|
expectProfileLoaded(id: AccountID, expectation?: string): RawProfile {
|
|
450
458
|
const account = this.expectCoValueLoaded(id, expectation);
|
|
451
459
|
const profileID = expectGroup(account.getCurrentContent()).get(
|
|
452
|
-
"profile"
|
|
460
|
+
"profile",
|
|
453
461
|
);
|
|
454
462
|
if (!profileID) {
|
|
455
463
|
throw new Error(
|
|
456
464
|
`${
|
|
457
465
|
expectation ? expectation + ": " : ""
|
|
458
|
-
}Account ${id} has no profile
|
|
466
|
+
}Account ${id} has no profile`,
|
|
459
467
|
);
|
|
460
468
|
}
|
|
461
469
|
return this.expectCoValueLoaded(
|
|
462
470
|
profileID,
|
|
463
|
-
expectation
|
|
471
|
+
expectation,
|
|
464
472
|
).getCurrentContent() as RawProfile;
|
|
465
473
|
}
|
|
466
474
|
|
|
467
475
|
/** @internal */
|
|
468
476
|
createAccount(
|
|
469
|
-
|
|
470
|
-
agentSecret = newRandomAgentSecret()
|
|
477
|
+
agentSecret = this.crypto.newRandomAgentSecret(),
|
|
471
478
|
): RawControlledAccount {
|
|
472
|
-
const accountAgentID = getAgentID(agentSecret);
|
|
473
|
-
|
|
474
|
-
this.createCoValue(
|
|
479
|
+
const accountAgentID = this.crypto.getAgentID(agentSecret);
|
|
480
|
+
const account = expectGroup(
|
|
481
|
+
this.createCoValue(
|
|
482
|
+
accountHeaderForInitialAgentSecret(agentSecret, this.crypto),
|
|
483
|
+
)
|
|
475
484
|
.testWithDifferentAccount(
|
|
476
|
-
new ControlledAgent(agentSecret),
|
|
477
|
-
newRandomSessionID(accountAgentID)
|
|
485
|
+
new ControlledAgent(agentSecret, this.crypto),
|
|
486
|
+
newRandomSessionID(accountAgentID),
|
|
478
487
|
)
|
|
479
|
-
.getCurrentContent()
|
|
488
|
+
.getCurrentContent(),
|
|
480
489
|
);
|
|
481
490
|
|
|
482
491
|
account.set(accountAgentID, "admin", "trusting");
|
|
483
492
|
|
|
484
|
-
const readKey = newRandomKeySecret();
|
|
493
|
+
const readKey = this.crypto.newRandomKeySecret();
|
|
485
494
|
|
|
486
|
-
const sealed = seal({
|
|
495
|
+
const sealed = this.crypto.seal({
|
|
487
496
|
message: readKey.secret,
|
|
488
|
-
from: getAgentSealerSecret(agentSecret),
|
|
489
|
-
to: getAgentSealerID(accountAgentID),
|
|
497
|
+
from: this.crypto.getAgentSealerSecret(agentSecret),
|
|
498
|
+
to: this.crypto.getAgentSealerID(accountAgentID),
|
|
490
499
|
nOnceMaterial: {
|
|
491
500
|
in: account.id,
|
|
492
501
|
tx: account.core.nextTransactionID(),
|
|
@@ -497,34 +506,19 @@ export class LocalNode {
|
|
|
497
506
|
|
|
498
507
|
account.set("readKey", readKey.id, "trusting");
|
|
499
508
|
|
|
500
|
-
const profile = account.createMap<RawProfile>(
|
|
501
|
-
{ name },
|
|
502
|
-
{
|
|
503
|
-
type: "profile",
|
|
504
|
-
},
|
|
505
|
-
"trusting"
|
|
506
|
-
);
|
|
507
|
-
|
|
508
|
-
account.set("profile", profile.id, "trusting");
|
|
509
|
-
|
|
510
509
|
const accountOnThisNode = this.expectCoValueLoaded(account.id);
|
|
511
510
|
|
|
512
511
|
accountOnThisNode._sessionLogs = new Map(account.core.sessionLogs);
|
|
513
512
|
|
|
514
513
|
accountOnThisNode._cachedContent = undefined;
|
|
515
514
|
|
|
516
|
-
const profileOnThisNode = this.createCoValue(profile.core.header);
|
|
517
|
-
|
|
518
|
-
profileOnThisNode._sessionLogs = new Map(profile.core.sessionLogs);
|
|
519
|
-
profileOnThisNode._cachedContent = undefined;
|
|
520
|
-
|
|
521
515
|
return new RawControlledAccount(accountOnThisNode, agentSecret);
|
|
522
516
|
}
|
|
523
517
|
|
|
524
518
|
/** @internal */
|
|
525
519
|
resolveAccountAgent(
|
|
526
520
|
id: AccountID | AgentID,
|
|
527
|
-
expectation?: string
|
|
521
|
+
expectation?: string,
|
|
528
522
|
): AgentID {
|
|
529
523
|
if (isAgentID(id)) {
|
|
530
524
|
return id;
|
|
@@ -542,16 +536,16 @@ export class LocalNode {
|
|
|
542
536
|
throw new Error(
|
|
543
537
|
`${
|
|
544
538
|
expectation ? expectation + ": " : ""
|
|
545
|
-
}CoValue ${id} is not an account
|
|
539
|
+
}CoValue ${id} is not an account`,
|
|
546
540
|
);
|
|
547
541
|
}
|
|
548
542
|
|
|
549
|
-
return
|
|
543
|
+
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
|
|
550
544
|
}
|
|
551
545
|
|
|
552
546
|
async resolveAccountAgentAsync(
|
|
553
547
|
id: AccountID | AgentID,
|
|
554
|
-
expectation?: string
|
|
548
|
+
expectation?: string,
|
|
555
549
|
): Promise<AgentID> {
|
|
556
550
|
if (isAgentID(id)) {
|
|
557
551
|
return id;
|
|
@@ -563,7 +557,7 @@ export class LocalNode {
|
|
|
563
557
|
throw new Error(
|
|
564
558
|
`${
|
|
565
559
|
expectation ? expectation + ": " : ""
|
|
566
|
-
}Account ${id} is unavailable from all peers
|
|
560
|
+
}Account ${id} is unavailable from all peers`,
|
|
567
561
|
);
|
|
568
562
|
}
|
|
569
563
|
|
|
@@ -577,11 +571,11 @@ export class LocalNode {
|
|
|
577
571
|
throw new Error(
|
|
578
572
|
`${
|
|
579
573
|
expectation ? expectation + ": " : ""
|
|
580
|
-
}CoValue ${id} is not an account
|
|
574
|
+
}CoValue ${id} is not an account`,
|
|
581
575
|
);
|
|
582
576
|
}
|
|
583
577
|
|
|
584
|
-
return
|
|
578
|
+
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
|
|
585
579
|
}
|
|
586
580
|
|
|
587
581
|
/**
|
|
@@ -592,18 +586,18 @@ export class LocalNode {
|
|
|
592
586
|
type: "comap",
|
|
593
587
|
ruleset: { type: "group", initialAdmin: this.account.id },
|
|
594
588
|
meta: null,
|
|
595
|
-
...createdNowUnique(),
|
|
589
|
+
...this.crypto.createdNowUnique(),
|
|
596
590
|
});
|
|
597
591
|
|
|
598
|
-
|
|
592
|
+
const group = expectGroup(groupCoValue.getCurrentContent());
|
|
599
593
|
|
|
600
594
|
group.set(this.account.id, "admin", "trusting");
|
|
601
595
|
|
|
602
|
-
const readKey = newRandomKeySecret();
|
|
596
|
+
const readKey = this.crypto.newRandomKeySecret();
|
|
603
597
|
|
|
604
598
|
group.set(
|
|
605
599
|
`${readKey.id}_for_${this.account.id}`,
|
|
606
|
-
seal({
|
|
600
|
+
this.crypto.seal({
|
|
607
601
|
message: readKey.secret,
|
|
608
602
|
from: this.account.currentSealerSecret(),
|
|
609
603
|
to: this.account.currentSealerID(),
|
|
@@ -612,7 +606,7 @@ export class LocalNode {
|
|
|
612
606
|
tx: groupCoValue.nextTransactionID(),
|
|
613
607
|
},
|
|
614
608
|
}),
|
|
615
|
-
"trusting"
|
|
609
|
+
"trusting",
|
|
616
610
|
);
|
|
617
611
|
|
|
618
612
|
group.set("readKey", readKey.id, "trusting");
|
|
@@ -623,9 +617,9 @@ export class LocalNode {
|
|
|
623
617
|
/** @internal */
|
|
624
618
|
testWithDifferentAccount(
|
|
625
619
|
account: ControlledAccountOrAgent,
|
|
626
|
-
currentSessionID: SessionID
|
|
620
|
+
currentSessionID: SessionID,
|
|
627
621
|
): LocalNode {
|
|
628
|
-
const newNode = new LocalNode(account, currentSessionID);
|
|
622
|
+
const newNode = new LocalNode(account, currentSessionID, this.crypto);
|
|
629
623
|
|
|
630
624
|
const coValuesToCopy = Object.entries(this.coValues);
|
|
631
625
|
|
|
@@ -650,7 +644,7 @@ export class LocalNode {
|
|
|
650
644
|
const newCoValue = new CoValueCore(
|
|
651
645
|
entry.coValue.header,
|
|
652
646
|
newNode,
|
|
653
|
-
new Map(entry.coValue.sessionLogs)
|
|
647
|
+
new Map(entry.coValue.sessionLogs),
|
|
654
648
|
);
|
|
655
649
|
|
|
656
650
|
newNode.coValues[coValueID as RawCoID] = {
|
|
@@ -666,7 +660,7 @@ export class LocalNode {
|
|
|
666
660
|
// To make sure that when we edit the account, we're modifying the correct sessions
|
|
667
661
|
const accountInNode = new RawControlledAccount(
|
|
668
662
|
newNode.expectCoValueLoaded(account.id),
|
|
669
|
-
account.agentSecret
|
|
663
|
+
account.agentSecret,
|
|
670
664
|
);
|
|
671
665
|
if (accountInNode.core.node !== newNode) {
|
|
672
666
|
throw new Error("Account's node is not the new node");
|
|
@@ -705,7 +699,7 @@ type CoValueState =
|
|
|
705
699
|
/** @internal */
|
|
706
700
|
export function newLoadingState(
|
|
707
701
|
currentPeerIds: Set<PeerID>,
|
|
708
|
-
onProgress?: (progress: number) => void
|
|
702
|
+
onProgress?: (progress: number) => void,
|
|
709
703
|
): CoValueState {
|
|
710
704
|
let resolve: (coValue: CoValueCore | "unavailable") => void;
|
|
711
705
|
|
|
@@ -725,7 +719,7 @@ export function newLoadingState(
|
|
|
725
719
|
resolve = r;
|
|
726
720
|
});
|
|
727
721
|
return [id, { type: "waiting", done, resolve: resolve! }];
|
|
728
|
-
})
|
|
722
|
+
}),
|
|
729
723
|
),
|
|
730
724
|
};
|
|
731
725
|
}
|
package/src/media.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RawCoMap } from
|
|
2
|
-
import { RawBinaryCoStream } from
|
|
1
|
+
import { RawCoMap } from "./coValues/coMap.js";
|
|
2
|
+
import { RawBinaryCoStream } from "./coValues/coStream.js";
|
|
3
3
|
|
|
4
4
|
export type ImageDefinition = RawCoMap<{
|
|
5
5
|
originalSize: [number, number];
|
|
6
6
|
placeholderDataURL?: string;
|
|
7
7
|
[res: `${number}x${number}`]: RawBinaryCoStream["id"];
|
|
8
|
-
}>;
|
|
8
|
+
}>;
|
package/src/permissions.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CoID } from "./coValue.js";
|
|
2
2
|
import { MapOpPayload } from "./coValues/coMap.js";
|
|
3
3
|
import { JsonValue } from "./jsonValue.js";
|
|
4
|
-
import { KeyID } from "./crypto.js";
|
|
4
|
+
import { KeyID } from "./crypto/crypto.js";
|
|
5
5
|
import { CoValueCore, Transaction } from "./coValueCore.js";
|
|
6
6
|
import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
|
|
7
7
|
import { AgentID, RawCoID, SessionID, TransactionID } from "./ids.js";
|
|
@@ -25,7 +25,7 @@ export type Role =
|
|
|
25
25
|
| "readerInvite";
|
|
26
26
|
|
|
27
27
|
export function determineValidTransactions(
|
|
28
|
-
coValue: CoValueCore
|
|
28
|
+
coValue: CoValueCore,
|
|
29
29
|
): { txID: TransactionID; tx: Transaction }[] {
|
|
30
30
|
if (coValue.header.ruleset.type === "group") {
|
|
31
31
|
const allTransactionsSorted = [
|
|
@@ -73,7 +73,7 @@ export function determineValidTransactions(
|
|
|
73
73
|
continue;
|
|
74
74
|
} else {
|
|
75
75
|
console.warn(
|
|
76
|
-
"Only admins can make private transactions in groups"
|
|
76
|
+
"Only admins can make private transactions in groups",
|
|
77
77
|
);
|
|
78
78
|
continue;
|
|
79
79
|
}
|
|
@@ -92,8 +92,8 @@ export function determineValidTransactions(
|
|
|
92
92
|
JSON.stringify(tx.changes, (k, v) =>
|
|
93
93
|
k === "changes" || k === "encryptedChanges"
|
|
94
94
|
? v.slice(0, 20) + "..."
|
|
95
|
-
: v
|
|
96
|
-
)
|
|
95
|
+
: v,
|
|
96
|
+
),
|
|
97
97
|
);
|
|
98
98
|
continue;
|
|
99
99
|
}
|
|
@@ -173,7 +173,7 @@ export function determineValidTransactions(
|
|
|
173
173
|
)
|
|
174
174
|
) {
|
|
175
175
|
console.warn(
|
|
176
|
-
"Everyone can only be set to reader, writer or revoked"
|
|
176
|
+
"Everyone can only be set to reader, writer or revoked",
|
|
177
177
|
);
|
|
178
178
|
continue;
|
|
179
179
|
}
|
|
@@ -212,7 +212,7 @@ export function determineValidTransactions(
|
|
|
212
212
|
}
|
|
213
213
|
} else {
|
|
214
214
|
console.warn(
|
|
215
|
-
"Group transaction must be made by current admin or invite"
|
|
215
|
+
"Group transaction must be made by current admin or invite",
|
|
216
216
|
);
|
|
217
217
|
continue;
|
|
218
218
|
}
|
|
@@ -230,9 +230,9 @@ export function determineValidTransactions(
|
|
|
230
230
|
coValue.node
|
|
231
231
|
.expectCoValueLoaded(
|
|
232
232
|
coValue.header.ruleset.group,
|
|
233
|
-
"Determining valid transaction in owned object but its group wasn't loaded"
|
|
233
|
+
"Determining valid transaction in owned object but its group wasn't loaded",
|
|
234
234
|
)
|
|
235
|
-
.getCurrentContent()
|
|
235
|
+
.getCurrentContent(),
|
|
236
236
|
);
|
|
237
237
|
|
|
238
238
|
if (groupContent.type !== "comap") {
|
|
@@ -264,7 +264,7 @@ export function determineValidTransactions(
|
|
|
264
264
|
txID: { sessionID: sessionID, txIndex },
|
|
265
265
|
tx,
|
|
266
266
|
}));
|
|
267
|
-
}
|
|
267
|
+
},
|
|
268
268
|
);
|
|
269
269
|
} else if (coValue.header.ruleset.type === "unsafeAllowAll") {
|
|
270
270
|
return [...coValue.sessionLogs.entries()].flatMap(
|
|
@@ -273,28 +273,26 @@ export function determineValidTransactions(
|
|
|
273
273
|
txID: { sessionID: sessionID, txIndex },
|
|
274
274
|
tx,
|
|
275
275
|
}));
|
|
276
|
-
}
|
|
276
|
+
},
|
|
277
277
|
);
|
|
278
278
|
} else {
|
|
279
279
|
throw new Error(
|
|
280
280
|
"Unknown ruleset type " +
|
|
281
|
-
(coValue.header.ruleset as { type: string }).type
|
|
281
|
+
(coValue.header.ruleset as { type: string }).type,
|
|
282
282
|
);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
export function isKeyForKeyField(
|
|
287
|
-
|
|
288
|
-
): val is `${KeyID}_for_${KeyID}` {
|
|
289
|
-
return val.startsWith("key_") && val.includes("_for_key");
|
|
286
|
+
export function isKeyForKeyField(co: string): co is `${KeyID}_for_${KeyID}` {
|
|
287
|
+
return co.startsWith("key_") && co.includes("_for_key");
|
|
290
288
|
}
|
|
291
289
|
|
|
292
290
|
export function isKeyForAccountField(
|
|
293
|
-
|
|
294
|
-
):
|
|
291
|
+
co: string,
|
|
292
|
+
): co is `${KeyID}_for_${AccountID | AgentID}` {
|
|
295
293
|
return (
|
|
296
|
-
(
|
|
297
|
-
(
|
|
298
|
-
|
|
294
|
+
(co.startsWith("key_") &&
|
|
295
|
+
(co.includes("_for_sealer") || co.includes("_for_co"))) ||
|
|
296
|
+
co.includes("_for_everyone")
|
|
299
297
|
);
|
|
300
298
|
}
|