jazz-tools 0.9.23 → 0.10.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 +11 -11
- package/CHANGELOG.md +19 -0
- package/dist/{chunk-OJIEP4WE.js → chunk-UBD75Z27.js} +566 -118
- package/dist/chunk-UBD75Z27.js.map +1 -0
- package/dist/index.native.js +17 -5
- package/dist/index.native.js.map +1 -1
- package/dist/index.web.js +17 -5
- package/dist/index.web.js.map +1 -1
- package/dist/testing.js +124 -33
- package/dist/testing.js.map +1 -1
- package/package.json +5 -3
- package/src/auth/AuthSecretStorage.ts +109 -0
- package/src/auth/DemoAuth.ts +188 -0
- package/src/auth/InMemoryKVStore.ts +25 -0
- package/src/auth/KvStoreContext.ts +39 -0
- package/src/auth/PassphraseAuth.ts +113 -0
- package/src/coValues/account.ts +8 -3
- package/src/coValues/coFeed.ts +1 -1
- package/src/coValues/coList.ts +1 -1
- package/src/coValues/coMap.ts +1 -1
- package/src/coValues/group.ts +9 -8
- package/src/coValues/interfaces.ts +14 -5
- package/src/exports.ts +17 -3
- package/src/implementation/ContextManager.ts +178 -0
- package/src/implementation/activeAccountContext.ts +6 -1
- package/src/implementation/createContext.ts +173 -149
- package/src/testing.ts +171 -33
- package/src/tests/AuthSecretStorage.test.ts +275 -0
- package/src/tests/ContextManager.test.ts +256 -0
- package/src/tests/DemoAuth.test.ts +269 -0
- package/src/tests/PassphraseAuth.test.ts +152 -0
- package/src/tests/coFeed.test.ts +44 -39
- package/src/tests/coList.test.ts +21 -20
- package/src/tests/coMap.test.ts +21 -20
- package/src/tests/coPlainText.test.ts +21 -20
- package/src/tests/coRichText.test.ts +21 -20
- package/src/tests/createContext.test.ts +339 -0
- package/src/tests/deepLoading.test.ts +41 -42
- package/src/tests/fixtures.ts +2050 -0
- package/src/tests/groupsAndAccounts.test.ts +2 -2
- package/src/tests/subscribe.test.ts +42 -9
- package/src/tests/testing.test.ts +56 -0
- package/src/tests/utils.ts +11 -11
- package/src/types.ts +54 -0
- package/dist/chunk-OJIEP4WE.js.map +0 -1
@@ -122,7 +122,7 @@ describe("Group inheritance", () => {
|
|
122
122
|
const mapAsReader = await TestMap.load(mapInChild.id, reader, {});
|
123
123
|
expect(mapAsReader?.title).toBe("In Child");
|
124
124
|
|
125
|
-
parentGroup.removeMember(reader);
|
125
|
+
await parentGroup.removeMember(reader);
|
126
126
|
|
127
127
|
mapInChild.title = "In Child (updated)";
|
128
128
|
|
@@ -161,7 +161,7 @@ describe("Group inheritance", () => {
|
|
161
161
|
const mapAsReader = await TestMap.load(mapInGrandChild.id, reader, {});
|
162
162
|
expect(mapAsReader?.title).toBe("In Grand Child");
|
163
163
|
|
164
|
-
grandParentGroup.removeMember(reader);
|
164
|
+
await grandParentGroup.removeMember(reader);
|
165
165
|
|
166
166
|
mapInGrandChild.title = "In Grand Child (updated)";
|
167
167
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { describe, expect, it, onTestFinished, vi } from "vitest";
|
1
|
+
import { beforeEach, describe, expect, it, onTestFinished, vi } from "vitest";
|
2
2
|
import {
|
3
3
|
Account,
|
4
4
|
CoFeed,
|
@@ -7,12 +7,15 @@ import {
|
|
7
7
|
FileStream,
|
8
8
|
Group,
|
9
9
|
co,
|
10
|
+
cojsonInternals,
|
10
11
|
} from "../index.web.js";
|
11
12
|
import {
|
12
13
|
type DepthsIn,
|
14
|
+
ID,
|
13
15
|
createCoValueObservable,
|
14
16
|
subscribeToCoValue,
|
15
17
|
} from "../internal.js";
|
18
|
+
import { setupJazzTestSync } from "../testing.js";
|
16
19
|
import { setupAccount, waitFor } from "./utils.js";
|
17
20
|
|
18
21
|
class ChatRoom extends CoMap {
|
@@ -43,6 +46,15 @@ function createMessage(me: Account | Group, text: string) {
|
|
43
46
|
);
|
44
47
|
}
|
45
48
|
|
49
|
+
beforeEach(async () => {
|
50
|
+
await setupJazzTestSync();
|
51
|
+
});
|
52
|
+
|
53
|
+
beforeEach(() => {
|
54
|
+
cojsonInternals.CO_VALUE_LOADING_CONFIG.MAX_RETRIES = 1;
|
55
|
+
cojsonInternals.CO_VALUE_LOADING_CONFIG.TIMEOUT = 1;
|
56
|
+
});
|
57
|
+
|
46
58
|
describe("subscribeToCoValue", () => {
|
47
59
|
it("subscribes to a CoMap", async () => {
|
48
60
|
const { me, meOnSecondPeer } = await setupAccount();
|
@@ -163,7 +175,7 @@ describe("subscribeToCoValue", () => {
|
|
163
175
|
onTestFinished(unsubscribe);
|
164
176
|
|
165
177
|
await waitFor(() => {
|
166
|
-
const lastValue = updateFn.mock.lastCall[0];
|
178
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
167
179
|
|
168
180
|
expect(lastValue?.messages?.[0]?.text).toBe(message.text);
|
169
181
|
});
|
@@ -175,7 +187,7 @@ describe("subscribeToCoValue", () => {
|
|
175
187
|
expect(updateFn).toHaveBeenCalled();
|
176
188
|
});
|
177
189
|
|
178
|
-
const lastValue = updateFn.mock.lastCall[0];
|
190
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
179
191
|
expect(lastValue?.messages?.[0]?.text).toBe(
|
180
192
|
"Nevermind, she was gone to the supermarket",
|
181
193
|
);
|
@@ -212,12 +224,12 @@ describe("subscribeToCoValue", () => {
|
|
212
224
|
onTestFinished(unsubscribe);
|
213
225
|
|
214
226
|
await waitFor(() => {
|
215
|
-
const lastValue = updateFn.mock.lastCall[0];
|
227
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
216
228
|
|
217
229
|
expect(lastValue?.messages?.[0]?.text).toBe(message.text);
|
218
230
|
});
|
219
231
|
|
220
|
-
const initialValue = updateFn.mock.lastCall[0];
|
232
|
+
const initialValue = updateFn.mock.lastCall?.[0];
|
221
233
|
const initialMessagesList = initialValue?.messages;
|
222
234
|
const initialMessage1 = initialValue?.messages[0];
|
223
235
|
const initialMessage2 = initialValue?.messages[1];
|
@@ -231,7 +243,7 @@ describe("subscribeToCoValue", () => {
|
|
231
243
|
expect(updateFn).toHaveBeenCalled();
|
232
244
|
});
|
233
245
|
|
234
|
-
const lastValue = updateFn.mock.lastCall[0];
|
246
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
235
247
|
expect(lastValue).not.toBe(initialValue);
|
236
248
|
expect(lastValue.messages).not.toBe(initialMessagesList);
|
237
249
|
expect(lastValue.messages[0]).not.toBe(initialMessage1);
|
@@ -278,13 +290,13 @@ describe("subscribeToCoValue", () => {
|
|
278
290
|
onTestFinished(unsubscribe);
|
279
291
|
|
280
292
|
await waitFor(() => {
|
281
|
-
const lastValue = updateFn.mock.lastCall[0];
|
293
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
282
294
|
|
283
295
|
expect(lastValue?.messages?.[0]?.text).toBe(message.text);
|
284
296
|
expect(lastValue?.messages?.[1]?.text).toBe(message2.text);
|
285
297
|
});
|
286
298
|
|
287
|
-
const initialValue = updateFn.mock.lastCall[0];
|
299
|
+
const initialValue = updateFn.mock.lastCall?.[0];
|
288
300
|
chatRoom.name = "Me and Luigi";
|
289
301
|
|
290
302
|
updateFn.mockClear();
|
@@ -293,7 +305,7 @@ describe("subscribeToCoValue", () => {
|
|
293
305
|
expect(updateFn).toHaveBeenCalled();
|
294
306
|
});
|
295
307
|
|
296
|
-
const lastValue = updateFn.mock.lastCall[0];
|
308
|
+
const lastValue = updateFn.mock.lastCall?.[0];
|
297
309
|
expect(lastValue).not.toBe(initialValue);
|
298
310
|
expect(lastValue.name).toBe("Me and Luigi");
|
299
311
|
|
@@ -368,4 +380,25 @@ describe("createCoValueObservable", () => {
|
|
368
380
|
unsubscribe();
|
369
381
|
expect(observable.getCurrentValue()).toBeUndefined();
|
370
382
|
});
|
383
|
+
|
384
|
+
it("should return null if the coValue is not found", async () => {
|
385
|
+
const { meOnSecondPeer } = await setupAccount();
|
386
|
+
const observable = createCoValueObservable<TestMap, DepthsIn<TestMap>>();
|
387
|
+
|
388
|
+
const unsubscribe = observable.subscribe(
|
389
|
+
TestMap,
|
390
|
+
"co_z123" as ID<TestMap>,
|
391
|
+
meOnSecondPeer,
|
392
|
+
{},
|
393
|
+
() => {},
|
394
|
+
);
|
395
|
+
|
396
|
+
expect(observable.getCurrentValue()).toBeUndefined();
|
397
|
+
|
398
|
+
await waitFor(() => {
|
399
|
+
expect(observable.getCurrentValue()).toBeNull();
|
400
|
+
});
|
401
|
+
|
402
|
+
unsubscribe();
|
403
|
+
});
|
371
404
|
});
|
@@ -48,4 +48,60 @@ describe("Jazz Test Sync", () => {
|
|
48
48
|
|
49
49
|
expect(account1.root?.value).toBe("ok");
|
50
50
|
});
|
51
|
+
|
52
|
+
test("correctly manages the global me during the migrations", async () => {
|
53
|
+
class MyRoot extends CoMap {
|
54
|
+
value = co.string;
|
55
|
+
}
|
56
|
+
|
57
|
+
class CustomAccount extends Account {
|
58
|
+
root = co.ref(MyRoot);
|
59
|
+
|
60
|
+
migrate() {
|
61
|
+
if (this.root === undefined) {
|
62
|
+
this.root = MyRoot.create({
|
63
|
+
value: "ok",
|
64
|
+
});
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
const account1 = await createJazzTestAccount({
|
70
|
+
AccountSchema: CustomAccount,
|
71
|
+
isCurrentActiveAccount: true,
|
72
|
+
});
|
73
|
+
|
74
|
+
const account2 = await createJazzTestAccount({
|
75
|
+
AccountSchema: CustomAccount,
|
76
|
+
isCurrentActiveAccount: false,
|
77
|
+
});
|
78
|
+
|
79
|
+
expect(account1.root?.value).toBe("ok");
|
80
|
+
expect(account2.root?.value).toBe("ok");
|
81
|
+
|
82
|
+
expect(Account.getMe()).toBe(account1);
|
83
|
+
});
|
84
|
+
|
85
|
+
test("throws when running multiple migrations in parallel", async () => {
|
86
|
+
class CustomAccount extends Account {
|
87
|
+
async migrate() {
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
const promise = Promise.all([
|
93
|
+
createJazzTestAccount({
|
94
|
+
AccountSchema: CustomAccount,
|
95
|
+
isCurrentActiveAccount: true,
|
96
|
+
}),
|
97
|
+
createJazzTestAccount({
|
98
|
+
AccountSchema: CustomAccount,
|
99
|
+
isCurrentActiveAccount: true,
|
100
|
+
}),
|
101
|
+
]);
|
102
|
+
|
103
|
+
await expect(promise).rejects.toThrow(
|
104
|
+
"It is not possible to create multiple accounts in parallel inside the test environment.",
|
105
|
+
);
|
106
|
+
});
|
51
107
|
});
|
package/src/tests/utils.ts
CHANGED
@@ -5,8 +5,7 @@ import { cojsonInternals } from "cojson";
|
|
5
5
|
import {
|
6
6
|
Account,
|
7
7
|
WasmCrypto,
|
8
|
-
|
9
|
-
fixedCredentialsAuth,
|
8
|
+
createJazzContextFromExistingCredentials,
|
10
9
|
randomSessionProvider,
|
11
10
|
} from "../index.web";
|
12
11
|
|
@@ -31,15 +30,16 @@ export async function setupAccount() {
|
|
31
30
|
throw "me is not a controlled account";
|
32
31
|
}
|
33
32
|
me._raw.core.node.syncManager.addPeer(secondPeer);
|
34
|
-
const { account: meOnSecondPeer } =
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
33
|
+
const { account: meOnSecondPeer } =
|
34
|
+
await createJazzContextFromExistingCredentials({
|
35
|
+
credentials: {
|
36
|
+
accountID: me.id,
|
37
|
+
secret: me._raw.agentSecret,
|
38
|
+
},
|
39
|
+
sessionProvider: randomSessionProvider,
|
40
|
+
peersToLoadFrom: [initialAsPeer],
|
41
|
+
crypto: Crypto,
|
42
|
+
});
|
43
43
|
|
44
44
|
return { me, meOnSecondPeer };
|
45
45
|
}
|
package/src/types.ts
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
import type { AgentSecret, LocalNode } from "cojson";
|
2
|
+
import type { Account } from "./exports.js";
|
3
|
+
import type { AnonymousJazzAgent, ID } from "./internal.js";
|
4
|
+
|
5
|
+
export type AuthCredentials = {
|
6
|
+
accountID: ID<Account>;
|
7
|
+
secretSeed?: Uint8Array;
|
8
|
+
accountSecret: AgentSecret;
|
9
|
+
provider?: "anonymous" | "clerk" | "demo" | "passkey" | "passphrase" | string;
|
10
|
+
};
|
11
|
+
|
12
|
+
export type AuthenticateAccountFunction = (
|
13
|
+
credentials: AuthCredentials,
|
14
|
+
) => Promise<void>;
|
15
|
+
export type RegisterAccountFunction = (
|
16
|
+
accountSecret: AgentSecret,
|
17
|
+
creationProps: { name: string },
|
18
|
+
) => Promise<ID<Account>>;
|
19
|
+
|
20
|
+
/** @category Context Creation */
|
21
|
+
export type JazzAuthContext<Acc extends Account> = {
|
22
|
+
me: Acc;
|
23
|
+
node: LocalNode;
|
24
|
+
authenticate: AuthenticateAccountFunction;
|
25
|
+
logOut: () => Promise<void>;
|
26
|
+
done: () => void;
|
27
|
+
};
|
28
|
+
|
29
|
+
export type JazzGuestContext = {
|
30
|
+
guest: AnonymousJazzAgent;
|
31
|
+
node: LocalNode;
|
32
|
+
authenticate: AuthenticateAccountFunction;
|
33
|
+
logOut: () => void;
|
34
|
+
done: () => void;
|
35
|
+
};
|
36
|
+
|
37
|
+
export type JazzContextType<Acc extends Account> =
|
38
|
+
| JazzAuthContext<Acc>
|
39
|
+
| JazzGuestContext;
|
40
|
+
|
41
|
+
export type NewAccountProps = {
|
42
|
+
secret?: AgentSecret;
|
43
|
+
creationProps?: { name: string };
|
44
|
+
};
|
45
|
+
|
46
|
+
export type SyncConfig =
|
47
|
+
| {
|
48
|
+
peer: `wss://${string}` | `ws://${string}`;
|
49
|
+
when?: "always" | "signedUp";
|
50
|
+
}
|
51
|
+
| {
|
52
|
+
peer?: `wss://${string}` | `ws://${string}`;
|
53
|
+
when: "never";
|
54
|
+
};
|