cojson 0.0.23 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/coValue.ts CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  determineValidTransactions,
28
28
  isKeyForKeyField,
29
29
  } from "./permissions.js";
30
- import { Team, expectTeamContent } from "./team.js";
30
+ import { Group, expectGroupContent } from "./group.js";
31
31
  import { LocalNode } from "./node.js";
32
32
  import { CoValueKnownState, NewContentMessage } from "./sync.js";
33
33
  import { RawCoID, SessionID, TransactionID } from "./ids.js";
@@ -106,10 +106,10 @@ export class CoValue {
106
106
  this._sessions = internalInitSessions;
107
107
  this.node = node;
108
108
 
109
- if (header.ruleset.type == "ownedByTeam") {
109
+ if (header.ruleset.type == "ownedByGroup") {
110
110
  this.node
111
- .expectCoValueLoaded(header.ruleset.team)
112
- .subscribe((_teamUpdate) => {
111
+ .expectCoValueLoaded(header.ruleset.group)
112
+ .subscribe((_groupUpdate) => {
113
113
  this._cachedContent = undefined;
114
114
  const newContent = this.getCurrentContent();
115
115
  for (const listener of this.listeners) {
@@ -385,8 +385,8 @@ export class CoValue {
385
385
  }
386
386
 
387
387
  getCurrentReadKey(): { secret: KeySecret | undefined; id: KeyID } {
388
- if (this.header.ruleset.type === "team") {
389
- const content = expectTeamContent(this.getCurrentContent());
388
+ if (this.header.ruleset.type === "group") {
389
+ const content = expectGroupContent(this.getCurrentContent());
390
390
 
391
391
  const currentKeyId = content.get("readKey");
392
392
 
@@ -400,20 +400,20 @@ export class CoValue {
400
400
  secret: secret,
401
401
  id: currentKeyId,
402
402
  };
403
- } else if (this.header.ruleset.type === "ownedByTeam") {
403
+ } else if (this.header.ruleset.type === "ownedByGroup") {
404
404
  return this.node
405
- .expectCoValueLoaded(this.header.ruleset.team)
405
+ .expectCoValueLoaded(this.header.ruleset.group)
406
406
  .getCurrentReadKey();
407
407
  } else {
408
408
  throw new Error(
409
- "Only teams or values owned by teams have read secrets"
409
+ "Only groups or values owned by groups have read secrets"
410
410
  );
411
411
  }
412
412
  }
413
413
 
414
414
  getReadKey(keyID: KeyID): KeySecret | undefined {
415
- if (this.header.ruleset.type === "team") {
416
- const content = expectTeamContent(this.getCurrentContent());
415
+ if (this.header.ruleset.type === "group") {
416
+ const content = expectGroupContent(this.getCurrentContent());
417
417
 
418
418
  // Try to find key revelation for us
419
419
 
@@ -477,26 +477,26 @@ export class CoValue {
477
477
  }
478
478
 
479
479
  return undefined;
480
- } else if (this.header.ruleset.type === "ownedByTeam") {
480
+ } else if (this.header.ruleset.type === "ownedByGroup") {
481
481
  return this.node
482
- .expectCoValueLoaded(this.header.ruleset.team)
482
+ .expectCoValueLoaded(this.header.ruleset.group)
483
483
  .getReadKey(keyID);
484
484
  } else {
485
485
  throw new Error(
486
- "Only teams or values owned by teams have read secrets"
486
+ "Only groups or values owned by groups have read secrets"
487
487
  );
488
488
  }
489
489
  }
490
490
 
491
- getTeam(): Team {
492
- if (this.header.ruleset.type !== "ownedByTeam") {
493
- throw new Error("Only values owned by teams have teams");
491
+ getGroup(): Group {
492
+ if (this.header.ruleset.type !== "ownedByGroup") {
493
+ throw new Error("Only values owned by groups have groups");
494
494
  }
495
495
 
496
- return new Team(
497
- expectTeamContent(
496
+ return new Group(
497
+ expectGroupContent(
498
498
  this.node
499
- .expectCoValueLoaded(this.header.ruleset.team)
499
+ .expectCoValueLoaded(this.header.ruleset.group)
500
500
  .getCurrentContent()
501
501
  ),
502
502
  this.node
@@ -553,12 +553,12 @@ export class CoValue {
553
553
  }
554
554
 
555
555
  getDependedOnCoValues(): RawCoID[] {
556
- return this.header.ruleset.type === "team"
557
- ? expectTeamContent(this.getCurrentContent())
556
+ return this.header.ruleset.type === "group"
557
+ ? expectGroupContent(this.getCurrentContent())
558
558
  .keys()
559
559
  .filter((k): k is AccountID => k.startsWith("co_"))
560
- : this.header.ruleset.type === "ownedByTeam"
561
- ? [this.header.ruleset.team]
560
+ : this.header.ruleset.type === "ownedByGroup"
561
+ ? [this.header.ruleset.group]
562
562
  : [];
563
563
  }
564
564
  }
@@ -25,7 +25,7 @@ import {
25
25
  import { Role } from "./permissions.js";
26
26
  import { base58 } from "@scure/base";
27
27
 
28
- export type TeamContent = {
28
+ export type GroupContent = {
29
29
  profile: CoID<Profile> | null;
30
30
  [key: AccountIDOrAgentID]: Role;
31
31
  readKey: KeyID;
@@ -36,34 +36,34 @@ export type TeamContent = {
36
36
  >;
37
37
  };
38
38
 
39
- export function expectTeamContent(
39
+ export function expectGroupContent(
40
40
  content: ContentType
41
- ): CoMap<TeamContent, JsonObject | null> {
41
+ ): CoMap<GroupContent, JsonObject | null> {
42
42
  if (content.type !== "comap") {
43
43
  throw new Error("Expected map");
44
44
  }
45
45
 
46
- return content as CoMap<TeamContent, JsonObject | null>;
46
+ return content as CoMap<GroupContent, JsonObject | null>;
47
47
  }
48
48
 
49
- export class Team {
50
- teamMap: CoMap<TeamContent, JsonObject | null>;
49
+ export class Group {
50
+ groupMap: CoMap<GroupContent, JsonObject | null>;
51
51
  node: LocalNode;
52
52
 
53
53
  constructor(
54
- teamMap: CoMap<TeamContent, JsonObject | null>,
54
+ groupMap: CoMap<GroupContent, JsonObject | null>,
55
55
  node: LocalNode
56
56
  ) {
57
- this.teamMap = teamMap;
57
+ this.groupMap = groupMap;
58
58
  this.node = node;
59
59
  }
60
60
 
61
- get id(): CoID<CoMap<TeamContent, JsonObject | null>> {
62
- return this.teamMap.id;
61
+ get id(): CoID<CoMap<GroupContent, JsonObject | null>> {
62
+ return this.groupMap.id;
63
63
  }
64
64
 
65
65
  roleOf(accountID: AccountIDOrAgentID): Role | undefined {
66
- return this.teamMap.get(accountID);
66
+ return this.groupMap.get(accountID);
67
67
  }
68
68
 
69
69
  myRole(): Role | undefined {
@@ -71,8 +71,8 @@ export class Team {
71
71
  }
72
72
 
73
73
  addMember(accountID: AccountIDOrAgentID, role: Role) {
74
- this.teamMap = this.teamMap.edit((map) => {
75
- const currentReadKey = this.teamMap.coValue.getCurrentReadKey();
74
+ this.groupMap = this.groupMap.edit((map) => {
75
+ const currentReadKey = this.groupMap.coValue.getCurrentReadKey();
76
76
 
77
77
  if (!currentReadKey.secret) {
78
78
  throw new Error("Can't add member without read key secret");
@@ -80,7 +80,7 @@ export class Team {
80
80
 
81
81
  const agent = this.node.resolveAccountAgent(
82
82
  accountID,
83
- "Expected to know agent to add them to team"
83
+ "Expected to know agent to add them to group"
84
84
  );
85
85
 
86
86
  map.set(accountID, role, "trusting");
@@ -93,11 +93,11 @@ export class Team {
93
93
  `${currentReadKey.id}_for_${accountID}`,
94
94
  seal(
95
95
  currentReadKey.secret,
96
- this.teamMap.coValue.node.account.currentSealerSecret(),
96
+ this.groupMap.coValue.node.account.currentSealerSecret(),
97
97
  getAgentSealerID(agent),
98
98
  {
99
- in: this.teamMap.coValue.id,
100
- tx: this.teamMap.coValue.nextTransactionID(),
99
+ in: this.groupMap.coValue.id,
100
+ tx: this.groupMap.coValue.nextTransactionID(),
101
101
  }
102
102
  ),
103
103
  "trusting"
@@ -117,9 +117,9 @@ export class Team {
117
117
  }
118
118
 
119
119
  rotateReadKey() {
120
- const currentlyPermittedReaders = this.teamMap.keys().filter((key) => {
120
+ const currentlyPermittedReaders = this.groupMap.keys().filter((key) => {
121
121
  if (key.startsWith("co_") || isAgentID(key)) {
122
- const role = this.teamMap.get(key);
122
+ const role = this.groupMap.get(key);
123
123
  return (
124
124
  role === "admin" || role === "writer" || role === "reader"
125
125
  );
@@ -128,7 +128,7 @@ export class Team {
128
128
  }
129
129
  }) as AccountIDOrAgentID[];
130
130
 
131
- const maybeCurrentReadKey = this.teamMap.coValue.getCurrentReadKey();
131
+ const maybeCurrentReadKey = this.groupMap.coValue.getCurrentReadKey();
132
132
 
133
133
  if (!maybeCurrentReadKey.secret) {
134
134
  throw new Error(
@@ -143,7 +143,7 @@ export class Team {
143
143
 
144
144
  const newReadKey = newRandomKeySecret();
145
145
 
146
- this.teamMap = this.teamMap.edit((map) => {
146
+ this.groupMap = this.groupMap.edit((map) => {
147
147
  for (const readerID of currentlyPermittedReaders) {
148
148
  const reader = this.node.resolveAccountAgent(
149
149
  readerID,
@@ -154,11 +154,11 @@ export class Team {
154
154
  `${newReadKey.id}_for_${readerID}`,
155
155
  seal(
156
156
  newReadKey.secret,
157
- this.teamMap.coValue.node.account.currentSealerSecret(),
157
+ this.groupMap.coValue.node.account.currentSealerSecret(),
158
158
  getAgentSealerID(reader),
159
159
  {
160
- in: this.teamMap.coValue.id,
161
- tx: this.teamMap.coValue.nextTransactionID(),
160
+ in: this.groupMap.coValue.id,
161
+ tx: this.groupMap.coValue.nextTransactionID(),
162
162
  }
163
163
  ),
164
164
  "trusting"
@@ -179,7 +179,7 @@ export class Team {
179
179
  }
180
180
 
181
181
  removeMember(accountID: AccountIDOrAgentID) {
182
- this.teamMap = this.teamMap.edit((map) => {
182
+ this.groupMap = this.groupMap.edit((map) => {
183
183
  map.set(accountID, "revoked", "trusting");
184
184
  });
185
185
 
@@ -194,8 +194,8 @@ export class Team {
194
194
  .createCoValue({
195
195
  type: "comap",
196
196
  ruleset: {
197
- type: "ownedByTeam",
198
- team: this.teamMap.id,
197
+ type: "ownedByGroup",
198
+ group: this.groupMap.id,
199
199
  },
200
200
  meta: meta || null,
201
201
  ...createdNowUnique(),
@@ -206,10 +206,10 @@ export class Team {
206
206
  testWithDifferentAccount(
207
207
  account: GeneralizedControlledAccount,
208
208
  sessionId: SessionID
209
- ): Team {
210
- return new Team(
211
- expectTeamContent(
212
- this.teamMap.coValue
209
+ ): Group {
210
+ return new Group(
211
+ expectGroupContent(
212
+ this.groupMap.coValue
213
213
  .testWithDifferentAccount(account, sessionId)
214
214
  .getCurrentContent()
215
215
  ),
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  import { connectedPeers } from "./streamUtils.js";
15
15
  import { AnonymousControlledAccount, ControlledAccount } from "./account.js";
16
16
  import { rawCoIDtoBytes, rawCoIDfromBytes } from "./ids.js";
17
- import { Team, expectTeamContent } from "./team.js"
17
+ import { Group, expectGroupContent } from "./group.js"
18
18
 
19
19
  import type { SessionID, AgentID } from "./ids.js";
20
20
  import type { CoID, ContentType } from "./contentType.js";
@@ -27,7 +27,7 @@ import type {
27
27
  ProfileContent,
28
28
  Profile,
29
29
  } from "./account.js";
30
- import type { InviteSecret } from "./team.js";
30
+ import type { InviteSecret } from "./group.js";
31
31
 
32
32
  type Value = JsonValue | ContentType;
33
33
 
@@ -44,7 +44,7 @@ export const cojsonInternals = {
44
44
  agentSecretFromSecretSeed,
45
45
  secretSeedLength,
46
46
  shortHashLength,
47
- expectTeamContent
47
+ expectGroupContent
48
48
  };
49
49
 
50
50
  export {
@@ -53,7 +53,7 @@ export {
53
53
  CoMap,
54
54
  AnonymousControlledAccount,
55
55
  ControlledAccount,
56
- Team
56
+ Group
57
57
  };
58
58
 
59
59
  export type {
package/src/node.ts CHANGED
@@ -12,11 +12,11 @@ import {
12
12
  import { CoValue, CoValueHeader, newRandomSessionID } from "./coValue.js";
13
13
  import {
14
14
  InviteSecret,
15
- Team,
16
- TeamContent,
17
- expectTeamContent,
15
+ Group,
16
+ GroupContent,
17
+ expectGroupContent,
18
18
  secretSeedFromInviteSecret,
19
- } from "./team.js";
19
+ } from "./group.js";
20
20
  import { Peer, SyncManager } from "./sync.js";
21
21
  import { AgentID, RawCoID, SessionID, isAgentID } from "./ids.js";
22
22
  import { CoID, ContentType } from "./contentType.js";
@@ -151,23 +151,23 @@ export class LocalNode {
151
151
  }
152
152
 
153
153
  async acceptInvite<T extends ContentType>(
154
- teamOrOwnedValueID: CoID<T>,
154
+ groupOrOwnedValueID: CoID<T>,
155
155
  inviteSecret: InviteSecret
156
156
  ): Promise<void> {
157
- const teamOrOwnedValue = await this.load(teamOrOwnedValueID);
157
+ const groupOrOwnedValue = await this.load(groupOrOwnedValueID);
158
158
 
159
- if (teamOrOwnedValue.coValue.header.ruleset.type === "ownedByTeam") {
159
+ if (groupOrOwnedValue.coValue.header.ruleset.type === "ownedByGroup") {
160
160
  return this.acceptInvite(
161
- teamOrOwnedValue.coValue.header.ruleset.team as CoID<
162
- CoMap<TeamContent>
161
+ groupOrOwnedValue.coValue.header.ruleset.group as CoID<
162
+ CoMap<GroupContent>
163
163
  >,
164
164
  inviteSecret
165
165
  );
166
- } else if (teamOrOwnedValue.coValue.header.ruleset.type !== "team") {
167
- throw new Error("Can only accept invites to teams");
166
+ } else if (groupOrOwnedValue.coValue.header.ruleset.type !== "group") {
167
+ throw new Error("Can only accept invites to groups");
168
168
  }
169
169
 
170
- const team = new Team(expectTeamContent(teamOrOwnedValue), this);
170
+ const group = new Group(expectGroupContent(groupOrOwnedValue), this);
171
171
 
172
172
  const inviteAgentSecret = agentSecretFromSecretSeed(
173
173
  secretSeedFromInviteSecret(inviteSecret)
@@ -175,8 +175,8 @@ export class LocalNode {
175
175
  const inviteAgentID = getAgentID(inviteAgentSecret);
176
176
 
177
177
  const invitationRole = await new Promise((resolve, reject) => {
178
- team.teamMap.subscribe((teamMap) => {
179
- const role = teamMap.get(inviteAgentID);
178
+ group.groupMap.subscribe((groupMap) => {
179
+ const role = groupMap.get(inviteAgentID);
180
180
  if (role) {
181
181
  resolve(role);
182
182
  }
@@ -194,7 +194,7 @@ export class LocalNode {
194
194
  throw new Error("No invitation found");
195
195
  }
196
196
 
197
- const existingRole = team.teamMap.get(this.account.id);
197
+ const existingRole = group.groupMap.get(this.account.id);
198
198
 
199
199
  if (
200
200
  existingRole === "admin" ||
@@ -204,12 +204,12 @@ export class LocalNode {
204
204
  return;
205
205
  }
206
206
 
207
- const teamAsInvite = team.testWithDifferentAccount(
207
+ const groupAsInvite = group.testWithDifferentAccount(
208
208
  new AnonymousControlledAccount(inviteAgentSecret),
209
209
  newRandomSessionID(inviteAgentID)
210
210
  );
211
211
 
212
- teamAsInvite.addMember(
212
+ groupAsInvite.addMember(
213
213
  this.account.id,
214
214
  invitationRole === "adminInvite"
215
215
  ? "admin"
@@ -218,8 +218,12 @@ export class LocalNode {
218
218
  : "reader"
219
219
  );
220
220
 
221
- team.teamMap.coValue._sessions = teamAsInvite.teamMap.coValue.sessions;
222
- team.teamMap.coValue._cachedContent = undefined;
221
+ group.groupMap.coValue._sessions = groupAsInvite.groupMap.coValue.sessions;
222
+ group.groupMap.coValue._cachedContent = undefined;
223
+
224
+ for (const groupListener of group.groupMap.coValue.listeners) {
225
+ groupListener(group.groupMap.coValue.getCurrentContent());
226
+ }
223
227
  }
224
228
 
225
229
  expectCoValueLoaded(id: RawCoID, expectation?: string): CoValue {
@@ -241,7 +245,7 @@ export class LocalNode {
241
245
 
242
246
  expectProfileLoaded(id: AccountID, expectation?: string): Profile {
243
247
  const account = this.expectCoValueLoaded(id, expectation);
244
- const profileID = expectTeamContent(account.getCurrentContent()).get(
248
+ const profileID = expectGroupContent(account.getCurrentContent()).get(
245
249
  "profile"
246
250
  );
247
251
  if (!profileID) {
@@ -268,12 +272,12 @@ export class LocalNode {
268
272
  newRandomSessionID(getAgentID(agentSecret))
269
273
  );
270
274
 
271
- const accountAsTeam = new Team(
272
- expectTeamContent(account.getCurrentContent()),
275
+ const accountAsGroup = new Group(
276
+ expectGroupContent(account.getCurrentContent()),
273
277
  account.node
274
278
  );
275
279
 
276
- accountAsTeam.teamMap.edit((editable) => {
280
+ accountAsGroup.groupMap.edit((editable) => {
277
281
  editable.set(getAgentID(agentSecret), "admin", "trusting");
278
282
 
279
283
  const readKey = newRandomKeySecret();
@@ -301,7 +305,7 @@ export class LocalNode {
301
305
  account.node
302
306
  );
303
307
 
304
- const profile = accountAsTeam.createMap<ProfileContent, ProfileMeta>({
308
+ const profile = accountAsGroup.createMap<ProfileContent, ProfileMeta>({
305
309
  type: "profile",
306
310
  });
307
311
 
@@ -309,13 +313,13 @@ export class LocalNode {
309
313
  editable.set("name", name, "trusting");
310
314
  });
311
315
 
312
- accountAsTeam.teamMap.edit((editable) => {
316
+ accountAsGroup.groupMap.edit((editable) => {
313
317
  editable.set("profile", profile.id, "trusting");
314
318
  });
315
319
 
316
320
  const accountOnThisNode = this.expectCoValueLoaded(account.id);
317
321
 
318
- accountOnThisNode._sessions = {...accountAsTeam.teamMap.coValue.sessions};
322
+ accountOnThisNode._sessions = {...accountAsGroup.groupMap.coValue.sessions};
319
323
  accountOnThisNode._cachedContent = undefined;
320
324
 
321
325
  return controlledAccount;
@@ -330,7 +334,7 @@ export class LocalNode {
330
334
 
331
335
  if (
332
336
  coValue.header.type !== "comap" ||
333
- coValue.header.ruleset.type !== "team" ||
337
+ coValue.header.ruleset.type !== "group" ||
334
338
  !coValue.header.meta ||
335
339
  !("type" in coValue.header.meta) ||
336
340
  coValue.header.meta.type !== "account"
@@ -343,22 +347,22 @@ export class LocalNode {
343
347
  }
344
348
 
345
349
  return new Account(
346
- coValue.getCurrentContent() as CoMap<TeamContent, AccountMeta>,
350
+ coValue.getCurrentContent() as CoMap<GroupContent, AccountMeta>,
347
351
  this
348
352
  ).getCurrentAgentID();
349
353
  }
350
354
 
351
- createTeam(): Team {
352
- const teamCoValue = this.createCoValue({
355
+ createGroup(): Group {
356
+ const groupCoValue = this.createCoValue({
353
357
  type: "comap",
354
- ruleset: { type: "team", initialAdmin: this.account.id },
358
+ ruleset: { type: "group", initialAdmin: this.account.id },
355
359
  meta: null,
356
360
  ...createdNowUnique(),
357
361
  });
358
362
 
359
- let teamContent = expectTeamContent(teamCoValue.getCurrentContent());
363
+ let groupContent = expectGroupContent(groupCoValue.getCurrentContent());
360
364
 
361
- teamContent = teamContent.edit((editable) => {
365
+ groupContent = groupContent.edit((editable) => {
362
366
  editable.set(this.account.id, "admin", "trusting");
363
367
 
364
368
  const readKey = newRandomKeySecret();
@@ -370,8 +374,8 @@ export class LocalNode {
370
374
  this.account.currentSealerSecret(),
371
375
  this.account.currentSealerID(),
372
376
  {
373
- in: teamCoValue.id,
374
- tx: teamCoValue.nextTransactionID(),
377
+ in: groupCoValue.id,
378
+ tx: groupCoValue.nextTransactionID(),
375
379
  }
376
380
  ),
377
381
  "trusting"
@@ -380,7 +384,7 @@ export class LocalNode {
380
384
  editable.set("readKey", readKey.id, "trusting");
381
385
  });
382
386
 
383
- return new Team(teamContent, this);
387
+ return new Group(groupContent, this);
384
388
  }
385
389
 
386
390
  testWithDifferentAccount(