jazz-tools 0.9.8 → 0.9.10-jazz-bridge-preview.0
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/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +144 -0
- package/CHANGELOG.md +14 -0
- package/dist/{chunk-YD32FKHW.js → chunk-YWGGIF2U.js} +209 -90
- package/dist/chunk-YWGGIF2U.js.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.web.js +1 -1
- package/dist/testing.js +1 -1
- package/package.json +3 -2
- package/src/coValues/coList.ts +14 -1
- package/src/coValues/coMap.ts +54 -2
- package/src/coValues/coPlainText.ts +7 -34
- package/src/coValues/coRichText.ts +194 -34
- package/src/coValues/interfaces.ts +10 -0
- package/src/exports.ts +7 -1
- package/src/internal.ts +4 -4
- package/src/tests/coList.test.ts +20 -0
- package/src/tests/coPlainText.test.ts +145 -17
- package/src/tests/coRichText.test.ts +889 -12
- package/src/tests/groupsAndAccounts.test.ts +3 -3
- package/tsconfig.native.json +1 -1
- package/tsconfig.web.json +1 -1
- package/dist/chunk-YD32FKHW.js.map +0 -1
@@ -1,33 +1,161 @@
|
|
1
|
+
import { connectedPeers } from "cojson/src/streamUtils.js";
|
1
2
|
import { describe, expect, test } from "vitest";
|
2
|
-
import {
|
3
|
+
import {
|
4
|
+
Account,
|
5
|
+
CoPlainText,
|
6
|
+
WasmCrypto,
|
7
|
+
cojsonInternals,
|
8
|
+
createJazzContext,
|
9
|
+
fixedCredentialsAuth,
|
10
|
+
isControlledAccount,
|
11
|
+
} from "../index.web.js";
|
12
|
+
import { randomSessionProvider } from "../internal.js";
|
3
13
|
|
4
14
|
const Crypto = await WasmCrypto.create();
|
5
15
|
|
6
|
-
describe("
|
7
|
-
const
|
8
|
-
|
9
|
-
|
16
|
+
describe("CoPlainText", () => {
|
17
|
+
const initNodeAndText = async () => {
|
18
|
+
const me = await Account.create({
|
19
|
+
creationProps: { name: "Hermes Puggington" },
|
20
|
+
crypto: Crypto,
|
21
|
+
});
|
22
|
+
|
23
|
+
const text = CoPlainText.create("hello world", { owner: me });
|
24
|
+
|
25
|
+
return { me, text };
|
26
|
+
};
|
27
|
+
|
28
|
+
describe("Simple CoPlainText operations", async () => {
|
29
|
+
const { me, text } = await initNodeAndText();
|
30
|
+
|
31
|
+
test("Construction", () => {
|
32
|
+
expect(text + "").toEqual("hello world");
|
33
|
+
});
|
34
|
+
|
35
|
+
describe("Mutation", () => {
|
36
|
+
test("insertion", () => {
|
37
|
+
const text = CoPlainText.create("hello world", { owner: me });
|
38
|
+
|
39
|
+
text.insertAfter(5, " cruel");
|
40
|
+
expect(text + "").toEqual("hello cruel world");
|
41
|
+
|
42
|
+
text.insertAfter(0, "Hello, ");
|
43
|
+
expect(text + "").toEqual("Hello, hello cruel world");
|
44
|
+
});
|
45
|
+
|
46
|
+
test("deletion", () => {
|
47
|
+
const text = CoPlainText.create("hello world", { owner: me });
|
48
|
+
|
49
|
+
text.deleteRange({ from: 3, to: 8 });
|
50
|
+
expect(text + "").toEqual("helrld");
|
51
|
+
});
|
52
|
+
});
|
53
|
+
|
54
|
+
describe("Position operations", () => {
|
55
|
+
test("idxBefore returns index before a position", () => {
|
56
|
+
const text = CoPlainText.create("hello world", { owner: me });
|
57
|
+
|
58
|
+
// Get position at index 5 (between "hello" and " world")
|
59
|
+
const pos = text.posBefore(5);
|
60
|
+
expect(pos).toBeDefined();
|
61
|
+
|
62
|
+
// Verify idxBefore returns the index before the position (4)
|
63
|
+
// This makes sense as the position is between characters,
|
64
|
+
// and idxBefore returns the index of the last character before that position
|
65
|
+
const idx = text.idxBefore(pos!);
|
66
|
+
expect(idx).toBe(4); // Index of 'o' in "hello"
|
67
|
+
});
|
68
|
+
|
69
|
+
test("idxAfter returns index after a position", () => {
|
70
|
+
const text = CoPlainText.create("hello world", { owner: me });
|
71
|
+
|
72
|
+
// Get position at index 5 (between "hello" and " world")
|
73
|
+
const pos = text.posBefore(5);
|
74
|
+
expect(pos).toBeDefined();
|
75
|
+
|
76
|
+
// Verify idxAfter returns the index after the position (5)
|
77
|
+
// This makes sense as the position is between characters,
|
78
|
+
// and idxAfter returns the index of the first character after that position
|
79
|
+
const idx = text.idxAfter(pos!);
|
80
|
+
expect(idx).toBe(5); // Index of ' ' in "hello world"
|
81
|
+
});
|
82
|
+
});
|
10
83
|
});
|
11
84
|
|
12
|
-
|
85
|
+
describe("Loading and availability", () => {
|
86
|
+
test("can load text across peers", async () => {
|
87
|
+
const { me, text } = await initNodeAndText();
|
88
|
+
const id = text.id;
|
89
|
+
|
90
|
+
// Set up peer connections
|
91
|
+
const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
|
92
|
+
peer1role: "server",
|
93
|
+
peer2role: "client",
|
94
|
+
});
|
95
|
+
|
96
|
+
if (!isControlledAccount(me)) {
|
97
|
+
throw "me is not a controlled account";
|
98
|
+
}
|
99
|
+
me._raw.core.node.syncManager.addPeer(secondPeer);
|
100
|
+
const { account: meOnSecondPeer } = await createJazzContext({
|
101
|
+
auth: fixedCredentialsAuth({
|
102
|
+
accountID: me.id,
|
103
|
+
secret: me._raw.agentSecret,
|
104
|
+
}),
|
105
|
+
sessionProvider: randomSessionProvider,
|
106
|
+
peersToLoadFrom: [initialAsPeer],
|
107
|
+
crypto: Crypto,
|
108
|
+
});
|
13
109
|
|
14
|
-
|
15
|
-
|
110
|
+
// Load the text on the second peer
|
111
|
+
const loaded = await CoPlainText.load(id, meOnSecondPeer);
|
112
|
+
expect(loaded).toBeDefined();
|
113
|
+
expect(loaded!.toString()).toBe("hello world");
|
114
|
+
});
|
16
115
|
});
|
17
116
|
|
18
|
-
|
19
|
-
|
20
|
-
|
117
|
+
test("Subscription & auto-resolution", async () => {
|
118
|
+
const { me, text } = await initNodeAndText();
|
119
|
+
|
120
|
+
// Set up peer connections
|
121
|
+
const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
|
122
|
+
peer1role: "server",
|
123
|
+
peer2role: "client",
|
124
|
+
});
|
21
125
|
|
22
|
-
|
23
|
-
|
126
|
+
if (!isControlledAccount(me)) {
|
127
|
+
throw "me is not a controlled account";
|
128
|
+
}
|
129
|
+
me._raw.core.node.syncManager.addPeer(secondPeer);
|
130
|
+
const { account: meOnSecondPeer } = await createJazzContext({
|
131
|
+
auth: fixedCredentialsAuth({
|
132
|
+
accountID: me.id,
|
133
|
+
secret: me._raw.agentSecret,
|
134
|
+
}),
|
135
|
+
sessionProvider: randomSessionProvider,
|
136
|
+
peersToLoadFrom: [initialAsPeer],
|
137
|
+
crypto: Crypto,
|
24
138
|
});
|
25
139
|
|
26
|
-
|
27
|
-
const text = CoPlainText.create("hello world", { owner: me });
|
140
|
+
const queue = new cojsonInternals.Channel();
|
28
141
|
|
29
|
-
|
30
|
-
|
142
|
+
// Subscribe to text updates
|
143
|
+
CoPlainText.subscribe(text.id, meOnSecondPeer, (subscribedText) => {
|
144
|
+
void queue.push(subscribedText);
|
31
145
|
});
|
146
|
+
|
147
|
+
// Initial subscription should give us the text
|
148
|
+
const update1 = (await queue.next()).value;
|
149
|
+
expect(update1.toString()).toBe("hello world");
|
150
|
+
|
151
|
+
// When we make a change, we should get an update
|
152
|
+
text.insertAfter(5, " beautiful");
|
153
|
+
const update2 = (await queue.next()).value;
|
154
|
+
expect(update2.toString()).toBe("hello beautiful world");
|
155
|
+
|
156
|
+
// When we make another change, we should get another update
|
157
|
+
update2.deleteRange({ from: 5, to: 15 }); // Delete " beautiful"
|
158
|
+
const update3 = (await queue.next()).value;
|
159
|
+
expect(update3.toString()).toBe("hello world");
|
32
160
|
});
|
33
161
|
});
|