cojson 0.9.9 → 0.9.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 (114) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/CHANGELOG.md +13 -0
  3. package/dist/native/PeerState.js +2 -1
  4. package/dist/native/PeerState.js.map +1 -1
  5. package/dist/native/PriorityBasedMessageQueue.js +54 -7
  6. package/dist/native/PriorityBasedMessageQueue.js.map +1 -1
  7. package/dist/native/base64url.js +0 -6
  8. package/dist/native/base64url.js.map +1 -1
  9. package/dist/native/coValue.js +27 -0
  10. package/dist/native/coValue.js.map +1 -1
  11. package/dist/native/coValueCore.js +30 -177
  12. package/dist/native/coValueCore.js.map +1 -1
  13. package/dist/native/coValueState.js +5 -4
  14. package/dist/native/coValueState.js.map +1 -1
  15. package/dist/native/coValues/account.js +2 -1
  16. package/dist/native/coValues/account.js.map +1 -1
  17. package/dist/native/coValues/coList.js +0 -7
  18. package/dist/native/coValues/coList.js.map +1 -1
  19. package/dist/native/coValues/coStream.js +3 -8
  20. package/dist/native/coValues/coStream.js.map +1 -1
  21. package/dist/native/coValues/group.js +3 -2
  22. package/dist/native/coValues/group.js.map +1 -1
  23. package/dist/native/coreToCoValue.js +2 -1
  24. package/dist/native/coreToCoValue.js.map +1 -1
  25. package/dist/native/crypto/PureJSCrypto.js +2 -1
  26. package/dist/native/crypto/PureJSCrypto.js.map +1 -1
  27. package/dist/native/crypto/WasmCrypto.js +2 -1
  28. package/dist/native/crypto/WasmCrypto.js.map +1 -1
  29. package/dist/native/crypto/crypto.js +2 -4
  30. package/dist/native/crypto/crypto.js.map +1 -1
  31. package/dist/native/exports.js +2 -1
  32. package/dist/native/exports.js.map +1 -1
  33. package/dist/native/localNode.js +5 -6
  34. package/dist/native/localNode.js.map +1 -1
  35. package/dist/native/logger.js +58 -0
  36. package/dist/native/logger.js.map +1 -0
  37. package/dist/native/permissions.js +3 -4
  38. package/dist/native/permissions.js.map +1 -1
  39. package/dist/native/storage/FileSystem.js +0 -10
  40. package/dist/native/storage/FileSystem.js.map +1 -1
  41. package/dist/native/storage/index.js +14 -23
  42. package/dist/native/storage/index.js.map +1 -1
  43. package/dist/native/sync.js +20 -28
  44. package/dist/native/sync.js.map +1 -1
  45. package/dist/web/PeerState.js +2 -1
  46. package/dist/web/PeerState.js.map +1 -1
  47. package/dist/web/PriorityBasedMessageQueue.js +54 -7
  48. package/dist/web/PriorityBasedMessageQueue.js.map +1 -1
  49. package/dist/web/base64url.js +0 -6
  50. package/dist/web/base64url.js.map +1 -1
  51. package/dist/web/coValue.js +27 -0
  52. package/dist/web/coValue.js.map +1 -1
  53. package/dist/web/coValueCore.js +30 -177
  54. package/dist/web/coValueCore.js.map +1 -1
  55. package/dist/web/coValueState.js +5 -4
  56. package/dist/web/coValueState.js.map +1 -1
  57. package/dist/web/coValues/account.js +2 -1
  58. package/dist/web/coValues/account.js.map +1 -1
  59. package/dist/web/coValues/coList.js +0 -7
  60. package/dist/web/coValues/coList.js.map +1 -1
  61. package/dist/web/coValues/coStream.js +3 -8
  62. package/dist/web/coValues/coStream.js.map +1 -1
  63. package/dist/web/coValues/group.js +3 -2
  64. package/dist/web/coValues/group.js.map +1 -1
  65. package/dist/web/coreToCoValue.js +2 -1
  66. package/dist/web/coreToCoValue.js.map +1 -1
  67. package/dist/web/crypto/PureJSCrypto.js +2 -1
  68. package/dist/web/crypto/PureJSCrypto.js.map +1 -1
  69. package/dist/web/crypto/WasmCrypto.js +2 -1
  70. package/dist/web/crypto/WasmCrypto.js.map +1 -1
  71. package/dist/web/crypto/crypto.js +2 -4
  72. package/dist/web/crypto/crypto.js.map +1 -1
  73. package/dist/web/exports.js +2 -1
  74. package/dist/web/exports.js.map +1 -1
  75. package/dist/web/localNode.js +5 -6
  76. package/dist/web/localNode.js.map +1 -1
  77. package/dist/web/logger.js +58 -0
  78. package/dist/web/logger.js.map +1 -0
  79. package/dist/web/permissions.js +3 -4
  80. package/dist/web/permissions.js.map +1 -1
  81. package/dist/web/storage/FileSystem.js +0 -10
  82. package/dist/web/storage/FileSystem.js.map +1 -1
  83. package/dist/web/storage/index.js +14 -23
  84. package/dist/web/storage/index.js.map +1 -1
  85. package/dist/web/sync.js +20 -28
  86. package/dist/web/sync.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/PeerState.ts +4 -3
  89. package/src/PriorityBasedMessageQueue.ts +67 -11
  90. package/src/base64url.ts +1 -6
  91. package/src/coValue.ts +37 -0
  92. package/src/coValueCore.ts +34 -180
  93. package/src/coValueState.ts +5 -4
  94. package/src/coValues/account.ts +2 -1
  95. package/src/coValues/coList.ts +0 -7
  96. package/src/coValues/coStream.ts +3 -8
  97. package/src/coValues/group.ts +3 -2
  98. package/src/coreToCoValue.ts +2 -1
  99. package/src/crypto/PureJSCrypto.ts +2 -1
  100. package/src/crypto/WasmCrypto.ts +2 -1
  101. package/src/crypto/crypto.ts +2 -4
  102. package/src/exports.ts +2 -0
  103. package/src/localNode.ts +5 -9
  104. package/src/logger.ts +78 -0
  105. package/src/permissions.ts +3 -5
  106. package/src/storage/FileSystem.ts +0 -12
  107. package/src/storage/index.ts +21 -37
  108. package/src/sync.ts +20 -29
  109. package/src/tests/PeerState.test.ts +0 -3
  110. package/src/tests/PriorityBasedMessageQueue.test.ts +1 -1
  111. package/src/tests/coValueCore.test.ts +32 -2
  112. package/src/tests/logger.test.ts +145 -0
  113. package/src/tests/sync.test.ts +43 -0
  114. package/src/tests/testUtils.ts +19 -0
@@ -1,11 +1,14 @@
1
1
  import { expect, test, vi } from "vitest";
2
- import { Transaction } from "../coValueCore.js";
2
+ import { CoValueCore, Transaction } from "../coValueCore.js";
3
3
  import { MapOpPayload } from "../coValues/coMap.js";
4
4
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
5
5
  import { stableStringify } from "../jsonStringify.js";
6
6
  import { LocalNode } from "../localNode.js";
7
7
  import { Role } from "../permissions.js";
8
- import { randomAnonymousAccountAndSessionID } from "./testUtils.js";
8
+ import {
9
+ createTestNode,
10
+ randomAnonymousAccountAndSessionID,
11
+ } from "./testUtils.js";
9
12
 
10
13
  const Crypto = await WasmCrypto.create();
11
14
 
@@ -191,3 +194,30 @@ test("New transactions in a group correctly update owned values, including subsc
191
194
 
192
195
  expect(map.core.getValidSortedTransactions().length).toBe(0);
193
196
  });
197
+
198
+ test("creating a coValue with a group should't trigger automatically a content creation (performance)", () => {
199
+ const node = createTestNode();
200
+
201
+ const group = node.createGroup();
202
+
203
+ const getCurrentContentSpy = vi.spyOn(
204
+ CoValueCore.prototype,
205
+ "getCurrentContent",
206
+ );
207
+ const groupSpy = vi.spyOn(group.core, "getCurrentContent");
208
+
209
+ getCurrentContentSpy.mockClear();
210
+
211
+ node.createCoValue({
212
+ type: "comap",
213
+ ruleset: { type: "ownedByGroup", group: group.id },
214
+ meta: null,
215
+ ...Crypto.createdNowUnique(),
216
+ });
217
+
218
+ // It's called once for the group and never for the coValue
219
+ expect(getCurrentContentSpy).toHaveBeenCalledTimes(1);
220
+ expect(groupSpy).toHaveBeenCalledTimes(1);
221
+
222
+ getCurrentContentSpy.mockRestore();
223
+ });
@@ -0,0 +1,145 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { LogLevel, Logger } from "../logger";
3
+
4
+ describe("Logger", () => {
5
+ describe("Log Level Filtering", () => {
6
+ test("should respect log level hierarchy", () => {
7
+ const mockLogSystem = {
8
+ debug: vi.fn(),
9
+ info: vi.fn(),
10
+ warn: vi.fn(),
11
+ error: vi.fn(),
12
+ };
13
+
14
+ const logger = new Logger(LogLevel.WARN, mockLogSystem);
15
+
16
+ logger.debug("Debug message");
17
+ logger.info("Info message");
18
+ logger.warn("Warning message");
19
+ logger.error("Error message");
20
+
21
+ expect(mockLogSystem.debug).not.toHaveBeenCalled();
22
+ expect(mockLogSystem.info).not.toHaveBeenCalled();
23
+ expect(mockLogSystem.warn).toHaveBeenCalledWith("Warning message");
24
+ expect(mockLogSystem.error).toHaveBeenCalledWith("Error message");
25
+ });
26
+
27
+ test("should pass additional arguments to log system", () => {
28
+ const mockLogSystem = {
29
+ debug: vi.fn(),
30
+ info: vi.fn(),
31
+ warn: vi.fn(),
32
+ error: vi.fn(),
33
+ };
34
+
35
+ const logger = new Logger(LogLevel.DEBUG, mockLogSystem);
36
+ const additionalArgs = [{ foo: "bar" }, 42, "extra"];
37
+
38
+ logger.debug("Debug message", ...additionalArgs);
39
+
40
+ expect(mockLogSystem.debug).toHaveBeenCalledWith(
41
+ "Debug message",
42
+ ...additionalArgs,
43
+ );
44
+ });
45
+ });
46
+
47
+ describe("Log System Configuration", () => {
48
+ test("should allow changing log level at runtime", () => {
49
+ const mockLogSystem = {
50
+ debug: vi.fn(),
51
+ info: vi.fn(),
52
+ warn: vi.fn(),
53
+ error: vi.fn(),
54
+ };
55
+
56
+ const logger = new Logger(LogLevel.ERROR, mockLogSystem);
57
+
58
+ logger.warn("Warning 1"); // Should not log
59
+ expect(mockLogSystem.warn).not.toHaveBeenCalled();
60
+
61
+ logger.setLevel(LogLevel.WARN);
62
+ logger.warn("Warning 2"); // Should log
63
+ expect(mockLogSystem.warn).toHaveBeenCalledWith("Warning 2");
64
+ });
65
+
66
+ test("should allow changing log system at runtime", () => {
67
+ const mockLogSystem1 = {
68
+ debug: vi.fn(),
69
+ info: vi.fn(),
70
+ warn: vi.fn(),
71
+ error: vi.fn(),
72
+ };
73
+
74
+ const mockLogSystem2 = {
75
+ debug: vi.fn(),
76
+ info: vi.fn(),
77
+ warn: vi.fn(),
78
+ error: vi.fn(),
79
+ };
80
+
81
+ const logger = new Logger(LogLevel.INFO, mockLogSystem1);
82
+
83
+ logger.info("Message 1");
84
+ expect(mockLogSystem1.info).toHaveBeenCalledWith("Message 1");
85
+ expect(mockLogSystem2.info).not.toHaveBeenCalled();
86
+
87
+ logger.setLogSystem(mockLogSystem2);
88
+ logger.info("Message 2");
89
+ expect(mockLogSystem2.info).toHaveBeenCalledWith("Message 2");
90
+ expect(mockLogSystem1.info).toHaveBeenCalledTimes(1);
91
+ });
92
+ });
93
+
94
+ describe("Default Console Log System", () => {
95
+ test("should use console methods by default", () => {
96
+ const consoleSpy = {
97
+ debug: vi.spyOn(console, "debug").mockImplementation(() => {}),
98
+ info: vi.spyOn(console, "info").mockImplementation(() => {}),
99
+ warn: vi.spyOn(console, "warn").mockImplementation(() => {}),
100
+ error: vi.spyOn(console, "error").mockImplementation(() => {}),
101
+ };
102
+
103
+ const logger = new Logger();
104
+ logger.setLevel(LogLevel.DEBUG);
105
+ const testMessage = "Test message";
106
+ const testArgs = [{ data: "test" }, 123];
107
+
108
+ logger.debug(testMessage, ...testArgs);
109
+ logger.info(testMessage, ...testArgs);
110
+ logger.warn(testMessage, ...testArgs);
111
+ logger.error(testMessage, ...testArgs);
112
+
113
+ expect(consoleSpy.debug).toHaveBeenCalledWith(testMessage, ...testArgs);
114
+ expect(consoleSpy.info).toHaveBeenCalledWith(testMessage, ...testArgs);
115
+ expect(consoleSpy.warn).toHaveBeenCalledWith(testMessage, ...testArgs);
116
+ expect(consoleSpy.error).toHaveBeenCalledWith(testMessage, ...testArgs);
117
+
118
+ // Cleanup
119
+ Object.values(consoleSpy).forEach((spy) => spy.mockRestore());
120
+ });
121
+ });
122
+
123
+ describe("Log Level NONE", () => {
124
+ test("should not log anything when level is NONE", () => {
125
+ const mockLogSystem = {
126
+ debug: vi.fn(),
127
+ info: vi.fn(),
128
+ warn: vi.fn(),
129
+ error: vi.fn(),
130
+ };
131
+
132
+ const logger = new Logger(LogLevel.NONE, mockLogSystem);
133
+
134
+ logger.debug("Debug message");
135
+ logger.info("Info message");
136
+ logger.warn("Warning message");
137
+ logger.error("Error message");
138
+
139
+ expect(mockLogSystem.debug).not.toHaveBeenCalled();
140
+ expect(mockLogSystem.info).not.toHaveBeenCalled();
141
+ expect(mockLogSystem.warn).not.toHaveBeenCalled();
142
+ expect(mockLogSystem.error).not.toHaveBeenCalled();
143
+ });
144
+ });
145
+ });
@@ -12,8 +12,10 @@ import { connectedPeers, newQueuePair } from "../streamUtils.js";
12
12
  import type { SyncMessage } from "../sync.js";
13
13
  import {
14
14
  blockMessageTypeOnOutgoingPeer,
15
+ connectTwoPeers,
15
16
  createTestMetricReader,
16
17
  createTestNode,
18
+ loadCoValueOrFail,
17
19
  randomAnonymousAccountAndSessionID,
18
20
  tearDownTestMetricReader,
19
21
  waitFor,
@@ -1645,6 +1647,28 @@ function createTwoConnectedNodes() {
1645
1647
  };
1646
1648
  }
1647
1649
 
1650
+ test("a value created on one node can be loaded on anotehr node even if not directly connected", async () => {
1651
+ const userA = createTestNode();
1652
+ const userB = createTestNode();
1653
+ const serverA = createTestNode();
1654
+ const serverB = createTestNode();
1655
+ const core = createTestNode();
1656
+
1657
+ connectTwoPeers(userA, serverA, "client", "server");
1658
+ connectTwoPeers(userB, serverB, "client", "server");
1659
+ connectTwoPeers(serverA, core, "client", "server");
1660
+ connectTwoPeers(serverB, core, "client", "server");
1661
+
1662
+ const group = userA.createGroup();
1663
+ const map = group.createMap();
1664
+ map.set("key1", "value1", "trusting");
1665
+
1666
+ await map.core.waitForSync();
1667
+
1668
+ const mapOnUserB = await loadCoValueOrFail(userB, map.id);
1669
+ expect(mapOnUserB.get("key1")).toBe("value1");
1670
+ });
1671
+
1648
1672
  describe("SyncManager - knownStates vs optimisticKnownStates", () => {
1649
1673
  test("knownStates and optimisticKnownStates are the same when the coValue is fully synced", async () => {
1650
1674
  const { client, jazzCloud } = createTwoConnectedNodes();
@@ -1961,6 +1985,25 @@ describe("waitForSyncWithPeer", () => {
1961
1985
  });
1962
1986
  });
1963
1987
 
1988
+ test("Should not crash when syncing an unknown coValue type", async () => {
1989
+ const { client, jazzCloud } = createTwoConnectedNodes();
1990
+
1991
+ const coValue = client.createCoValue({
1992
+ type: "ooops" as any,
1993
+ ruleset: { type: "unsafeAllowAll" },
1994
+ meta: null,
1995
+ ...Crypto.createdNowUnique(),
1996
+ });
1997
+
1998
+ await coValue.waitForSync();
1999
+
2000
+ const coValueOnTheOtherNode = await loadCoValueOrFail(
2001
+ jazzCloud,
2002
+ coValue.getCurrentContent().id,
2003
+ );
2004
+ expect(coValueOnTheOtherNode.id).toBe(coValue.id);
2005
+ });
2006
+
1964
2007
  describe("metrics", () => {
1965
2008
  afterEach(() => {
1966
2009
  tearDownTestMetricReader();
@@ -33,6 +33,25 @@ export function createTestNode() {
33
33
  return new LocalNode(admin, session, Crypto);
34
34
  }
35
35
 
36
+ export function connectTwoPeers(
37
+ a: LocalNode,
38
+ b: LocalNode,
39
+ aRole: "client" | "server",
40
+ bRole: "client" | "server",
41
+ ) {
42
+ const [aAsPeer, bAsPeer] = connectedPeers(
43
+ "peer:" + a.account.id,
44
+ "peer:" + b.account.id,
45
+ {
46
+ peer1role: aRole,
47
+ peer2role: bRole,
48
+ },
49
+ );
50
+
51
+ a.syncManager.addPeer(bAsPeer);
52
+ b.syncManager.addPeer(aAsPeer);
53
+ }
54
+
36
55
  export async function createTwoConnectedNodes(
37
56
  node1Role: Peer["role"],
38
57
  node2Role: Peer["role"],