cojson 0.16.4 → 0.16.5

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 (50) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/dist/coValue.d.ts.map +1 -1
  4. package/dist/coValue.js.map +1 -1
  5. package/dist/coValueCore/coValueCore.d.ts +6 -10
  6. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  7. package/dist/coValueCore/coValueCore.js +15 -122
  8. package/dist/coValueCore/coValueCore.js.map +1 -1
  9. package/dist/coValues/group.d.ts +18 -10
  10. package/dist/coValues/group.d.ts.map +1 -1
  11. package/dist/coValues/group.js +221 -59
  12. package/dist/coValues/group.js.map +1 -1
  13. package/dist/ids.d.ts +3 -3
  14. package/dist/ids.d.ts.map +1 -1
  15. package/dist/ids.js.map +1 -1
  16. package/dist/localNode.d.ts +5 -5
  17. package/dist/localNode.d.ts.map +1 -1
  18. package/dist/tests/group.inheritance.test.js +195 -0
  19. package/dist/tests/group.inheritance.test.js.map +1 -1
  20. package/dist/tests/group.removeMember.test.js +152 -1
  21. package/dist/tests/group.removeMember.test.js.map +1 -1
  22. package/dist/tests/group.roleOf.test.js +2 -2
  23. package/dist/tests/group.roleOf.test.js.map +1 -1
  24. package/dist/tests/group.test.js +81 -3
  25. package/dist/tests/group.test.js.map +1 -1
  26. package/dist/tests/sync.load.test.js +6 -3
  27. package/dist/tests/sync.load.test.js.map +1 -1
  28. package/dist/tests/testUtils.d.ts +1 -0
  29. package/dist/tests/testUtils.d.ts.map +1 -1
  30. package/dist/tests/testUtils.js +5 -0
  31. package/dist/tests/testUtils.js.map +1 -1
  32. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
  33. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
  34. package/dist/typeUtils/expectGroup.d.ts.map +1 -1
  35. package/dist/typeUtils/expectGroup.js +6 -5
  36. package/dist/typeUtils/expectGroup.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/coValue.ts +1 -4
  39. package/src/coValueCore/coValueCore.ts +23 -188
  40. package/src/coValues/group.ts +310 -91
  41. package/src/ids.ts +3 -3
  42. package/src/localNode.ts +7 -7
  43. package/src/tests/group.inheritance.test.ts +279 -0
  44. package/src/tests/group.removeMember.test.ts +244 -1
  45. package/src/tests/group.roleOf.test.ts +2 -2
  46. package/src/tests/group.test.ts +105 -5
  47. package/src/tests/sync.load.test.ts +6 -3
  48. package/src/tests/testUtils.ts +5 -0
  49. package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
  50. package/src/typeUtils/expectGroup.ts +8 -5
@@ -1,8 +1,11 @@
1
1
  import { base58 } from "@scure/base";
2
- import { CoID } from "../coValue.js";
3
- import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
4
- import { CoValueUniqueness } from "../coValueCore/verifiedState.js";
5
- import {
2
+ import type { CoID } from "../coValue.js";
3
+ import type {
4
+ AvailableCoValueCore,
5
+ CoValueCore,
6
+ } from "../coValueCore/coValueCore.js";
7
+ import type { CoValueUniqueness } from "../coValueCore/verifiedState.js";
8
+ import type {
6
9
  CryptoProvider,
7
10
  Encrypted,
8
11
  KeyID,
@@ -21,8 +24,10 @@ import {
21
24
  } from "../ids.js";
22
25
  import { JsonObject } from "../jsonValue.js";
23
26
  import { logger } from "../logger.js";
24
- import { AccountRole, Role } from "../permissions.js";
27
+ import { AccountRole, Role, isKeyForKeyField } from "../permissions.js";
28
+ import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
25
29
  import { expectGroup } from "../typeUtils/expectGroup.js";
30
+ import { isAccountID } from "../typeUtils/isAccountID.js";
26
31
  import {
27
32
  ControlledAccountOrAgent,
28
33
  RawAccount,
@@ -60,6 +65,59 @@ export type GroupShape = {
60
65
  [child: ChildGroupReference]: "revoked" | "extend";
61
66
  };
62
67
 
68
+ // We had a bug on key rotation, where the new read key was not revealed to everyone
69
+ // TODO: remove this when we hit the 0.18.0 release (either the groups are healed or they are not used often, it's a minor issue anyway)
70
+ function healMissingKeyForEveryone(group: RawGroup) {
71
+ const readKeyId = group.get("readKey");
72
+
73
+ if (
74
+ !readKeyId ||
75
+ !canRead(group, EVERYONE) ||
76
+ group.get(`${readKeyId}_for_${EVERYONE}`)
77
+ ) {
78
+ return;
79
+ }
80
+
81
+ const hasAccessToReadKey = canRead(
82
+ group,
83
+ group.core.node.getCurrentAgent().id,
84
+ );
85
+
86
+ // If the current account has access to the read key, we can fix the group
87
+ if (hasAccessToReadKey) {
88
+ const secret = group.getReadKey(readKeyId);
89
+ if (secret) {
90
+ group.set(`${readKeyId}_for_${EVERYONE}`, secret, "trusting");
91
+ }
92
+ return;
93
+ }
94
+
95
+ // Fallback to the latest readable key for everyone
96
+ const keys = group
97
+ .keys()
98
+ .filter((key) => key.startsWith("key_") && key.endsWith("_for_everyone"));
99
+
100
+ let latestKey = keys[0];
101
+
102
+ for (const key of keys) {
103
+ if (!latestKey) {
104
+ latestKey = key;
105
+ continue;
106
+ }
107
+
108
+ const keyEntry = group.getRaw(key);
109
+ const latestKeyEntry = group.getRaw(latestKey);
110
+
111
+ if (keyEntry && latestKeyEntry && keyEntry.madeAt > latestKeyEntry.madeAt) {
112
+ latestKey = key;
113
+ }
114
+ }
115
+
116
+ if (latestKey) {
117
+ group._lastReadableKeyId = latestKey.replace("_for_everyone", "") as KeyID;
118
+ }
119
+ }
120
+
63
121
  /** A `Group` is a scope for permissions of its members (`"reader" | "writer" | "admin"`), applying to objects owned by that group.
64
122
  *
65
123
  * A `Group` object exposes methods for permission management and allows you to create new CoValues owned by that group.
@@ -86,6 +144,8 @@ export class RawGroup<
86
144
  > extends RawCoMap<GroupShape, Meta> {
87
145
  protected readonly crypto: CryptoProvider;
88
146
 
147
+ _lastReadableKeyId?: KeyID;
148
+
89
149
  constructor(
90
150
  core: AvailableCoValueCore,
91
151
  options?: {
@@ -94,6 +154,8 @@ export class RawGroup<
94
154
  ) {
95
155
  super(core, options);
96
156
  this.crypto = core.node.crypto;
157
+
158
+ healMissingKeyForEveryone(this);
97
159
  }
98
160
 
99
161
  /**
@@ -191,43 +253,7 @@ export class RawGroup<
191
253
  return groups;
192
254
  }
193
255
 
194
- loadAllChildGroups() {
195
- const requests: Promise<unknown>[] = [];
196
- const peers = this.core.node.syncManager.getServerPeers();
197
-
198
- for (const key of this.keys()) {
199
- if (!isChildGroupReference(key)) {
200
- continue;
201
- }
202
-
203
- const id = getChildGroupId(key);
204
- const child = this.core.node.getCoValue(id);
205
-
206
- if (
207
- child.loadingState === "unknown" ||
208
- child.loadingState === "unavailable"
209
- ) {
210
- child.load(peers);
211
- }
212
-
213
- requests.push(
214
- child.waitForAvailableOrUnavailable().then((coValue) => {
215
- if (!coValue.isAvailable()) {
216
- throw new Error(`Child group ${child.id} is unavailable`);
217
- }
218
-
219
- // Recursively load child groups
220
- return expectGroup(coValue.getCurrentContent()).loadAllChildGroups();
221
- }),
222
- );
223
- }
224
-
225
- return Promise.all(requests);
226
- }
227
-
228
- getChildGroups() {
229
- const groups: RawGroup[] = [];
230
-
256
+ forEachChildGroup(callback: (child: RawGroup) => void) {
231
257
  for (const key of this.keys()) {
232
258
  if (isChildGroupReference(key)) {
233
259
  // Check if the child group reference is revoked
@@ -235,15 +261,22 @@ export class RawGroup<
235
261
  continue;
236
262
  }
237
263
 
238
- const child = this.core.node.expectCoValueLoaded(
239
- getChildGroupId(key),
240
- "Expected child group to be loaded",
241
- );
242
- groups.push(expectGroup(child.getCurrentContent()));
264
+ const id = getChildGroupId(key);
265
+ const child = this.core.node.getCoValue(id);
266
+
267
+ if (child.isAvailable()) {
268
+ callback(expectGroup(child.getCurrentContent()));
269
+ } else {
270
+ this.core.node.load(id).then((child) => {
271
+ if (child !== "unavailable") {
272
+ callback(expectGroup(child));
273
+ } else {
274
+ logger.warn(`Unable to load child group ${id}, skipping`);
275
+ }
276
+ });
277
+ }
243
278
  }
244
279
  }
245
-
246
- return groups;
247
280
  }
248
281
 
249
282
  /**
@@ -279,7 +312,7 @@ export class RawGroup<
279
312
  "Can't make everyone something other than reader, writer or writeOnly",
280
313
  );
281
314
  }
282
- const currentReadKey = this.core.getCurrentReadKey();
315
+ const currentReadKey = this.getCurrentReadKey();
283
316
 
284
317
  if (!currentReadKey.secret) {
285
318
  throw new Error("Can't add member without read key secret");
@@ -306,7 +339,7 @@ export class RawGroup<
306
339
 
307
340
  if (role === "writeOnly") {
308
341
  if (previousRole === "reader" || previousRole === "writer") {
309
- this.rotateReadKey();
342
+ this.rotateReadKey("everyone");
310
343
  }
311
344
 
312
345
  this.delete(`${currentReadKey.id}_for_${EVERYONE}`);
@@ -349,7 +382,7 @@ export class RawGroup<
349
382
 
350
383
  this.internalCreateWriteOnlyKeyForMember(memberKey, agent);
351
384
  } else {
352
- const currentReadKey = this.core.getCurrentReadKey();
385
+ const currentReadKey = this.getCurrentReadKey();
353
386
 
354
387
  if (!currentReadKey.secret) {
355
388
  throw new Error("Can't add member without read key secret");
@@ -467,6 +500,10 @@ export class RawGroup<
467
500
  }
468
501
 
469
502
  getCurrentReadKeyId() {
503
+ if (this._lastReadableKeyId) {
504
+ return this._lastReadableKeyId;
505
+ }
506
+
470
507
  const myRole = this.myRole();
471
508
 
472
509
  if (myRole === "writeOnly") {
@@ -518,23 +555,173 @@ export class RawGroup<
518
555
  return memberKeys;
519
556
  }
520
557
 
558
+ getReadKey(keyID: KeyID): KeySecret | undefined {
559
+ const cache = this.core.readKeyCache;
560
+
561
+ let key = cache.get(keyID);
562
+ if (!key) {
563
+ key = this.getUncachedReadKey(keyID);
564
+ if (key) {
565
+ cache.set(keyID, key);
566
+ }
567
+ }
568
+ return key;
569
+ }
570
+
571
+ getUncachedReadKey(keyID: KeyID) {
572
+ const core = this.core;
573
+
574
+ const keyForEveryone = this.get(`${keyID}_for_everyone`);
575
+ if (keyForEveryone) {
576
+ return keyForEveryone;
577
+ }
578
+
579
+ // Try to find key revelation for us
580
+ const currentAgentOrAccountID = accountOrAgentIDfromSessionID(
581
+ core.node.currentSessionID,
582
+ );
583
+
584
+ // being careful here to avoid recursion
585
+ const lookupAccountOrAgentID = isAccountID(currentAgentOrAccountID)
586
+ ? core.id === currentAgentOrAccountID
587
+ ? core.node.crypto.getAgentID(core.node.agentSecret) // in accounts, the read key is revealed for the primitive agent
588
+ : currentAgentOrAccountID // current account ID
589
+ : currentAgentOrAccountID; // current agent ID
590
+
591
+ const lastReadyKeyEdit = this.lastEditAt(
592
+ `${keyID}_for_${lookupAccountOrAgentID}`,
593
+ );
594
+
595
+ if (lastReadyKeyEdit?.value) {
596
+ const revealer = lastReadyKeyEdit.by;
597
+ const revealerAgent = core.node
598
+ .resolveAccountAgent(revealer, "Expected to know revealer")
599
+ ._unsafeUnwrap({ withStackTrace: true });
600
+
601
+ const secret = this.crypto.unseal(
602
+ lastReadyKeyEdit.value,
603
+ this.crypto.getAgentSealerSecret(core.node.agentSecret), // being careful here to avoid recursion
604
+ this.crypto.getAgentSealerID(revealerAgent),
605
+ {
606
+ in: this.id,
607
+ tx: lastReadyKeyEdit.tx,
608
+ },
609
+ );
610
+
611
+ if (secret) {
612
+ return secret as KeySecret;
613
+ }
614
+ }
615
+
616
+ // Try to find indirect revelation through previousKeys
617
+ for (const co of this.keys()) {
618
+ if (isKeyForKeyField(co) && co.startsWith(keyID)) {
619
+ const encryptingKeyID = co.split("_for_")[1] as KeyID;
620
+ const encryptingKeySecret = this.getReadKey(encryptingKeyID);
621
+
622
+ if (!encryptingKeySecret) {
623
+ continue;
624
+ }
625
+
626
+ const encryptedPreviousKey = this.get(co)!;
627
+
628
+ const secret = this.crypto.decryptKeySecret(
629
+ {
630
+ encryptedID: keyID,
631
+ encryptingID: encryptingKeyID,
632
+ encrypted: encryptedPreviousKey,
633
+ },
634
+ encryptingKeySecret,
635
+ );
636
+
637
+ if (secret) {
638
+ return secret as KeySecret;
639
+ } else {
640
+ logger.warn(
641
+ `Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
642
+ );
643
+ }
644
+ }
645
+ }
646
+
647
+ // try to find revelation to parent group read keys
648
+ for (const co of this.keys()) {
649
+ if (isParentGroupReference(co)) {
650
+ const parentGroupID = getParentGroupId(co);
651
+ const parentGroup = core.node.expectCoValueLoaded(
652
+ parentGroupID,
653
+ "Expected parent group to be loaded",
654
+ );
655
+
656
+ const parentKeys = this.findValidParentKeys(keyID, parentGroup);
657
+
658
+ for (const parentKey of parentKeys) {
659
+ const revelationForParentKey = this.get(
660
+ `${keyID}_for_${parentKey.id}`,
661
+ );
662
+
663
+ if (revelationForParentKey) {
664
+ const secret = parentGroup.node.crypto.decryptKeySecret(
665
+ {
666
+ encryptedID: keyID,
667
+ encryptingID: parentKey.id,
668
+ encrypted: revelationForParentKey,
669
+ },
670
+ parentKey.secret,
671
+ );
672
+
673
+ if (secret) {
674
+ return secret as KeySecret;
675
+ } else {
676
+ logger.warn(
677
+ `Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`,
678
+ );
679
+ }
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ return undefined;
686
+ }
687
+
688
+ findValidParentKeys(keyID: KeyID, parentGroup: CoValueCore) {
689
+ const validParentKeys: { id: KeyID; secret: KeySecret }[] = [];
690
+
691
+ for (const co of this.keys()) {
692
+ if (isKeyForKeyField(co) && co.startsWith(keyID)) {
693
+ const encryptingKeyID = co.split("_for_")[1] as KeyID;
694
+ const encryptingKeySecret = parentGroup.getReadKey(encryptingKeyID);
695
+
696
+ if (!encryptingKeySecret) {
697
+ continue;
698
+ }
699
+
700
+ validParentKeys.push({
701
+ id: encryptingKeyID,
702
+ secret: encryptingKeySecret,
703
+ });
704
+ }
705
+ }
706
+
707
+ return validParentKeys;
708
+ }
709
+
521
710
  /** @internal */
522
711
  rotateReadKey(removedMemberKey?: RawAccountID | AgentID | "everyone") {
712
+ if (removedMemberKey !== EVERYONE && canRead(this, EVERYONE)) {
713
+ // When everyone has access to the group, rotating the key is useless
714
+ // because it would be stored unencrypted and available to everyone
715
+ return;
716
+ }
717
+
523
718
  const memberKeys = this.getMemberKeys().filter(
524
719
  (key) => key !== removedMemberKey,
525
720
  );
526
721
 
527
- const currentlyPermittedReaders = memberKeys.filter((key) => {
528
- const role = this.get(key);
529
- return (
530
- role === "admin" ||
531
- role === "writer" ||
532
- role === "reader" ||
533
- role === "adminInvite" ||
534
- role === "writerInvite" ||
535
- role === "readerInvite"
536
- );
537
- });
722
+ const currentlyPermittedReaders = memberKeys.filter((key) =>
723
+ canRead(this, key),
724
+ );
538
725
 
539
726
  const writeOnlyMembers = memberKeys.filter((key) => {
540
727
  const role = this.get(key);
@@ -543,12 +730,12 @@ export class RawGroup<
543
730
 
544
731
  // Get these early, so we fail fast if they are unavailable
545
732
  const parentGroups = this.getParentGroups();
546
- const childGroups = this.getChildGroups();
547
-
548
- const maybeCurrentReadKey = this.core.getCurrentReadKey();
733
+ const maybeCurrentReadKey = this.getCurrentReadKey();
549
734
 
550
735
  if (!maybeCurrentReadKey.secret) {
551
- throw new Error("Can't rotate read key secret we don't have access to");
736
+ throw new NoReadKeyAccessError(
737
+ "Can't rotate read key secret we don't have access to",
738
+ );
552
739
  }
553
740
 
554
741
  const currentReadKey = {
@@ -631,7 +818,7 @@ export class RawGroup<
631
818
  */
632
819
  for (const parent of parentGroups) {
633
820
  const { id: parentReadKeyID, secret: parentReadKeySecret } =
634
- parent.core.getCurrentReadKey();
821
+ parent.getCurrentReadKey();
635
822
 
636
823
  if (!parentReadKeySecret) {
637
824
  // We can't reveal the new child key to the parent group where we don't have access to the parent read key
@@ -655,16 +842,26 @@ export class RawGroup<
655
842
  );
656
843
  }
657
844
 
658
- for (const child of childGroups) {
845
+ this.forEachChildGroup((child) => {
659
846
  // Since child references are mantained only for the key rotation,
660
847
  // circular references are skipped here because it's more performant
661
848
  // than always checking for circular references in childs inside the permission checks
662
849
  if (child.isSelfExtension(this)) {
663
- continue;
850
+ return;
664
851
  }
665
852
 
666
- child.rotateReadKey(removedMemberKey);
667
- }
853
+ try {
854
+ child.rotateReadKey(removedMemberKey);
855
+ } catch (error) {
856
+ if (error instanceof NoReadKeyAccessError) {
857
+ logger.warn(
858
+ `Can't rotate read key on child ${child.id} because we don't have access to the read key`,
859
+ );
860
+ } else {
861
+ throw error;
862
+ }
863
+ }
864
+ });
668
865
  }
669
866
 
670
867
  /** Detect circular references in group inheritance */
@@ -695,6 +892,19 @@ export class RawGroup<
695
892
  }
696
893
  }
697
894
 
895
+ getCurrentReadKey() {
896
+ const keyId = this.getCurrentReadKeyId();
897
+
898
+ if (!keyId) {
899
+ throw new Error("No readKey set");
900
+ }
901
+
902
+ return {
903
+ secret: this.getReadKey(keyId),
904
+ id: keyId,
905
+ };
906
+ }
907
+
698
908
  extend(
699
909
  parent: RawGroup,
700
910
  role: "reader" | "writer" | "admin" | "inherit" = "inherit",
@@ -727,14 +937,15 @@ export class RawGroup<
727
937
  );
728
938
  }
729
939
 
730
- const { id: parentReadKeyID, secret: parentReadKeySecret } =
731
- parent.core.getCurrentReadKey();
940
+ let { id: parentReadKeyID, secret: parentReadKeySecret } =
941
+ parent.getCurrentReadKey();
942
+
732
943
  if (!parentReadKeySecret) {
733
944
  throw new Error("Can't extend group without parent read key secret");
734
945
  }
735
946
 
736
947
  const { id: childReadKeyID, secret: childReadKeySecret } =
737
- this.core.getCurrentReadKey();
948
+ this.getCurrentReadKey();
738
949
  if (!childReadKeySecret) {
739
950
  throw new Error("Can't extend group without child read key secret");
740
951
  }
@@ -755,7 +966,7 @@ export class RawGroup<
755
966
  );
756
967
  }
757
968
 
758
- async revokeExtend(parent: RawGroup) {
969
+ revokeExtend(parent: RawGroup) {
759
970
  if (this.myRole() !== "admin") {
760
971
  throw new Error(
761
972
  "To unextend a group, the current account must be an admin in the child group",
@@ -786,8 +997,6 @@ export class RawGroup<
786
997
  // Set the child key on the parent group to `revoked`
787
998
  parent.set(`child_${this.id}`, "revoked", "trusting");
788
999
 
789
- await this.loadAllChildGroups();
790
-
791
1000
  // Rotate the keys on the child group
792
1001
  this.rotateReadKey();
793
1002
  }
@@ -799,19 +1008,7 @@ export class RawGroup<
799
1008
  *
800
1009
  * @category 2. Role changing
801
1010
  */
802
- async removeMember(
803
- account: RawAccount | ControlledAccountOrAgent | Everyone,
804
- ) {
805
- // Ensure all child groups are loaded before removing a member
806
- await this.loadAllChildGroups();
807
-
808
- this.removeMemberInternal(account);
809
- }
810
-
811
- /** @internal */
812
- removeMemberInternal(
813
- account: RawAccount | ControlledAccountOrAgent | AgentID | Everyone,
814
- ) {
1011
+ removeMember(account: RawAccount | ControlledAccountOrAgent | Everyone) {
815
1012
  const memberKey = typeof account === "string" ? account : account.id;
816
1013
 
817
1014
  if (this.myRole() === "admin") {
@@ -1022,3 +1219,25 @@ export function secretSeedFromInviteSecret(inviteSecret: InviteSecret) {
1022
1219
 
1023
1220
  return base58.decode(inviteSecret.slice("inviteSecret_z".length));
1024
1221
  }
1222
+
1223
+ const canRead = (
1224
+ group: RawGroup,
1225
+ key: RawAccountID | AgentID | "everyone",
1226
+ ): boolean => {
1227
+ const role = group.get(key);
1228
+ return (
1229
+ role === "admin" ||
1230
+ role === "writer" ||
1231
+ role === "reader" ||
1232
+ role === "adminInvite" ||
1233
+ role === "writerInvite" ||
1234
+ role === "readerInvite"
1235
+ );
1236
+ };
1237
+
1238
+ class NoReadKeyAccessError extends Error {
1239
+ constructor(message: string) {
1240
+ super(message);
1241
+ this.name = "NoReadKeyAccessError";
1242
+ }
1243
+ }
package/src/ids.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { base58 } from "@scure/base";
2
- import { CoID } from "./coValue.js";
3
- import { RawAccountID } from "./coValues/account.js";
2
+ import type { CoID } from "./coValue.js";
3
+ import type { RawAccountID } from "./coValues/account.js";
4
+ import type { RawGroup } from "./coValues/group.js";
4
5
  import { shortHashLength } from "./crypto/crypto.js";
5
- import { RawGroup } from "./exports.js";
6
6
 
7
7
  export type RawCoID = `co_z${string}`;
8
8
  export type ParentGroupReference = `parent_${CoID<RawGroup>}`;
package/src/localNode.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { Result, err, ok } from "neverthrow";
2
- import { CoID } from "./coValue.js";
3
- import { RawCoValue } from "./coValue.js";
2
+ import type { CoID } from "./coValue.js";
3
+ import type { RawCoValue } from "./coValue.js";
4
4
  import {
5
- AvailableCoValueCore,
5
+ type AvailableCoValueCore,
6
6
  CoValueCore,
7
7
  idforHeader,
8
8
  } from "./coValueCore/coValueCore.js";
9
9
  import {
10
- CoValueHeader,
11
- CoValueUniqueness,
10
+ type CoValueHeader,
11
+ type CoValueUniqueness,
12
12
  VerifiedState,
13
13
  } from "./coValueCore/verifiedState.js";
14
14
  import {
@@ -26,8 +26,8 @@ import {
26
26
  expectAccount,
27
27
  } from "./coValues/account.js";
28
28
  import {
29
- InviteSecret,
30
- RawGroup,
29
+ type InviteSecret,
30
+ type RawGroup,
31
31
  secretSeedFromInviteSecret,
32
32
  } from "./coValues/group.js";
33
33
  import { CO_VALUE_LOADING_CONFIG } from "./config.js";