cojson 0.1.8 → 0.1.9

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.
Files changed (75) hide show
  1. package/dist/account.d.ts +4 -2
  2. package/dist/account.js +4 -2
  3. package/dist/account.js.map +1 -1
  4. package/dist/coValue.d.ts +44 -81
  5. package/dist/coValue.js +4 -348
  6. package/dist/coValue.js.map +1 -1
  7. package/dist/coValueCore.d.ts +84 -0
  8. package/dist/coValueCore.js +351 -0
  9. package/dist/coValueCore.js.map +1 -0
  10. package/dist/coValues/coList.d.ts +113 -0
  11. package/dist/{contentTypes → coValues}/coList.js +59 -19
  12. package/dist/coValues/coList.js.map +1 -0
  13. package/dist/{contentTypes → coValues}/coMap.d.ts +25 -7
  14. package/dist/{contentTypes → coValues}/coMap.js +34 -15
  15. package/dist/coValues/coMap.js.map +1 -0
  16. package/dist/coValues/coStream.d.ts +14 -0
  17. package/dist/coValues/coStream.js +22 -0
  18. package/dist/coValues/coStream.js.map +1 -0
  19. package/dist/coValues/static.d.ts +14 -0
  20. package/dist/coValues/static.js +20 -0
  21. package/dist/coValues/static.js.map +1 -0
  22. package/dist/group.d.ts +54 -9
  23. package/dist/group.js +68 -28
  24. package/dist/group.js.map +1 -1
  25. package/dist/index.d.ts +17 -10
  26. package/dist/index.js +6 -5
  27. package/dist/index.js.map +1 -1
  28. package/dist/node.d.ts +59 -5
  29. package/dist/node.js +36 -15
  30. package/dist/node.js.map +1 -1
  31. package/dist/permissions.d.ts +2 -2
  32. package/dist/permissions.js +1 -1
  33. package/dist/permissions.js.map +1 -1
  34. package/dist/sync.d.ts +3 -3
  35. package/dist/sync.js +2 -2
  36. package/dist/sync.js.map +1 -1
  37. package/dist/testUtils.d.ts +2 -2
  38. package/dist/testUtils.js +1 -1
  39. package/dist/testUtils.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/account.test.ts +1 -1
  42. package/src/account.ts +6 -4
  43. package/src/coValue.test.ts +233 -130
  44. package/src/coValue.ts +50 -576
  45. package/src/coValueCore.test.ts +181 -0
  46. package/src/coValueCore.ts +588 -0
  47. package/src/{contentTypes → coValues}/coList.ts +89 -40
  48. package/src/{contentTypes → coValues}/coMap.ts +40 -20
  49. package/src/coValues/coStream.ts +33 -0
  50. package/src/coValues/static.ts +31 -0
  51. package/src/group.ts +87 -50
  52. package/src/index.ts +30 -28
  53. package/src/node.ts +47 -26
  54. package/src/permissions.test.ts +32 -32
  55. package/src/permissions.ts +5 -5
  56. package/src/sync.test.ts +77 -77
  57. package/src/sync.ts +5 -5
  58. package/src/testUtils.ts +1 -1
  59. package/tsconfig.json +1 -2
  60. package/dist/contentType.d.ts +0 -15
  61. package/dist/contentType.js +0 -7
  62. package/dist/contentType.js.map +0 -1
  63. package/dist/contentTypes/coList.d.ts +0 -77
  64. package/dist/contentTypes/coList.js.map +0 -1
  65. package/dist/contentTypes/coMap.js.map +0 -1
  66. package/dist/contentTypes/coStream.d.ts +0 -11
  67. package/dist/contentTypes/coStream.js +0 -16
  68. package/dist/contentTypes/coStream.js.map +0 -1
  69. package/dist/contentTypes/static.d.ts +0 -11
  70. package/dist/contentTypes/static.js +0 -14
  71. package/dist/contentTypes/static.js.map +0 -1
  72. package/src/contentType.test.ts +0 -284
  73. package/src/contentType.ts +0 -26
  74. package/src/contentTypes/coStream.ts +0 -24
  75. package/src/contentTypes/static.ts +0 -22
package/src/group.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { CoID, ContentType } from "./contentType.js";
2
- import { CoMap } from "./contentTypes/coMap.js";
1
+ import { CoID, CoValueImpl } from "./coValue.js";
2
+ import { CoMap } from "./coValues/coMap.js";
3
3
  import { JsonObject, JsonValue } from "./jsonValue.js";
4
4
  import {
5
5
  Encrypted,
@@ -17,14 +17,10 @@ import {
17
17
  } from "./crypto.js";
18
18
  import { LocalNode } from "./node.js";
19
19
  import { AgentID, SessionID, isAgentID } from "./ids.js";
20
- import {
21
- AccountID,
22
- GeneralizedControlledAccount,
23
- Profile,
24
- } from "./account.js";
20
+ import { AccountID, GeneralizedControlledAccount, Profile } from "./account.js";
25
21
  import { Role } from "./permissions.js";
26
22
  import { base58 } from "@scure/base";
27
- import { CoList } from "./contentTypes/coList.js";
23
+ import { CoList } from "./coValues/coList.js";
28
24
 
29
25
  export type GroupContent = {
30
26
  profile: CoID<Profile> | null;
@@ -38,7 +34,7 @@ export type GroupContent = {
38
34
  };
39
35
 
40
36
  export function expectGroupContent(
41
- content: ContentType
37
+ content: CoValueImpl
42
38
  ): CoMap<GroupContent, JsonObject | null> {
43
39
  if (content.type !== "comap") {
44
40
  throw new Error("Expected map");
@@ -47,43 +43,71 @@ export function expectGroupContent(
47
43
  return content as CoMap<GroupContent, JsonObject | null>;
48
44
  }
49
45
 
46
+ /** A `Group` is a scope for permissions of its members (`"reader" | "writer" | "admin"`), applying to objects owned by that group.
47
+ *
48
+ * A `Group` object exposes methods for permission management and allows you to create new CoValues owned by that group.
49
+ *
50
+ * (Internally, a `Group` is also just a `CoMap`, mapping member accounts to roles and containing some
51
+ * state management for making cryptographic keys available to current members)
52
+ *
53
+ * @example
54
+ * You typically get a group from a CoValue that you already have loaded:
55
+ *
56
+ * ```typescript
57
+ * const group = coMap.group;
58
+ * ```
59
+ *
60
+ * @example
61
+ * Or, you can create a new group with a `LocalNode`:
62
+ *
63
+ * ```typescript
64
+ * const localNode.createGroup();
65
+ * ```
66
+ * */
50
67
  export class Group {
51
- groupMap: CoMap<GroupContent, JsonObject | null>;
68
+ underlyingMap: CoMap<GroupContent, JsonObject | null>;
69
+ /** @internal */
52
70
  node: LocalNode;
53
71
 
72
+ /** @internal */
54
73
  constructor(
55
- groupMap: CoMap<GroupContent, JsonObject | null>,
74
+ underlyingMap: CoMap<GroupContent, JsonObject | null>,
56
75
  node: LocalNode
57
76
  ) {
58
- this.groupMap = groupMap;
77
+ this.underlyingMap = underlyingMap;
59
78
  this.node = node;
60
79
  }
61
80
 
81
+ /** Returns the `CoID` of the `Group`. */
62
82
  get id(): CoID<CoMap<GroupContent, JsonObject | null>> {
63
- return this.groupMap.id;
83
+ return this.underlyingMap.id;
64
84
  }
65
85
 
86
+ /** Returns the current role of a given account. */
66
87
  roleOf(accountID: AccountID): Role | undefined {
67
88
  return this.roleOfInternal(accountID);
68
89
  }
69
90
 
70
91
  /** @internal */
71
92
  roleOfInternal(accountID: AccountID | AgentID): Role | undefined {
72
- return this.groupMap.get(accountID);
93
+ return this.underlyingMap.get(accountID);
73
94
  }
74
95
 
96
+ /** Returns the role of the current account in the group. */
75
97
  myRole(): Role | undefined {
76
98
  return this.roleOfInternal(this.node.account.id);
77
99
  }
78
100
 
101
+ /** Directly grants a new member a role in the group. The current account must be an
102
+ * admin to be able to do so. Throws otherwise. */
79
103
  addMember(accountID: AccountID, role: Role) {
80
104
  this.addMemberInternal(accountID, role);
81
105
  }
82
106
 
83
107
  /** @internal */
84
108
  addMemberInternal(accountID: AccountID | AgentID, role: Role) {
85
- this.groupMap = this.groupMap.edit((map) => {
86
- const currentReadKey = this.groupMap.coValue.getCurrentReadKey();
109
+ this.underlyingMap = this.underlyingMap.edit((map) => {
110
+ const currentReadKey = this.underlyingMap.core.getCurrentReadKey();
87
111
 
88
112
  if (!currentReadKey.secret) {
89
113
  throw new Error("Can't add member without read key secret");
@@ -104,11 +128,11 @@ export class Group {
104
128
  `${currentReadKey.id}_for_${accountID}`,
105
129
  seal(
106
130
  currentReadKey.secret,
107
- this.groupMap.coValue.node.account.currentSealerSecret(),
131
+ this.underlyingMap.core.node.account.currentSealerSecret(),
108
132
  getAgentSealerID(agent),
109
133
  {
110
- in: this.groupMap.coValue.id,
111
- tx: this.groupMap.coValue.nextTransactionID(),
134
+ in: this.underlyingMap.core.id,
135
+ tx: this.underlyingMap.core.nextTransactionID(),
112
136
  }
113
137
  ),
114
138
  "trusting"
@@ -116,30 +140,24 @@ export class Group {
116
140
  });
117
141
  }
118
142
 
119
- createInvite(role: "reader" | "writer" | "admin"): InviteSecret {
120
- const secretSeed = newRandomSecretSeed();
121
-
122
- const inviteSecret = agentSecretFromSecretSeed(secretSeed);
123
- const inviteID = getAgentID(inviteSecret);
124
-
125
- this.addMemberInternal(inviteID, `${role}Invite` as Role);
126
-
127
- return inviteSecretFromSecretSeed(secretSeed);
128
- }
129
-
143
+ /** @internal */
130
144
  rotateReadKey() {
131
- const currentlyPermittedReaders = this.groupMap.keys().filter((key) => {
132
- if (key.startsWith("co_") || isAgentID(key)) {
133
- const role = this.groupMap.get(key);
134
- return (
135
- role === "admin" || role === "writer" || role === "reader"
136
- );
137
- } else {
138
- return false;
139
- }
140
- }) as (AccountID | AgentID)[];
141
-
142
- const maybeCurrentReadKey = this.groupMap.coValue.getCurrentReadKey();
145
+ const currentlyPermittedReaders = this.underlyingMap
146
+ .keys()
147
+ .filter((key) => {
148
+ if (key.startsWith("co_") || isAgentID(key)) {
149
+ const role = this.underlyingMap.get(key);
150
+ return (
151
+ role === "admin" ||
152
+ role === "writer" ||
153
+ role === "reader"
154
+ );
155
+ } else {
156
+ return false;
157
+ }
158
+ }) as (AccountID | AgentID)[];
159
+
160
+ const maybeCurrentReadKey = this.underlyingMap.core.getCurrentReadKey();
143
161
 
144
162
  if (!maybeCurrentReadKey.secret) {
145
163
  throw new Error(
@@ -154,7 +172,7 @@ export class Group {
154
172
 
155
173
  const newReadKey = newRandomKeySecret();
156
174
 
157
- this.groupMap = this.groupMap.edit((map) => {
175
+ this.underlyingMap = this.underlyingMap.edit((map) => {
158
176
  for (const readerID of currentlyPermittedReaders) {
159
177
  const reader = this.node.resolveAccountAgent(
160
178
  readerID,
@@ -165,11 +183,11 @@ export class Group {
165
183
  `${newReadKey.id}_for_${readerID}`,
166
184
  seal(
167
185
  newReadKey.secret,
168
- this.groupMap.coValue.node.account.currentSealerSecret(),
186
+ this.underlyingMap.core.node.account.currentSealerSecret(),
169
187
  getAgentSealerID(reader),
170
188
  {
171
- in: this.groupMap.coValue.id,
172
- tx: this.groupMap.coValue.nextTransactionID(),
189
+ in: this.underlyingMap.core.id,
190
+ tx: this.underlyingMap.core.nextTransactionID(),
173
191
  }
174
192
  ),
175
193
  "trusting"
@@ -189,19 +207,36 @@ export class Group {
189
207
  });
190
208
  }
191
209
 
210
+ /** Strips the specified member of all roles (preventing future writes in
211
+ * the group and owned values) and rotates the read encryption key for that group
212
+ * (preventing reads of new content in the group and owned values) */
192
213
  removeMember(accountID: AccountID) {
193
214
  this.removeMemberInternal(accountID);
194
215
  }
195
216
 
196
217
  /** @internal */
197
218
  removeMemberInternal(accountID: AccountID | AgentID) {
198
- this.groupMap = this.groupMap.edit((map) => {
219
+ this.underlyingMap = this.underlyingMap.edit((map) => {
199
220
  map.set(accountID, "revoked", "trusting");
200
221
  });
201
222
 
202
223
  this.rotateReadKey();
203
224
  }
204
225
 
226
+ /** Creates an invite for new members to indirectly join the group, allowing them to grant themselves the specified role with the InviteSecret (a string starting with "inviteSecret_") - use `LocalNode.acceptInvite()` for this purpose. */
227
+ createInvite(role: "reader" | "writer" | "admin"): InviteSecret {
228
+ const secretSeed = newRandomSecretSeed();
229
+
230
+ const inviteSecret = agentSecretFromSecretSeed(secretSeed);
231
+ const inviteID = getAgentID(inviteSecret);
232
+
233
+ this.addMemberInternal(inviteID, `${role}Invite` as Role);
234
+
235
+ return inviteSecretFromSecretSeed(secretSeed);
236
+ }
237
+
238
+ /** Creates a new `CoMap` within this group, with the specified specialized
239
+ * `CoMap` type `M` and optional static metadata. */
205
240
  createMap<M extends CoMap<{ [key: string]: JsonValue }, JsonObject | null>>(
206
241
  meta?: M["meta"]
207
242
  ): M {
@@ -210,7 +245,7 @@ export class Group {
210
245
  type: "comap",
211
246
  ruleset: {
212
247
  type: "ownedByGroup",
213
- group: this.groupMap.id,
248
+ group: this.underlyingMap.id,
214
249
  },
215
250
  meta: meta || null,
216
251
  ...createdNowUnique(),
@@ -218,6 +253,8 @@ export class Group {
218
253
  .getCurrentContent() as M;
219
254
  }
220
255
 
256
+ /** Creates a new `CoList` within this group, with the specified specialized
257
+ * `CoList` type `L` and optional static metadata. */
221
258
  createList<L extends CoList<JsonValue, JsonObject | null>>(
222
259
  meta?: L["meta"]
223
260
  ): L {
@@ -226,7 +263,7 @@ export class Group {
226
263
  type: "colist",
227
264
  ruleset: {
228
265
  type: "ownedByGroup",
229
- group: this.groupMap.id,
266
+ group: this.underlyingMap.id,
230
267
  },
231
268
  meta: meta || null,
232
269
  ...createdNowUnique(),
@@ -241,7 +278,7 @@ export class Group {
241
278
  ): Group {
242
279
  return new Group(
243
280
  expectGroupContent(
244
- this.groupMap.coValue
281
+ this.underlyingMap.core
245
282
  .testWithDifferentAccount(account, sessionId)
246
283
  .getCurrentContent()
247
284
  ),
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { CoValue, newRandomSessionID } from "./coValue.js";
1
+ import { CoValueCore, newRandomSessionID } from "./coValueCore.js";
2
2
  import { LocalNode } from "./node.js";
3
- import { CoMap } from "./contentTypes/coMap.js";
4
- import { CoList } from "./contentTypes/coList.js";
3
+ import type { CoValue, ReadableCoValue } from "./coValue.js";
4
+ import { CoMap, WriteableCoMap } from "./coValues/coMap.js";
5
+ import { CoList, WriteableCoList } from "./coValues/coList.js";
5
6
  import {
6
7
  agentSecretFromBytes,
7
8
  agentSecretToBytes,
@@ -15,24 +16,19 @@ import {
15
16
  import { connectedPeers } from "./streamUtils.js";
16
17
  import { AnonymousControlledAccount, ControlledAccount } from "./account.js";
17
18
  import { rawCoIDtoBytes, rawCoIDfromBytes } from "./ids.js";
18
- import { Group, expectGroupContent } from "./group.js"
19
+ import { Group, expectGroupContent } from "./group.js";
19
20
 
20
21
  import type { SessionID, AgentID } from "./ids.js";
21
- import type { CoID, ContentType } from "./contentType.js";
22
+ import type { CoID, CoValueImpl } from "./coValue.js";
22
23
  import type { JsonValue } from "./jsonValue.js";
23
24
  import type { SyncMessage, Peer } from "./sync.js";
24
25
  import type { AgentSecret } from "./crypto.js";
25
- import type {
26
- AccountID,
27
- AccountContent,
28
- ProfileContent,
29
- ProfileMeta,
30
- Profile,
31
- } from "./account.js";
26
+ import type { AccountID, Profile } from "./account.js";
32
27
  import type { InviteSecret } from "./group.js";
33
28
 
34
- type Value = JsonValue | ContentType;
29
+ type Value = JsonValue | CoValueImpl;
35
30
 
31
+ /** @hidden */
36
32
  export const cojsonInternals = {
37
33
  agentSecretFromBytes,
38
34
  agentSecretToBytes,
@@ -46,35 +42,36 @@ export const cojsonInternals = {
46
42
  agentSecretFromSecretSeed,
47
43
  secretSeedLength,
48
44
  shortHashLength,
49
- expectGroupContent
45
+ expectGroupContent,
50
46
  };
51
47
 
52
48
  export {
53
49
  LocalNode,
54
- CoValue,
50
+ Group,
55
51
  CoMap,
52
+ WriteableCoMap,
56
53
  CoList,
54
+ WriteableCoList,
55
+ CoValueCore,
57
56
  AnonymousControlledAccount,
58
57
  ControlledAccount,
59
- Group
60
58
  };
61
59
 
62
60
  export type {
63
61
  Value,
64
62
  JsonValue,
65
- ContentType,
63
+ CoValue,
64
+ ReadableCoValue,
65
+ CoValueImpl,
66
66
  CoID,
67
- AgentSecret,
68
- SessionID,
69
- SyncMessage,
70
- AgentID,
71
67
  AccountID,
72
- Peer,
73
- AccountContent,
74
68
  Profile,
75
- ProfileContent,
76
- ProfileMeta,
77
- InviteSecret
69
+ SessionID,
70
+ Peer,
71
+ AgentID,
72
+ AgentSecret,
73
+ InviteSecret,
74
+ SyncMessage,
78
75
  };
79
76
 
80
77
  // eslint-disable-next-line @typescript-eslint/no-namespace
@@ -84,8 +81,13 @@ export namespace CojsonInternalTypes {
84
81
  export type KnownStateMessage = import("./sync.js").KnownStateMessage;
85
82
  export type LoadMessage = import("./sync.js").LoadMessage;
86
83
  export type NewContentMessage = import("./sync.js").NewContentMessage;
87
- export type CoValueHeader = import("./coValue.js").CoValueHeader;
88
- export type Transaction = import("./coValue.js").Transaction;
84
+ export type CoValueHeader = import("./coValueCore.js").CoValueHeader;
85
+ export type Transaction = import("./coValueCore.js").Transaction;
89
86
  export type Signature = import("./crypto.js").Signature;
90
87
  export type RawCoID = import("./ids.js").RawCoID;
88
+ export type AccountContent = import("./account.js").AccountContent;
89
+ export type ProfileContent = import("./account.js").ProfileContent;
90
+ export type ProfileMeta = import("./account.js").ProfileMeta;
91
+ export type SealerSecret = import("./crypto.js").SealerSecret;
92
+ export type SignerSecret = import("./crypto.js").SignerSecret;
91
93
  }
package/src/node.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  newRandomKeySecret,
10
10
  seal,
11
11
  } from "./crypto.js";
12
- import { CoValue, CoValueHeader, newRandomSessionID } from "./coValue.js";
12
+ import { CoValueCore, CoValueHeader, newRandomSessionID } from "./coValueCore.js";
13
13
  import {
14
14
  InviteSecret,
15
15
  Group,
@@ -19,7 +19,7 @@ import {
19
19
  } from "./group.js";
20
20
  import { Peer, SyncManager } from "./sync.js";
21
21
  import { AgentID, RawCoID, SessionID, isAgentID } from "./ids.js";
22
- import { CoID, ContentType } from "./contentType.js";
22
+ import { CoID, CoValueImpl } from "./coValue.js";
23
23
  import {
24
24
  Account,
25
25
  AccountMeta,
@@ -34,6 +34,17 @@ import {
34
34
  } from "./account.js";
35
35
  import { CoMap } from "./index.js";
36
36
 
37
+ /** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
38
+
39
+ A `LocalNode` can have peers that it syncs to, for example some form of local persistence, or a sync server, such as `sync.jazz.tools` (Jazz Global Mesh).
40
+
41
+ @example
42
+ You typically get hold of a `LocalNode` using `jazz-react`'s `useJazz()`:
43
+
44
+ ```typescript
45
+ const { localNode } = useJazz();
46
+ ```
47
+ */
37
48
  export class LocalNode {
38
49
  /** @internal */
39
50
  coValues: { [key: RawCoID]: CoValueState } = {};
@@ -111,8 +122,8 @@ export class LocalNode {
111
122
  }
112
123
 
113
124
  /** @internal */
114
- createCoValue(header: CoValueHeader): CoValue {
115
- const coValue = new CoValue(header, this);
125
+ createCoValue(header: CoValueHeader): CoValueCore {
126
+ const coValue = new CoValueCore(header, this);
116
127
  this.coValues[coValue.id] = { state: "loaded", coValue: coValue };
117
128
 
118
129
  void this.sync.syncCoValue(coValue);
@@ -121,7 +132,7 @@ export class LocalNode {
121
132
  }
122
133
 
123
134
  /** @internal */
124
- loadCoValue(id: RawCoID): Promise<CoValue> {
135
+ loadCoValue(id: RawCoID): Promise<CoValueCore> {
125
136
  let entry = this.coValues[id];
126
137
  if (!entry) {
127
138
  entry = newLoadingState();
@@ -136,10 +147,19 @@ export class LocalNode {
136
147
  return entry.done;
137
148
  }
138
149
 
139
- async load<T extends ContentType>(id: CoID<T>): Promise<T> {
150
+ /**
151
+ * Loads a CoValue's content, syncing from peers as necessary and resolving the returned
152
+ * promise once a first version has been loaded. See `coValue.subscribe()` and `node.useTelepathicData()`
153
+ * for listening to subsequent updates to the CoValue.
154
+ */
155
+ async load<T extends CoValueImpl>(id: CoID<T>): Promise<T> {
140
156
  return (await this.loadCoValue(id)).getCurrentContent() as T;
141
157
  }
142
158
 
159
+ /**
160
+ * Loads a profile associated with an account. `Profile` is at least a `CoMap<{string: name}>`,
161
+ * but might contain other, app-specific properties.
162
+ */
143
163
  async loadProfile(id: AccountID): Promise<Profile> {
144
164
  const account = await this.load<AccountMap>(id);
145
165
  const profileID = account.get("profile");
@@ -152,20 +172,20 @@ export class LocalNode {
152
172
  ).getCurrentContent() as Profile;
153
173
  }
154
174
 
155
- async acceptInvite<T extends ContentType>(
175
+ async acceptInvite<T extends CoValueImpl>(
156
176
  groupOrOwnedValueID: CoID<T>,
157
177
  inviteSecret: InviteSecret
158
178
  ): Promise<void> {
159
179
  const groupOrOwnedValue = await this.load(groupOrOwnedValueID);
160
180
 
161
- if (groupOrOwnedValue.coValue.header.ruleset.type === "ownedByGroup") {
181
+ if (groupOrOwnedValue.core.header.ruleset.type === "ownedByGroup") {
162
182
  return this.acceptInvite(
163
- groupOrOwnedValue.coValue.header.ruleset.group as CoID<
183
+ groupOrOwnedValue.core.header.ruleset.group as CoID<
164
184
  CoMap<GroupContent>
165
185
  >,
166
186
  inviteSecret
167
187
  );
168
- } else if (groupOrOwnedValue.coValue.header.ruleset.type !== "group") {
188
+ } else if (groupOrOwnedValue.core.header.ruleset.type !== "group") {
169
189
  throw new Error("Can only accept invites to groups");
170
190
  }
171
191
 
@@ -177,7 +197,7 @@ export class LocalNode {
177
197
  const inviteAgentID = getAgentID(inviteAgentSecret);
178
198
 
179
199
  const inviteRole = await new Promise((resolve, reject) => {
180
- group.groupMap.subscribe((groupMap) => {
200
+ group.underlyingMap.subscribe((groupMap) => {
181
201
  const role = groupMap.get(inviteAgentID);
182
202
  if (role) {
183
203
  resolve(role);
@@ -196,7 +216,7 @@ export class LocalNode {
196
216
  throw new Error("No invite found");
197
217
  }
198
218
 
199
- const existingRole = group.groupMap.get(this.account.id);
219
+ const existingRole = group.underlyingMap.get(this.account.id);
200
220
 
201
221
  if (
202
222
  existingRole === "admin" ||
@@ -222,16 +242,16 @@ export class LocalNode {
222
242
  : "reader"
223
243
  );
224
244
 
225
- group.groupMap.coValue._sessions = groupAsInvite.groupMap.coValue.sessions;
226
- group.groupMap.coValue._cachedContent = undefined;
245
+ group.underlyingMap.core._sessions = groupAsInvite.underlyingMap.core.sessions;
246
+ group.underlyingMap.core._cachedContent = undefined;
227
247
 
228
- for (const groupListener of group.groupMap.coValue.listeners) {
229
- groupListener(group.groupMap.coValue.getCurrentContent());
248
+ for (const groupListener of group.underlyingMap.core.listeners) {
249
+ groupListener(group.underlyingMap.core.getCurrentContent());
230
250
  }
231
251
  }
232
252
 
233
253
  /** @internal */
234
- expectCoValueLoaded(id: RawCoID, expectation?: string): CoValue {
254
+ expectCoValueLoaded(id: RawCoID, expectation?: string): CoValueCore {
235
255
  const entry = this.coValues[id];
236
256
  if (!entry) {
237
257
  throw new Error(
@@ -284,7 +304,7 @@ export class LocalNode {
284
304
  account.node
285
305
  );
286
306
 
287
- accountAsGroup.groupMap.edit((editable) => {
307
+ accountAsGroup.underlyingMap.edit((editable) => {
288
308
  editable.set(getAgentID(agentSecret), "admin", "trusting");
289
309
 
290
310
  const readKey = newRandomKeySecret();
@@ -320,13 +340,13 @@ export class LocalNode {
320
340
  editable.set("name", name, "trusting");
321
341
  });
322
342
 
323
- accountAsGroup.groupMap.edit((editable) => {
343
+ accountAsGroup.underlyingMap.edit((editable) => {
324
344
  editable.set("profile", profile.id, "trusting");
325
345
  });
326
346
 
327
347
  const accountOnThisNode = this.expectCoValueLoaded(account.id);
328
348
 
329
- accountOnThisNode._sessions = {...accountAsGroup.groupMap.coValue.sessions};
349
+ accountOnThisNode._sessions = {...accountAsGroup.underlyingMap.core.sessions};
330
350
  accountOnThisNode._cachedContent = undefined;
331
351
 
332
352
  return controlledAccount;
@@ -360,6 +380,7 @@ export class LocalNode {
360
380
  ).getCurrentAgentID();
361
381
  }
362
382
 
383
+ /** Creates a new group (with the current account as the group's first admin). */
363
384
  createGroup(): Group {
364
385
  const groupCoValue = this.createCoValue({
365
386
  type: "comap",
@@ -422,7 +443,7 @@ export class LocalNode {
422
443
  continue;
423
444
  }
424
445
 
425
- const newCoValue = new CoValue(entry.coValue.header, newNode, {...entry.coValue.sessions});
446
+ const newCoValue = new CoValueCore(entry.coValue.header, newNode, {...entry.coValue.sessions});
426
447
 
427
448
  newNode.coValues[coValueID as RawCoID] = {
428
449
  state: "loaded",
@@ -441,16 +462,16 @@ export class LocalNode {
441
462
  type CoValueState =
442
463
  | {
443
464
  state: "loading";
444
- done: Promise<CoValue>;
445
- resolve: (coValue: CoValue) => void;
465
+ done: Promise<CoValueCore>;
466
+ resolve: (coValue: CoValueCore) => void;
446
467
  }
447
- | { state: "loaded"; coValue: CoValue };
468
+ | { state: "loaded"; coValue: CoValueCore };
448
469
 
449
470
  /** @internal */
450
471
  export function newLoadingState(): CoValueState {
451
- let resolve: (coValue: CoValue) => void;
472
+ let resolve: (coValue: CoValueCore) => void;
452
473
 
453
- const promise = new Promise<CoValue>((r) => {
474
+ const promise = new Promise<CoValueCore>((r) => {
454
475
  resolve = r;
455
476
  });
456
477