cojson 0.17.9 → 0.17.11

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 (86) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/coValueCore/SessionMap.d.ts +45 -0
  4. package/dist/coValueCore/SessionMap.d.ts.map +1 -0
  5. package/dist/coValueCore/SessionMap.js +118 -0
  6. package/dist/coValueCore/SessionMap.js.map +1 -0
  7. package/dist/coValueCore/coValueCore.d.ts +10 -4
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +55 -68
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/verifiedState.d.ts +15 -19
  12. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  13. package/dist/coValueCore/verifiedState.js +24 -87
  14. package/dist/coValueCore/verifiedState.js.map +1 -1
  15. package/dist/coValues/account.d.ts +4 -0
  16. package/dist/coValues/account.d.ts.map +1 -1
  17. package/dist/coValues/account.js +24 -4
  18. package/dist/coValues/account.js.map +1 -1
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +6 -2
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/crypto/PureJSCrypto.d.ts +31 -3
  23. package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
  24. package/dist/crypto/PureJSCrypto.js +115 -0
  25. package/dist/crypto/PureJSCrypto.js.map +1 -1
  26. package/dist/crypto/WasmCrypto.d.ts +23 -4
  27. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  28. package/dist/crypto/WasmCrypto.js +44 -2
  29. package/dist/crypto/WasmCrypto.js.map +1 -1
  30. package/dist/crypto/crypto.d.ts +17 -1
  31. package/dist/crypto/crypto.d.ts.map +1 -1
  32. package/dist/crypto/crypto.js.map +1 -1
  33. package/dist/localNode.d.ts +1 -0
  34. package/dist/localNode.d.ts.map +1 -1
  35. package/dist/localNode.js +10 -5
  36. package/dist/localNode.js.map +1 -1
  37. package/dist/permissions.d.ts +17 -1
  38. package/dist/permissions.d.ts.map +1 -1
  39. package/dist/permissions.js.map +1 -1
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +55 -49
  42. package/dist/sync.js.map +1 -1
  43. package/dist/tests/PureJSCrypto.test.d.ts +2 -0
  44. package/dist/tests/PureJSCrypto.test.d.ts.map +1 -0
  45. package/dist/tests/PureJSCrypto.test.js +102 -0
  46. package/dist/tests/PureJSCrypto.test.js.map +1 -0
  47. package/dist/tests/WasmCrypto.test.d.ts +2 -0
  48. package/dist/tests/WasmCrypto.test.d.ts.map +1 -0
  49. package/dist/tests/WasmCrypto.test.js +88 -0
  50. package/dist/tests/WasmCrypto.test.js.map +1 -0
  51. package/dist/tests/coValueCore.test.js +62 -187
  52. package/dist/tests/coValueCore.test.js.map +1 -1
  53. package/dist/tests/coreWasm.test.d.ts +2 -0
  54. package/dist/tests/coreWasm.test.d.ts.map +1 -0
  55. package/dist/tests/coreWasm.test.js +80 -0
  56. package/dist/tests/coreWasm.test.js.map +1 -0
  57. package/dist/tests/group.addMember.test.js +6 -11
  58. package/dist/tests/group.addMember.test.js.map +1 -1
  59. package/dist/tests/sync.load.test.js +40 -1
  60. package/dist/tests/sync.load.test.js.map +1 -1
  61. package/dist/tests/sync.test.js +1 -1
  62. package/dist/tests/sync.test.js.map +1 -1
  63. package/dist/tests/testUtils.d.ts +3 -0
  64. package/dist/tests/testUtils.d.ts.map +1 -1
  65. package/dist/tests/testUtils.js +4 -1
  66. package/dist/tests/testUtils.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/coValueCore/SessionMap.ts +229 -0
  69. package/src/coValueCore/coValueCore.ts +106 -121
  70. package/src/coValueCore/verifiedState.ts +61 -132
  71. package/src/coValues/account.ts +28 -4
  72. package/src/coValues/group.ts +10 -2
  73. package/src/crypto/PureJSCrypto.ts +206 -2
  74. package/src/crypto/WasmCrypto.ts +95 -4
  75. package/src/crypto/crypto.ts +38 -1
  76. package/src/localNode.ts +18 -10
  77. package/src/permissions.ts +17 -1
  78. package/src/sync.ts +63 -59
  79. package/src/tests/PureJSCrypto.test.ts +153 -0
  80. package/src/tests/WasmCrypto.test.ts +128 -0
  81. package/src/tests/coValueCore.test.ts +81 -293
  82. package/src/tests/coreWasm.test.ts +142 -0
  83. package/src/tests/group.addMember.test.ts +69 -63
  84. package/src/tests/sync.load.test.ts +52 -0
  85. package/src/tests/sync.test.ts +0 -2
  86. package/src/tests/testUtils.ts +9 -1
@@ -0,0 +1,142 @@
1
+ import { assert, describe, expect, it } from "vitest";
2
+ import { WasmCrypto } from "../crypto/WasmCrypto";
3
+ import { JsonValue, LocalNode, SessionID } from "../exports";
4
+ import {
5
+ agentAndSessionIDFromSecret,
6
+ randomAgentAndSessionID,
7
+ } from "./testUtils";
8
+ import { PureJSCrypto } from "../crypto/PureJSCrypto";
9
+ import { Encrypted } from "../crypto/crypto";
10
+ import { PrivateTransaction } from "../coValueCore/verifiedState";
11
+
12
+ const wasmCrypto = await WasmCrypto.create();
13
+ const jsCrypto = await PureJSCrypto.create();
14
+
15
+ const agentSecret =
16
+ "sealerSecret_zE3Nr7YFr1KkVbJSx4JDCzYn4ApYdm8kJ5ghNBxREHQya/signerSecret_z9fEu4eNG1eXHMak3YSzY7uLdoG8HESSJ8YW4xWdNNDSP";
17
+
18
+ function createTestNode() {
19
+ const [agent, session] = agentAndSessionIDFromSecret(agentSecret);
20
+ return {
21
+ agent,
22
+ session,
23
+ node: new LocalNode(agent.agentSecret, session, jsCrypto),
24
+ };
25
+ }
26
+
27
+ describe("SessionLog WASM", () => {
28
+ it("it works", () => {
29
+ const [agent, sessionId] = agentAndSessionIDFromSecret(agentSecret);
30
+
31
+ const session = wasmCrypto.createSessionLog(
32
+ "co_test1" as any,
33
+ sessionId,
34
+ agent.currentSignerID(),
35
+ );
36
+
37
+ expect(session).toBeDefined();
38
+ });
39
+
40
+ it("test_add_from_example_json", () => {
41
+ const { agent, session, node } = createTestNode();
42
+
43
+ const group = node.createGroup();
44
+ const sessionContent =
45
+ group.core.verified.newContentSince(undefined)?.[0]?.new[session];
46
+ assert(sessionContent);
47
+
48
+ let log = wasmCrypto.createSessionLog(
49
+ group.id,
50
+ session,
51
+ agent.currentSignerID(),
52
+ );
53
+
54
+ log.tryAdd(
55
+ sessionContent.newTransactions,
56
+ sessionContent.lastSignature,
57
+ false,
58
+ );
59
+ });
60
+
61
+ it("test_add_new_transaction", () => {
62
+ const { agent, session, node } = createTestNode();
63
+
64
+ const group = node.createGroup();
65
+ const sessionContent =
66
+ group.core.verified.newContentSince(undefined)?.[0]?.new[session];
67
+ assert(sessionContent);
68
+
69
+ let log = wasmCrypto.createSessionLog(
70
+ group.id,
71
+ session,
72
+ agent.currentSignerID(),
73
+ );
74
+
75
+ const changesJson = [
76
+ { after: "start", op: "app", value: "co_zMphsnYN6GU8nn2HDY5suvyGufY" },
77
+ ];
78
+ const key = group.getCurrentReadKey();
79
+ assert(key);
80
+ assert(key.secret);
81
+
82
+ const { signature, transaction } = log.addNewPrivateTransaction(
83
+ agent,
84
+ changesJson,
85
+ key.id,
86
+ key.secret,
87
+ 0,
88
+ );
89
+
90
+ expect(signature).toMatch(/^signature_z[a-zA-Z0-9]+$/);
91
+ expect(transaction).toEqual({
92
+ encryptedChanges: expect.stringMatching(/^encrypted_U/),
93
+ keyUsed: expect.stringMatching(/^key_z/),
94
+ madeAt: 0,
95
+ privacy: "private",
96
+ });
97
+
98
+ const decrypted = log.decryptNextTransactionChangesJson(0, key.secret);
99
+
100
+ expect(decrypted).toEqual(
101
+ '[{"after":"start","op":"app","value":"co_zMphsnYN6GU8nn2HDY5suvyGufY"}]',
102
+ );
103
+ });
104
+
105
+ it("test_decrypt + clone", () => {
106
+ const [agent] = agentAndSessionIDFromSecret(agentSecret);
107
+ const fixtures = {
108
+ id: "co_zWwrEiushQLvbkWd6Z3L8WxTU1r",
109
+ signature:
110
+ "signature_z3ktW7wxMnW7VYExCGZv4Ug2UJSW3ag6zLDiP8GpZThzif6veJt7JipYpUgshhuGbgHtLcWywWSWysV7hChxFypDt",
111
+ decrypted:
112
+ '[{"after":"start","op":"app","value":"co_zMphsnYN6GU8nn2HDY5suvyGufY"}]',
113
+ key: {
114
+ secret: "keySecret_z3dU66SsyQkkGKpNCJW6NX74MnfVGHUyY7r85b4M8X88L",
115
+ id: "key_z5XUAHyoqUV9zXWvMK",
116
+ },
117
+ transaction: {
118
+ privacy: "private",
119
+ madeAt: 0,
120
+ encryptedChanges:
121
+ "encrypted_UNAxqdUSGRZ2rzuLU99AFPKCe2C0HwsTzMWQreXZqLr6RpWrSMa-5lwgwIev7xPHTgZFq5UyUgMFrO9zlHJHJGgjJcDzFihY=" as any,
122
+ keyUsed: "key_z5XUAHyoqUV9zXWvMK",
123
+ },
124
+ session:
125
+ "sealer_z5yhsCCe2XwLTZC4254mUoMASshm3Diq49JrefPpjTktp/signer_z7gVGDpNz9qUtsRxAkHMuu4DYdtVVCG4XELTKPYdoYLPr_session_z9mDP8FoonSA",
126
+ } as const;
127
+
128
+ let log = wasmCrypto.createSessionLog(
129
+ fixtures.id,
130
+ fixtures.session,
131
+ agent.currentSignerID(),
132
+ );
133
+
134
+ log.tryAdd([fixtures.transaction], fixtures.signature, true);
135
+
136
+ const decrypted = log
137
+ .clone()
138
+ .decryptNextTransactionChangesJson(0, fixtures.key.secret);
139
+
140
+ expect(decrypted).toEqual(fixtures.decrypted);
141
+ });
142
+ });
@@ -2,7 +2,6 @@ import { beforeEach, describe, expect, test } from "vitest";
2
2
  import { expectMap } from "../coValue.js";
3
3
  import {
4
4
  SyncMessagesLog,
5
- TEST_NODE_CONFIG,
6
5
  loadCoValueOrFail,
7
6
  setupTestAccount,
8
7
  setupTestNode,
@@ -220,68 +219,75 @@ describe("Group.addMember", () => {
220
219
  expect(personOnReaderNode.get("name")).toEqual(undefined);
221
220
  });
222
221
 
223
- test("an admin should not be able downgrade an admin", async () => {
224
- const admin = await setupTestAccount({
225
- connected: true,
226
- });
227
-
228
- const otherAdmin = await setupTestAccount({
229
- connected: true,
230
- });
231
-
232
- const group = admin.node.createGroup();
233
- const person = group.createMap({
234
- name: "John Doe",
235
- });
236
-
237
- const otherAdminOnAdminNode = await loadCoValueOrFail(
238
- admin.node,
239
- otherAdmin.accountID,
240
- );
241
- group.addMember(otherAdminOnAdminNode, "admin");
242
-
243
- // Try to downgrade other admin
244
- try {
245
- group.addMember(otherAdminOnAdminNode, "writer");
246
- } catch (e) {
247
- expect(e).toBeDefined();
248
- }
249
-
250
- expect(group.roleOf(otherAdmin.accountID)).toEqual("admin");
251
-
252
- // Verify other admin still has admin access by adding a new member
253
- const reader = await setupTestAccount({
254
- connected: true,
255
- });
256
-
257
- const readerOnOtherAdminNode = await loadCoValueOrFail(
258
- otherAdmin.node,
259
- reader.accountID,
260
- );
261
- group.addMember(readerOnOtherAdminNode, "reader");
262
-
263
- const personOnReaderNode = await loadCoValueOrFail(reader.node, person.id);
264
-
265
- await waitFor(() => {
266
- expect(
267
- expectMap(personOnReaderNode.core.getCurrentContent()).get("name"),
268
- ).toEqual("John Doe");
269
- });
270
- });
271
-
272
- test("an admin should be able downgrade themselves", async () => {
273
- const admin = await setupTestAccount({
274
- connected: true,
275
- });
276
-
277
- const group = admin.node.createGroup();
278
-
279
- const account = await loadCoValueOrFail(admin.node, admin.accountID);
280
-
281
- // Downgrade self to writer
282
- group.addMember(account, "writer");
283
- expect(group.roleOf(admin.accountID)).toEqual("writer");
284
- });
222
+ test.each(["writer", "reader", "writeOnly"] as const)(
223
+ "an admin should not be able to downgrade an admin to %s",
224
+ async (targetRole) => {
225
+ const admin = await setupTestAccount({
226
+ connected: true,
227
+ });
228
+
229
+ const otherAdmin = await setupTestAccount({
230
+ connected: true,
231
+ });
232
+
233
+ const group = admin.node.createGroup();
234
+ const person = group.createMap({
235
+ name: "John Doe",
236
+ });
237
+
238
+ const otherAdminOnAdminNode = await loadCoValueOrFail(
239
+ admin.node,
240
+ otherAdmin.accountID,
241
+ );
242
+ group.addMember(otherAdminOnAdminNode, "admin");
243
+
244
+ // Try to downgrade other admin
245
+ expect(() => group.addMember(otherAdminOnAdminNode, targetRole)).toThrow(
246
+ "Administrators cannot demote other administrators in a group",
247
+ );
248
+
249
+ expect(group.roleOf(otherAdmin.accountID)).toEqual("admin");
250
+
251
+ // Verify other admin still has admin access by adding a new member
252
+ const reader = await setupTestAccount({
253
+ connected: true,
254
+ });
255
+
256
+ const readerOnOtherAdminNode = await loadCoValueOrFail(
257
+ otherAdmin.node,
258
+ reader.accountID,
259
+ );
260
+ group.addMember(readerOnOtherAdminNode, "reader");
261
+
262
+ const personOnReaderNode = await loadCoValueOrFail(
263
+ reader.node,
264
+ person.id,
265
+ );
266
+
267
+ await waitFor(() => {
268
+ expect(
269
+ expectMap(personOnReaderNode.core.getCurrentContent()).get("name"),
270
+ ).toEqual("John Doe");
271
+ });
272
+ },
273
+ );
274
+
275
+ test.each(["writer", "reader", "writeOnly"] as const)(
276
+ "an admin should be able downgrade themselves to %s",
277
+ async (targetRole) => {
278
+ const admin = await setupTestAccount({
279
+ connected: true,
280
+ });
281
+
282
+ const group = admin.node.createGroup();
283
+
284
+ const account = await loadCoValueOrFail(admin.node, admin.accountID);
285
+
286
+ // Downgrade self to target role
287
+ group.addMember(account, targetRole);
288
+ expect(group.roleOf(admin.accountID)).toEqual(targetRole);
289
+ },
290
+ );
285
291
 
286
292
  test("an admin should be able downgrade a writeOnly to reader", async () => {
287
293
  const admin = await setupTestAccount({
@@ -9,6 +9,7 @@ import {
9
9
  SyncMessagesLog,
10
10
  TEST_NODE_CONFIG,
11
11
  blockMessageTypeOnOutgoingPeer,
12
+ getSyncServerConnectedPeer,
12
13
  loadCoValueOrFail,
13
14
  setupTestAccount,
14
15
  setupTestNode,
@@ -1034,4 +1035,55 @@ describe("loading coValues from server", () => {
1034
1035
 
1035
1036
  vi.useRealTimers();
1036
1037
  });
1038
+
1039
+ test("should not request dependencies if transaction verification is disabled", async () => {
1040
+ // Create a disconnected client
1041
+ const { node: client, accountID } = await setupTestAccount({
1042
+ connected: false,
1043
+ });
1044
+ const account = client.expectCurrentAccount(accountID);
1045
+
1046
+ // Prepare a group -- this will be a non-account dependency of a forthcoming map.
1047
+ const group = client.createGroup();
1048
+ group.addMember("everyone", "writer");
1049
+
1050
+ // Create a sync server and disable transaction verification
1051
+ const syncServer = await setupTestAccount({ isSyncServer: true });
1052
+ syncServer.node.syncManager.disableTransactionVerification();
1053
+
1054
+ // Connect the client, but don't setup syncing just yet...
1055
+ const { peer } = getSyncServerConnectedPeer({
1056
+ peerId: client.getCurrentAgent().id,
1057
+ syncServer: syncServer.node,
1058
+ });
1059
+
1060
+ // Disable reconciliation while we setup syncing because we don't want the
1061
+ // server to know about our forthcoming map's dependencies (group + account).
1062
+ const blocker = blockMessageTypeOnOutgoingPeer(peer, "load", {});
1063
+ client.syncManager.addPeer(peer);
1064
+ blocker.unblock();
1065
+
1066
+ // Create a map and set a value on it.
1067
+ // If transaction verification were enabled, this would trigger LOAD messages
1068
+ // from the server to the client asking for the group and account. However, we
1069
+ // don't expect to see those messages since we disabled transaction verification.
1070
+ const map = group.createMap();
1071
+ map.set("hello", "world");
1072
+ await map.core.waitForSync();
1073
+
1074
+ const syncMessages = SyncMessagesLog.getMessages({
1075
+ Account: account.core,
1076
+ Group: group.core,
1077
+ Map: map.core,
1078
+ });
1079
+ expect(
1080
+ syncMessages.some(
1081
+ (msg) => msg.includes("LOAD Account") || msg.includes("LOAD Group"),
1082
+ ),
1083
+ ).toBe(false);
1084
+
1085
+ // Verify the map is available on the server (transaction was accepted)
1086
+ const mapOnServerCore = await syncServer.node.loadCoValueCore(map.core.id);
1087
+ expect(mapOnServerCore.isAvailable()).toBe(true);
1088
+ });
1037
1089
  });
@@ -180,9 +180,7 @@ test("should not verify transactions when SyncManager has verification disabled"
180
180
  madeAt: Date.now(),
181
181
  },
182
182
  ],
183
- undefined,
184
183
  Crypto.sign(agent.currentSignerSecret(), "hash_z12345678"),
185
- "immediate",
186
184
  true,
187
185
  );
188
186
 
@@ -12,6 +12,7 @@ import {
12
12
  type AgentSecret,
13
13
  type CoID,
14
14
  type CoValueCore,
15
+ CryptoProvider,
15
16
  type RawAccount,
16
17
  type RawCoValue,
17
18
  StorageAPI,
@@ -23,8 +24,15 @@ import type { Peer, SyncMessage } from "../sync.js";
23
24
  import { expectGroup } from "../typeUtils/expectGroup.js";
24
25
  import { toSimplifiedMessages } from "./messagesTestUtils.js";
25
26
  import { createAsyncStorage, createSyncStorage } from "./testStorage.js";
27
+ import { PureJSCrypto } from "../crypto/PureJSCrypto.js";
26
28
 
27
- const Crypto = await WasmCrypto.create();
29
+ let Crypto = await WasmCrypto.create();
30
+
31
+ export function setCurrentTestCryptoProvider(
32
+ crypto: WasmCrypto | PureJSCrypto,
33
+ ) {
34
+ Crypto = crypto;
35
+ }
28
36
 
29
37
  const syncServer: {
30
38
  current: undefined | LocalNode;