cojson 0.0.24 → 0.1.1

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,32 +151,32 @@ 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)
174
174
  );
175
175
  const inviteAgentID = getAgentID(inviteAgentSecret);
176
176
 
177
- const invitationRole = await new Promise((resolve, reject) => {
178
- team.teamMap.subscribe((teamMap) => {
179
- const role = teamMap.get(inviteAgentID);
177
+ const inviteRole = await new Promise((resolve, reject) => {
178
+ group.groupMap.subscribe((groupMap) => {
179
+ const role = groupMap.get(inviteAgentID);
180
180
  if (role) {
181
181
  resolve(role);
182
182
  }
@@ -184,45 +184,47 @@ export class LocalNode {
184
184
  setTimeout(
185
185
  () =>
186
186
  reject(
187
- new Error("Couldn't find invitation before timeout")
187
+ new Error("Couldn't find invite before timeout")
188
188
  ),
189
189
  1000
190
190
  );
191
191
  });
192
192
 
193
- if (!invitationRole) {
194
- throw new Error("No invitation found");
193
+ if (!inviteRole) {
194
+ throw new Error("No invite 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" ||
201
- (existingRole === "writer" && invitationRole === "reader")
201
+ (existingRole === "writer" && inviteRole === "writerInvite") ||
202
+ (existingRole === "writer" && inviteRole === "reader") ||
203
+ (existingRole === "reader" && inviteRole === "readerInvite")
202
204
  ) {
203
- console.debug("Not accepting invite that would downgrade role");
205
+ console.debug("Not accepting invite that would replace or downgrade role");
204
206
  return;
205
207
  }
206
208
 
207
- const teamAsInvite = team.testWithDifferentAccount(
209
+ const groupAsInvite = group.testWithDifferentAccount(
208
210
  new AnonymousControlledAccount(inviteAgentSecret),
209
211
  newRandomSessionID(inviteAgentID)
210
212
  );
211
213
 
212
- teamAsInvite.addMember(
214
+ groupAsInvite.addMember(
213
215
  this.account.id,
214
- invitationRole === "adminInvite"
216
+ inviteRole === "adminInvite"
215
217
  ? "admin"
216
- : invitationRole === "writerInvite"
218
+ : inviteRole === "writerInvite"
217
219
  ? "writer"
218
220
  : "reader"
219
221
  );
220
222
 
221
- team.teamMap.coValue._sessions = teamAsInvite.teamMap.coValue.sessions;
222
- team.teamMap.coValue._cachedContent = undefined;
223
+ group.groupMap.coValue._sessions = groupAsInvite.groupMap.coValue.sessions;
224
+ group.groupMap.coValue._cachedContent = undefined;
223
225
 
224
- for (const teamListener of team.teamMap.coValue.listeners) {
225
- teamListener(team.teamMap.coValue.getCurrentContent());
226
+ for (const groupListener of group.groupMap.coValue.listeners) {
227
+ groupListener(group.groupMap.coValue.getCurrentContent());
226
228
  }
227
229
  }
228
230
 
@@ -245,7 +247,7 @@ export class LocalNode {
245
247
 
246
248
  expectProfileLoaded(id: AccountID, expectation?: string): Profile {
247
249
  const account = this.expectCoValueLoaded(id, expectation);
248
- const profileID = expectTeamContent(account.getCurrentContent()).get(
250
+ const profileID = expectGroupContent(account.getCurrentContent()).get(
249
251
  "profile"
250
252
  );
251
253
  if (!profileID) {
@@ -272,12 +274,12 @@ export class LocalNode {
272
274
  newRandomSessionID(getAgentID(agentSecret))
273
275
  );
274
276
 
275
- const accountAsTeam = new Team(
276
- expectTeamContent(account.getCurrentContent()),
277
+ const accountAsGroup = new Group(
278
+ expectGroupContent(account.getCurrentContent()),
277
279
  account.node
278
280
  );
279
281
 
280
- accountAsTeam.teamMap.edit((editable) => {
282
+ accountAsGroup.groupMap.edit((editable) => {
281
283
  editable.set(getAgentID(agentSecret), "admin", "trusting");
282
284
 
283
285
  const readKey = newRandomKeySecret();
@@ -305,7 +307,7 @@ export class LocalNode {
305
307
  account.node
306
308
  );
307
309
 
308
- const profile = accountAsTeam.createMap<ProfileContent, ProfileMeta>({
310
+ const profile = accountAsGroup.createMap<ProfileContent, ProfileMeta>({
309
311
  type: "profile",
310
312
  });
311
313
 
@@ -313,13 +315,13 @@ export class LocalNode {
313
315
  editable.set("name", name, "trusting");
314
316
  });
315
317
 
316
- accountAsTeam.teamMap.edit((editable) => {
318
+ accountAsGroup.groupMap.edit((editable) => {
317
319
  editable.set("profile", profile.id, "trusting");
318
320
  });
319
321
 
320
322
  const accountOnThisNode = this.expectCoValueLoaded(account.id);
321
323
 
322
- accountOnThisNode._sessions = {...accountAsTeam.teamMap.coValue.sessions};
324
+ accountOnThisNode._sessions = {...accountAsGroup.groupMap.coValue.sessions};
323
325
  accountOnThisNode._cachedContent = undefined;
324
326
 
325
327
  return controlledAccount;
@@ -334,7 +336,7 @@ export class LocalNode {
334
336
 
335
337
  if (
336
338
  coValue.header.type !== "comap" ||
337
- coValue.header.ruleset.type !== "team" ||
339
+ coValue.header.ruleset.type !== "group" ||
338
340
  !coValue.header.meta ||
339
341
  !("type" in coValue.header.meta) ||
340
342
  coValue.header.meta.type !== "account"
@@ -347,22 +349,22 @@ export class LocalNode {
347
349
  }
348
350
 
349
351
  return new Account(
350
- coValue.getCurrentContent() as CoMap<TeamContent, AccountMeta>,
352
+ coValue.getCurrentContent() as CoMap<GroupContent, AccountMeta>,
351
353
  this
352
354
  ).getCurrentAgentID();
353
355
  }
354
356
 
355
- createTeam(): Team {
356
- const teamCoValue = this.createCoValue({
357
+ createGroup(): Group {
358
+ const groupCoValue = this.createCoValue({
357
359
  type: "comap",
358
- ruleset: { type: "team", initialAdmin: this.account.id },
360
+ ruleset: { type: "group", initialAdmin: this.account.id },
359
361
  meta: null,
360
362
  ...createdNowUnique(),
361
363
  });
362
364
 
363
- let teamContent = expectTeamContent(teamCoValue.getCurrentContent());
365
+ let groupContent = expectGroupContent(groupCoValue.getCurrentContent());
364
366
 
365
- teamContent = teamContent.edit((editable) => {
367
+ groupContent = groupContent.edit((editable) => {
366
368
  editable.set(this.account.id, "admin", "trusting");
367
369
 
368
370
  const readKey = newRandomKeySecret();
@@ -374,8 +376,8 @@ export class LocalNode {
374
376
  this.account.currentSealerSecret(),
375
377
  this.account.currentSealerID(),
376
378
  {
377
- in: teamCoValue.id,
378
- tx: teamCoValue.nextTransactionID(),
379
+ in: groupCoValue.id,
380
+ tx: groupCoValue.nextTransactionID(),
379
381
  }
380
382
  ),
381
383
  "trusting"
@@ -384,7 +386,7 @@ export class LocalNode {
384
386
  editable.set("readKey", readKey.id, "trusting");
385
387
  });
386
388
 
387
- return new Team(teamContent, this);
389
+ return new Group(groupContent, this);
388
390
  }
389
391
 
390
392
  testWithDifferentAccount(