jazz-tools 0.10.14 → 0.11.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 -7
- package/CHANGELOG.md +31 -0
- package/dist/auth/AuthSecretStorage.d.ts +25 -0
- package/dist/auth/AuthSecretStorage.d.ts.map +1 -0
- package/dist/auth/DemoAuth.d.ts +27 -0
- package/dist/auth/DemoAuth.d.ts.map +1 -0
- package/dist/auth/InMemoryKVStore.d.ts +9 -0
- package/dist/auth/InMemoryKVStore.d.ts.map +1 -0
- package/dist/auth/KvStoreContext.d.ts +17 -0
- package/dist/auth/KvStoreContext.d.ts.map +1 -0
- package/dist/auth/PassphraseAuth.d.ts +35 -0
- package/dist/auth/PassphraseAuth.d.ts.map +1 -0
- package/dist/{chunk-5YDDEUNX.js → chunk-RTRX7HIO.js} +193 -81
- package/dist/chunk-RTRX7HIO.js.map +1 -0
- package/dist/coValues/account.d.ts +120 -0
- package/dist/coValues/account.d.ts.map +1 -0
- package/dist/coValues/coFeed.d.ts +361 -0
- package/dist/coValues/coFeed.d.ts.map +1 -0
- package/dist/coValues/coList.d.ts +221 -0
- package/dist/coValues/coList.d.ts.map +1 -0
- package/dist/coValues/coMap.d.ts +500 -0
- package/dist/coValues/coMap.d.ts.map +1 -0
- package/dist/coValues/coPlainText.d.ts +69 -0
- package/dist/coValues/coPlainText.d.ts.map +1 -0
- package/dist/coValues/coRichText.d.ts +259 -0
- package/dist/coValues/coRichText.d.ts.map +1 -0
- package/dist/coValues/deepLoading.d.ts +81 -0
- package/dist/coValues/deepLoading.d.ts.map +1 -0
- package/dist/coValues/extensions/imageDef.d.ts +17 -0
- package/dist/coValues/extensions/imageDef.d.ts.map +1 -0
- package/dist/coValues/group.d.ts +67 -0
- package/dist/coValues/group.d.ts.map +1 -0
- package/dist/coValues/inbox.d.ts +52 -0
- package/dist/coValues/inbox.d.ts.map +1 -0
- package/dist/coValues/interfaces.d.ts +97 -0
- package/dist/coValues/interfaces.d.ts.map +1 -0
- package/dist/coValues/profile.d.ts +28 -0
- package/dist/coValues/profile.d.ts.map +1 -0
- package/dist/coValues/registeredSchemas.d.ts +12 -0
- package/dist/coValues/registeredSchemas.d.ts.map +1 -0
- package/dist/coValues/schemaUnion.d.ts +79 -0
- package/dist/coValues/schemaUnion.d.ts.map +1 -0
- package/dist/exports.d.ts +27 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/implementation/ContextManager.d.ts +65 -0
- package/dist/implementation/ContextManager.d.ts.map +1 -0
- package/dist/implementation/activeAccountContext.d.ts +12 -0
- package/dist/implementation/activeAccountContext.d.ts.map +1 -0
- package/dist/implementation/anonymousJazzAgent.d.ts +7 -0
- package/dist/implementation/anonymousJazzAgent.d.ts.map +1 -0
- package/dist/implementation/createContext.d.ts +91 -0
- package/dist/implementation/createContext.d.ts.map +1 -0
- package/dist/implementation/devtoolsFormatters.d.ts +2 -0
- package/dist/implementation/devtoolsFormatters.d.ts.map +1 -0
- package/dist/implementation/errors.d.ts +2 -0
- package/dist/implementation/errors.d.ts.map +1 -0
- package/dist/implementation/inspect.d.ts +3 -0
- package/dist/implementation/inspect.d.ts.map +1 -0
- package/dist/implementation/invites.d.ts +23 -0
- package/dist/implementation/invites.d.ts.map +1 -0
- package/dist/implementation/refs.d.ts +21 -0
- package/dist/implementation/refs.d.ts.map +1 -0
- package/dist/implementation/schema.d.ts +72 -0
- package/dist/implementation/schema.d.ts.map +1 -0
- package/dist/implementation/subscriptionScope.d.ts +33 -0
- package/dist/implementation/subscriptionScope.d.ts.map +1 -0
- package/dist/implementation/symbols.d.ts +8 -0
- package/dist/implementation/symbols.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +12 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/lib/cache.d.ts +6 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.test.d.ts +2 -0
- package/dist/lib/cache.test.d.ts.map +1 -0
- package/dist/testing.d.ts +41 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +11 -16
- package/dist/testing.js.map +1 -1
- package/dist/tests/AuthSecretStorage.test.d.ts +2 -0
- package/dist/tests/AuthSecretStorage.test.d.ts.map +1 -0
- package/dist/tests/ContextManager.test.d.ts +2 -0
- package/dist/tests/ContextManager.test.d.ts.map +1 -0
- package/dist/tests/DemoAuth.test.d.ts +2 -0
- package/dist/tests/DemoAuth.test.d.ts.map +1 -0
- package/dist/tests/PassphraseAuth.test.d.ts +2 -0
- package/dist/tests/PassphraseAuth.test.d.ts.map +1 -0
- package/dist/tests/account.test.d.ts +2 -0
- package/dist/tests/account.test.d.ts.map +1 -0
- package/dist/tests/coFeed.test.d.ts +2 -0
- package/dist/tests/coFeed.test.d.ts.map +1 -0
- package/dist/tests/coList.test.d.ts +2 -0
- package/dist/tests/coList.test.d.ts.map +1 -0
- package/dist/tests/coMap.test.d.ts +2 -0
- package/dist/tests/coMap.test.d.ts.map +1 -0
- package/dist/tests/coPlainText.test.d.ts +2 -0
- package/dist/tests/coPlainText.test.d.ts.map +1 -0
- package/dist/tests/coRichText.test.d.ts +2 -0
- package/dist/tests/coRichText.test.d.ts.map +1 -0
- package/dist/tests/createContext.test.d.ts +2 -0
- package/dist/tests/createContext.test.d.ts.map +1 -0
- package/dist/tests/deepLoading.test.d.ts +2 -0
- package/dist/tests/deepLoading.test.d.ts.map +1 -0
- package/dist/tests/fixtures.d.ts +2 -0
- package/dist/tests/fixtures.d.ts.map +1 -0
- package/dist/tests/groupsAndAccounts.test.d.ts +2 -0
- package/dist/tests/groupsAndAccounts.test.d.ts.map +1 -0
- package/dist/tests/inbox.test.d.ts +2 -0
- package/dist/tests/inbox.test.d.ts.map +1 -0
- package/dist/tests/interfaces.test.d.ts +2 -0
- package/dist/tests/interfaces.test.d.ts.map +1 -0
- package/dist/tests/invites.test.d.ts +2 -0
- package/dist/tests/invites.test.d.ts.map +1 -0
- package/dist/tests/schema.test.d.ts +2 -0
- package/dist/tests/schema.test.d.ts.map +1 -0
- package/dist/tests/schemaUnion.test.d.ts +2 -0
- package/dist/tests/schemaUnion.test.d.ts.map +1 -0
- package/dist/tests/subscribe.test.d.ts +2 -0
- package/dist/tests/subscribe.test.d.ts.map +1 -0
- package/dist/tests/testing.test.d.ts +2 -0
- package/dist/tests/testing.test.d.ts.map +1 -0
- package/dist/tests/utils.d.ts +21 -0
- package/dist/tests/utils.d.ts.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +8 -7
- package/src/coValues/account.ts +69 -11
- package/src/coValues/coMap.ts +2 -2
- package/src/coValues/coRichText.ts +42 -17
- package/src/coValues/group.ts +76 -31
- package/src/coValues/inbox.ts +10 -0
- package/src/coValues/interfaces.ts +1 -1
- package/src/coValues/profile.ts +35 -2
- package/src/implementation/ContextManager.ts +63 -15
- package/src/implementation/schema.ts +1 -3
- package/src/testing.ts +10 -16
- package/src/tests/AuthSecretStorage.test.ts +1 -2
- package/src/tests/ContextManager.test.ts +27 -14
- package/src/tests/PassphraseAuth.test.ts +7 -3
- package/src/tests/coMap.test.ts +20 -21
- package/src/tests/deepLoading.test.ts +8 -17
- package/src/tests/groupsAndAccounts.test.ts +429 -89
- package/src/tests/inbox.test.ts +24 -0
- package/src/tests/schema.test.ts +45 -5
- package/src/tests/utils.ts +7 -3
- package/src/types.ts +6 -0
- package/tsconfig.json +4 -1
- package/dist/chunk-5YDDEUNX.js.map +0 -1
@@ -6,6 +6,7 @@ import {
|
|
6
6
|
CoFeed,
|
7
7
|
CoList,
|
8
8
|
CoMap,
|
9
|
+
Group,
|
9
10
|
ID,
|
10
11
|
Profile,
|
11
12
|
SessionID,
|
@@ -187,17 +188,15 @@ class CustomAccount extends Account {
|
|
187
188
|
creationProps?: { name: string } | undefined,
|
188
189
|
) {
|
189
190
|
if (creationProps) {
|
191
|
+
const profileGroup = Group.create(this);
|
190
192
|
this.profile = CustomProfile.create(
|
191
193
|
{
|
192
194
|
name: creationProps.name,
|
193
|
-
stream: TestStream.create([],
|
195
|
+
stream: TestStream.create([], this),
|
194
196
|
},
|
195
|
-
|
196
|
-
);
|
197
|
-
this.root = TestMap.create(
|
198
|
-
{ list: TestList.create([], { owner: this }) },
|
199
|
-
{ owner: this },
|
197
|
+
profileGroup,
|
200
198
|
);
|
199
|
+
this.root = TestMap.create({ list: TestList.create([], this) }, this);
|
201
200
|
}
|
202
201
|
|
203
202
|
const thisLoaded = await this.ensureLoaded({
|
@@ -312,19 +311,11 @@ test("doesn't break on Map.Record key deletion when the key is referenced in the
|
|
312
311
|
|
313
312
|
class JazzySnapStore extends CoMap.Record(co.ref(JazzProfile)) {}
|
314
313
|
|
315
|
-
const
|
316
|
-
|
317
|
-
|
314
|
+
const snapStore = JazzySnapStore.create({
|
315
|
+
profile1: JazzProfile.create({ firstName: "John" }),
|
316
|
+
profile2: JazzProfile.create({ firstName: "John" }),
|
318
317
|
});
|
319
318
|
|
320
|
-
const snapStore = JazzySnapStore.create(
|
321
|
-
{
|
322
|
-
profile1: JazzProfile.create({ firstName: "John" }, { owner: me }),
|
323
|
-
profile2: JazzProfile.create({ firstName: "John" }, { owner: me }),
|
324
|
-
},
|
325
|
-
{ owner: me },
|
326
|
-
);
|
327
|
-
|
328
319
|
const spy = vi.fn();
|
329
320
|
const unsub = snapStore.subscribe({ profile1: {}, profile2: {} }, spy);
|
330
321
|
|
@@ -1,97 +1,84 @@
|
|
1
1
|
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
2
|
-
import { beforeEach, describe, expect, test } from "vitest";
|
2
|
+
import { assert, beforeEach, describe, expect, test } from "vitest";
|
3
3
|
import { Account, CoMap, Group, Profile, co } from "../exports.js";
|
4
|
-
import {
|
4
|
+
import { Ref } from "../internal.js";
|
5
|
+
import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
|
5
6
|
import { setupTwoNodes } from "./utils.js";
|
6
7
|
|
7
8
|
const Crypto = await WasmCrypto.create();
|
8
9
|
|
9
10
|
beforeEach(async () => {
|
11
|
+
await setupJazzTestSync();
|
12
|
+
|
10
13
|
await createJazzTestAccount({
|
11
14
|
isCurrentActiveAccount: true,
|
12
15
|
});
|
13
16
|
});
|
14
17
|
|
15
18
|
describe("Custom accounts and groups", async () => {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
class CustomAccount extends Account {
|
22
|
-
profile = co.ref(CustomProfile);
|
23
|
-
root = co.ref(CoMap);
|
24
|
-
|
25
|
-
migrate(this: CustomAccount, creationProps?: { name: string }) {
|
26
|
-
if (creationProps) {
|
27
|
-
const profileGroup = Group.create({ owner: this });
|
28
|
-
profileGroup.addMember("everyone", "reader");
|
29
|
-
this.profile = CustomProfile.create(
|
30
|
-
{ name: creationProps.name, color: "blue" },
|
31
|
-
{ owner: this },
|
32
|
-
);
|
33
|
-
}
|
19
|
+
test("Custom account and group", async () => {
|
20
|
+
class CustomProfile extends Profile {
|
21
|
+
name = co.string;
|
22
|
+
color = co.string;
|
34
23
|
}
|
35
|
-
}
|
36
|
-
|
37
|
-
class CustomGroup extends Group {
|
38
|
-
profile = co.null;
|
39
|
-
root = co.null;
|
40
|
-
[co.members] = co.ref(CustomAccount);
|
41
24
|
|
42
|
-
|
43
|
-
|
25
|
+
class CustomAccount extends Account {
|
26
|
+
profile = co.ref(CustomProfile);
|
27
|
+
root = co.ref(CoMap);
|
28
|
+
|
29
|
+
migrate(this: CustomAccount, creationProps?: { name: string }) {
|
30
|
+
if (creationProps) {
|
31
|
+
const profileGroup = Group.create({ owner: this });
|
32
|
+
profileGroup.addMember("everyone", "reader");
|
33
|
+
this.profile = CustomProfile.create(
|
34
|
+
{ name: creationProps.name, color: "blue" },
|
35
|
+
profileGroup,
|
36
|
+
);
|
37
|
+
}
|
38
|
+
}
|
44
39
|
}
|
45
|
-
}
|
46
40
|
|
47
|
-
|
48
|
-
const me = await CustomAccount.create({
|
41
|
+
const me = await createJazzTestAccount({
|
49
42
|
creationProps: { name: "Hermes Puggington" },
|
50
|
-
|
43
|
+
isCurrentActiveAccount: true,
|
44
|
+
AccountSchema: CustomAccount,
|
51
45
|
});
|
52
46
|
|
53
47
|
expect(me.profile).toBeDefined();
|
54
48
|
expect(me.profile?.name).toBe("Hermes Puggington");
|
55
49
|
expect(me.profile?.color).toBe("blue");
|
56
50
|
|
57
|
-
const group =
|
51
|
+
const group = Group.create({ owner: me });
|
58
52
|
group.addMember("everyone", "reader");
|
59
53
|
|
60
|
-
expect(group.members).toMatchObject([
|
61
|
-
{ id: me.id, role: "admin" },
|
62
|
-
{ id: "everyone", role: "reader" },
|
63
|
-
]);
|
54
|
+
expect(group.members).toMatchObject([{ id: me.id, role: "admin" }]);
|
64
55
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
});
|
72
|
-
if (meAsMember) {
|
73
|
-
expect(meAsMember.account?.profile?.name).toBe("Hermes Puggington");
|
74
|
-
expect(meAsMember.account?.profile?.color).toBe("blue");
|
75
|
-
resolve();
|
76
|
-
}
|
77
|
-
});
|
78
|
-
});
|
56
|
+
const meAsMember = group.members.find((member) => member.id === me.id);
|
57
|
+
expect((meAsMember?.account as CustomAccount).profile?.name).toBe(
|
58
|
+
"Hermes Puggington",
|
59
|
+
);
|
60
|
+
expect((meAsMember?.account as CustomAccount).profile?.color).toBe("blue");
|
61
|
+
});
|
79
62
|
|
80
|
-
|
81
|
-
|
63
|
+
test("Should throw when creating a profile with an account as owner", async () => {
|
64
|
+
class CustomAccount extends Account {
|
65
|
+
migrate(this: CustomAccount, creationProps?: { name: string }) {
|
66
|
+
if (creationProps) {
|
67
|
+
this.profile = Profile.create(
|
68
|
+
{ name: creationProps.name },
|
69
|
+
// @ts-expect-error - only groups can own profiles, but we want to also perform a runtime check
|
70
|
+
this,
|
71
|
+
);
|
72
|
+
}
|
73
|
+
}
|
82
74
|
}
|
83
75
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
expect(meAsCastMember?.account?.profile?.color).toBe("blue");
|
91
|
-
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
93
|
-
expect((map._owner as any).nMembers).toBeUndefined();
|
94
|
-
expect(map._owner.castAs(CustomGroup).nMembers).toBe(2);
|
76
|
+
await expect(() =>
|
77
|
+
CustomAccount.create({
|
78
|
+
creationProps: { name: "Hermes Puggington" },
|
79
|
+
crypto: Crypto,
|
80
|
+
}),
|
81
|
+
).rejects.toThrowError("Profiles should be owned by a group");
|
95
82
|
});
|
96
83
|
});
|
97
84
|
|
@@ -173,6 +160,42 @@ describe("Group inheritance", () => {
|
|
173
160
|
expect(mapAsReaderAfterUpdate?.title).toBe("In Grand Child");
|
174
161
|
});
|
175
162
|
|
163
|
+
test("Group.getParentGroups should return the parent groups", async () => {
|
164
|
+
const me = await Account.create({
|
165
|
+
creationProps: { name: "Test Owner" },
|
166
|
+
crypto: Crypto,
|
167
|
+
});
|
168
|
+
|
169
|
+
const grandParentGroup = Group.create({ owner: me });
|
170
|
+
const parentGroup = Group.create({ owner: me });
|
171
|
+
const childGroup = Group.create({ owner: me });
|
172
|
+
|
173
|
+
childGroup.extend(parentGroup);
|
174
|
+
parentGroup.extend(grandParentGroup);
|
175
|
+
|
176
|
+
const parentGroups = childGroup.getParentGroups();
|
177
|
+
|
178
|
+
expect(parentGroups).toHaveLength(1);
|
179
|
+
expect(parentGroups).toContainEqual(
|
180
|
+
expect.objectContaining({ id: parentGroup.id }),
|
181
|
+
);
|
182
|
+
|
183
|
+
expect(parentGroups[0]?.getParentGroups()).toContainEqual(
|
184
|
+
expect.objectContaining({ id: grandParentGroup.id }),
|
185
|
+
);
|
186
|
+
});
|
187
|
+
|
188
|
+
test("Account.getParentGroups should return an empty array", async () => {
|
189
|
+
const account = await Account.create({
|
190
|
+
creationProps: { name: "Test Account" },
|
191
|
+
crypto: Crypto,
|
192
|
+
});
|
193
|
+
|
194
|
+
const parentGroups = account.getParentGroups();
|
195
|
+
|
196
|
+
expect(parentGroups).toEqual([]);
|
197
|
+
});
|
198
|
+
|
176
199
|
test("waitForSync should resolve when the value is uploaded", async () => {
|
177
200
|
const { clientNode, serverNode, clientAccount } = await setupTwoNodes();
|
178
201
|
|
@@ -192,56 +215,373 @@ describe("Group inheritance", () => {
|
|
192
215
|
const group = Group.create();
|
193
216
|
group.addMember("everyone", "reader");
|
194
217
|
|
195
|
-
expect(group.
|
196
|
-
id: "everyone",
|
197
|
-
role: "reader",
|
198
|
-
account: undefined,
|
199
|
-
ref: undefined,
|
200
|
-
});
|
218
|
+
expect(group.getRoleOf("everyone")).toBe("reader");
|
201
219
|
|
202
220
|
group.addMember("everyone", "writer");
|
203
221
|
|
204
|
-
expect(group.
|
205
|
-
id: "everyone",
|
206
|
-
role: "writer",
|
207
|
-
account: undefined,
|
208
|
-
ref: undefined,
|
209
|
-
});
|
222
|
+
expect(group.getRoleOf("everyone")).toBe("writer");
|
210
223
|
|
211
224
|
// @ts-expect-error - admin is not a valid role for everyone
|
212
225
|
expect(() => group.addMember("everyone", "admin")).toThrow();
|
213
226
|
|
214
|
-
expect(group.
|
215
|
-
id: "everyone",
|
216
|
-
role: "writer",
|
217
|
-
account: undefined,
|
218
|
-
ref: undefined,
|
219
|
-
});
|
227
|
+
expect(group.getRoleOf("everyone")).toBe("writer");
|
220
228
|
|
221
229
|
// @ts-expect-error - writeOnly is not a valid role for everyone
|
222
230
|
expect(() => group.addMember("everyone", "writeOnly")).toThrow();
|
223
231
|
|
224
|
-
expect(group.
|
225
|
-
id: "everyone",
|
226
|
-
role: "writer",
|
227
|
-
account: undefined,
|
228
|
-
ref: undefined,
|
229
|
-
});
|
232
|
+
expect(group.getRoleOf("everyone")).toBe("writer");
|
230
233
|
});
|
231
234
|
|
232
235
|
test("typescript should show an error when adding a member with a non-account role", async () => {
|
233
236
|
const account = await createJazzTestAccount({});
|
237
|
+
await account.waitForAllCoValuesSync();
|
234
238
|
|
235
239
|
const group = Group.create();
|
236
240
|
|
237
241
|
// @ts-expect-error - Even though readerInvite is a valid role for an account, we don't allow it to not create confusion when using the intellisense
|
238
242
|
group.addMember(account, "readerInvite");
|
239
243
|
|
240
|
-
expect(group.members).toContainEqual(
|
244
|
+
expect(group.members).not.toContainEqual(
|
241
245
|
expect.objectContaining({
|
242
246
|
id: account.id,
|
243
247
|
role: "readerInvite",
|
244
248
|
}),
|
245
249
|
);
|
250
|
+
|
251
|
+
expect(group.getRoleOf(account.id)).toBe("readerInvite");
|
252
|
+
});
|
253
|
+
});
|
254
|
+
|
255
|
+
describe("Group.getRoleOf", () => {
|
256
|
+
beforeEach(async () => {
|
257
|
+
await createJazzTestAccount({ isCurrentActiveAccount: true });
|
258
|
+
});
|
259
|
+
|
260
|
+
test("returns correct role for admin", async () => {
|
261
|
+
const group = Group.create();
|
262
|
+
const admin = await createJazzTestAccount({});
|
263
|
+
await admin.waitForAllCoValuesSync();
|
264
|
+
group.addMember(admin, "admin");
|
265
|
+
expect(group.getRoleOf(admin.id)).toBe("admin");
|
266
|
+
expect(group.getRoleOf("me")).toBe("admin");
|
267
|
+
});
|
268
|
+
|
269
|
+
test("returns correct role for writer", async () => {
|
270
|
+
const group = Group.create();
|
271
|
+
const writer = await createJazzTestAccount({});
|
272
|
+
await writer.waitForAllCoValuesSync();
|
273
|
+
group.addMember(writer, "writer");
|
274
|
+
expect(group.getRoleOf(writer.id)).toBe("writer");
|
275
|
+
});
|
276
|
+
|
277
|
+
test("returns correct role for reader", async () => {
|
278
|
+
const group = Group.create();
|
279
|
+
const reader = await createJazzTestAccount({});
|
280
|
+
await reader.waitForAllCoValuesSync();
|
281
|
+
group.addMember(reader, "reader");
|
282
|
+
expect(group.getRoleOf(reader.id)).toBe("reader");
|
283
|
+
});
|
284
|
+
|
285
|
+
test("returns correct role for writeOnly", async () => {
|
286
|
+
const group = Group.create();
|
287
|
+
const writeOnly = await createJazzTestAccount({});
|
288
|
+
await writeOnly.waitForAllCoValuesSync();
|
289
|
+
group.addMember(writeOnly, "writeOnly");
|
290
|
+
expect(group.getRoleOf(writeOnly.id)).toBe("writeOnly");
|
291
|
+
});
|
292
|
+
|
293
|
+
test("returns correct role for everyone", () => {
|
294
|
+
const group = Group.create();
|
295
|
+
group.addMember("everyone", "reader");
|
296
|
+
expect(group.getRoleOf("everyone")).toBe("reader");
|
297
|
+
});
|
298
|
+
});
|
299
|
+
|
300
|
+
describe("Group.getRoleOf with 'me' parameter", () => {
|
301
|
+
beforeEach(async () => {
|
302
|
+
await createJazzTestAccount({ isCurrentActiveAccount: true });
|
303
|
+
});
|
304
|
+
|
305
|
+
test("returns correct role for 'me' when current account is admin", () => {
|
306
|
+
const group = Group.create();
|
307
|
+
expect(group.getRoleOf("me")).toBe("admin");
|
308
|
+
});
|
309
|
+
|
310
|
+
test("returns correct role for 'me' when current account is writer", async () => {
|
311
|
+
const account = await createJazzTestAccount();
|
312
|
+
await account.waitForAllCoValuesSync();
|
313
|
+
const group = Group.create({ owner: account });
|
314
|
+
|
315
|
+
group.addMember(Account.getMe(), "writer");
|
316
|
+
|
317
|
+
expect(group.getRoleOf("me")).toBe("writer");
|
318
|
+
});
|
319
|
+
|
320
|
+
test("returns correct role for 'me' when current account is reader", async () => {
|
321
|
+
const account = await createJazzTestAccount();
|
322
|
+
await account.waitForAllCoValuesSync();
|
323
|
+
const group = Group.create({ owner: account });
|
324
|
+
|
325
|
+
group.addMember(Account.getMe(), "reader");
|
326
|
+
|
327
|
+
expect(group.getRoleOf("me")).toBe("reader");
|
328
|
+
});
|
329
|
+
|
330
|
+
test("returns undefined for 'me' when current account has no role", async () => {
|
331
|
+
const account = await createJazzTestAccount();
|
332
|
+
await account.waitForAllCoValuesSync();
|
333
|
+
const group = Group.create({ owner: account });
|
334
|
+
|
335
|
+
expect(group.getRoleOf("me")).toBeUndefined();
|
336
|
+
});
|
337
|
+
});
|
338
|
+
|
339
|
+
describe("Account permissions", () => {
|
340
|
+
beforeEach(async () => {
|
341
|
+
await createJazzTestAccount({ isCurrentActiveAccount: true });
|
342
|
+
});
|
343
|
+
|
344
|
+
test("getRoleOf returns admin only for self and me", async () => {
|
345
|
+
const account = await Account.create({
|
346
|
+
creationProps: { name: "Test Account" },
|
347
|
+
crypto: Crypto,
|
348
|
+
});
|
349
|
+
|
350
|
+
// Account should be admin of itself
|
351
|
+
expect(account.getRoleOf(account.id)).toBe("admin");
|
352
|
+
|
353
|
+
// The GlobalMe is not this account
|
354
|
+
expect(account.getRoleOf("me")).toBe(undefined);
|
355
|
+
expect(Account.getMe().getRoleOf("me")).toBe("admin");
|
356
|
+
|
357
|
+
// Other accounts should have no role
|
358
|
+
const otherAccount = await Account.create({
|
359
|
+
creationProps: { name: "Other Account" },
|
360
|
+
crypto: Crypto,
|
361
|
+
});
|
362
|
+
expect(account.getRoleOf(otherAccount.id)).toBeUndefined();
|
363
|
+
|
364
|
+
// Everyone should have no role
|
365
|
+
expect(account.getRoleOf("everyone")).toBeUndefined();
|
366
|
+
});
|
367
|
+
|
368
|
+
test("members array only contains self as admin", async () => {
|
369
|
+
const account = await Account.create({
|
370
|
+
creationProps: { name: "Test Account" },
|
371
|
+
crypto: Crypto,
|
372
|
+
});
|
373
|
+
|
374
|
+
expect(account.members).toEqual([
|
375
|
+
{ id: account.id, role: "admin", account: account, ref: expect.any(Ref) },
|
376
|
+
]);
|
377
|
+
});
|
378
|
+
});
|
379
|
+
|
380
|
+
describe("Account permissions", () => {
|
381
|
+
test("canRead permissions for different roles", async () => {
|
382
|
+
// Create test accounts
|
383
|
+
const admin = await Account.create({
|
384
|
+
creationProps: { name: "Admin" },
|
385
|
+
crypto: Crypto,
|
386
|
+
});
|
387
|
+
|
388
|
+
const group = Group.create({ owner: admin });
|
389
|
+
const testObject = CoMap.create({}, { owner: group });
|
390
|
+
|
391
|
+
const writer = await Account.createAs(admin, {
|
392
|
+
creationProps: { name: "Writer" },
|
393
|
+
});
|
394
|
+
const reader = await Account.createAs(admin, {
|
395
|
+
creationProps: { name: "Reader" },
|
396
|
+
});
|
397
|
+
const writeOnly = await Account.createAs(admin, {
|
398
|
+
creationProps: { name: "WriteOnly" },
|
399
|
+
});
|
400
|
+
|
401
|
+
// Set up roles
|
402
|
+
group.addMember(writer, "writer");
|
403
|
+
group.addMember(reader, "reader");
|
404
|
+
group.addMember(writeOnly, "writeOnly");
|
405
|
+
|
406
|
+
// Test canRead permissions
|
407
|
+
expect(admin.canRead(testObject)).toBe(true);
|
408
|
+
expect(writer.canRead(testObject)).toBe(true);
|
409
|
+
expect(reader.canRead(testObject)).toBe(true);
|
410
|
+
expect(writeOnly.canRead(testObject)).toBe(true);
|
411
|
+
});
|
412
|
+
|
413
|
+
test("canWrite permissions for different roles", async () => {
|
414
|
+
// Create test accounts
|
415
|
+
const admin = await Account.create({
|
416
|
+
creationProps: { name: "Admin" },
|
417
|
+
crypto: Crypto,
|
418
|
+
});
|
419
|
+
|
420
|
+
const group = Group.create({ owner: admin });
|
421
|
+
const testObject = CoMap.create({}, { owner: group });
|
422
|
+
|
423
|
+
const writer = await Account.createAs(admin, {
|
424
|
+
creationProps: { name: "Writer" },
|
425
|
+
});
|
426
|
+
const reader = await Account.createAs(admin, {
|
427
|
+
creationProps: { name: "Reader" },
|
428
|
+
});
|
429
|
+
const writeOnly = await Account.createAs(admin, {
|
430
|
+
creationProps: { name: "WriteOnly" },
|
431
|
+
});
|
432
|
+
|
433
|
+
// Set up roles
|
434
|
+
group.addMember(writer, "writer");
|
435
|
+
group.addMember(reader, "reader");
|
436
|
+
group.addMember(writeOnly, "writeOnly");
|
437
|
+
|
438
|
+
// Test canWrite permissions
|
439
|
+
expect(admin.canWrite(testObject)).toBe(true);
|
440
|
+
expect(writer.canWrite(testObject)).toBe(true);
|
441
|
+
expect(reader.canWrite(testObject)).toBe(false);
|
442
|
+
expect(writeOnly.canWrite(testObject)).toBe(true);
|
443
|
+
});
|
444
|
+
|
445
|
+
test("canAdmin permissions for different roles", async () => {
|
446
|
+
// Create test accounts
|
447
|
+
const admin = await Account.create({
|
448
|
+
creationProps: { name: "Admin" },
|
449
|
+
crypto: Crypto,
|
450
|
+
});
|
451
|
+
|
452
|
+
const group = Group.create({ owner: admin });
|
453
|
+
const testObject = CoMap.create({}, { owner: group });
|
454
|
+
|
455
|
+
const writer = await Account.createAs(admin, {
|
456
|
+
creationProps: { name: "Writer" },
|
457
|
+
});
|
458
|
+
const reader = await Account.createAs(admin, {
|
459
|
+
creationProps: { name: "Reader" },
|
460
|
+
});
|
461
|
+
const writeOnly = await Account.createAs(admin, {
|
462
|
+
creationProps: { name: "WriteOnly" },
|
463
|
+
});
|
464
|
+
|
465
|
+
// Set up roles
|
466
|
+
group.addMember(writer, "writer");
|
467
|
+
group.addMember(reader, "reader");
|
468
|
+
group.addMember(writeOnly, "writeOnly");
|
469
|
+
|
470
|
+
// Test canAdmin permissions
|
471
|
+
expect(admin.canAdmin(testObject)).toBe(true);
|
472
|
+
expect(writer.canAdmin(testObject)).toBe(false);
|
473
|
+
expect(reader.canAdmin(testObject)).toBe(false);
|
474
|
+
expect(writeOnly.canAdmin(testObject)).toBe(false);
|
475
|
+
});
|
476
|
+
|
477
|
+
test("permissions for non-members", async () => {
|
478
|
+
const admin = await Account.create({
|
479
|
+
creationProps: { name: "Admin" },
|
480
|
+
crypto: Crypto,
|
481
|
+
});
|
482
|
+
|
483
|
+
const group = Group.create({ owner: admin });
|
484
|
+
const testObject = CoMap.create({}, { owner: group });
|
485
|
+
|
486
|
+
const nonMember = await Account.createAs(admin, {
|
487
|
+
creationProps: { name: "NonMember" },
|
488
|
+
});
|
489
|
+
|
490
|
+
// Test permissions for non-member
|
491
|
+
expect(nonMember.canRead(testObject)).toBe(false);
|
492
|
+
expect(nonMember.canWrite(testObject)).toBe(false);
|
493
|
+
expect(nonMember.canAdmin(testObject)).toBe(false);
|
494
|
+
});
|
495
|
+
});
|
496
|
+
|
497
|
+
describe("Group.members", () => {
|
498
|
+
test("should return the members of the group", async () => {
|
499
|
+
const childGroup = Group.create();
|
500
|
+
|
501
|
+
const bob = await createJazzTestAccount({});
|
502
|
+
await bob.waitForAllCoValuesSync();
|
503
|
+
|
504
|
+
childGroup.addMember(bob, "reader");
|
505
|
+
expect(childGroup.getRoleOf(bob.id)).toBe("reader");
|
506
|
+
|
507
|
+
expect(childGroup.members).toEqual([
|
508
|
+
expect.objectContaining({
|
509
|
+
account: expect.objectContaining({
|
510
|
+
id: Account.getMe().id,
|
511
|
+
}),
|
512
|
+
role: "admin",
|
513
|
+
}),
|
514
|
+
expect.objectContaining({
|
515
|
+
account: expect.objectContaining({
|
516
|
+
id: bob.id,
|
517
|
+
}),
|
518
|
+
role: "reader",
|
519
|
+
}),
|
520
|
+
]);
|
521
|
+
});
|
522
|
+
|
523
|
+
test("should return the members of the parent group", async () => {
|
524
|
+
const childGroup = Group.create();
|
525
|
+
const parentGroup = Group.create();
|
526
|
+
|
527
|
+
const bob = await createJazzTestAccount({});
|
528
|
+
await bob.waitForAllCoValuesSync();
|
529
|
+
|
530
|
+
parentGroup.addMember(bob, "writer");
|
531
|
+
childGroup.extend(parentGroup, "reader");
|
532
|
+
|
533
|
+
expect(childGroup.getRoleOf(bob.id)).toBe("reader");
|
534
|
+
|
535
|
+
expect(childGroup.members).toEqual([
|
536
|
+
expect.objectContaining({
|
537
|
+
account: expect.objectContaining({
|
538
|
+
id: Account.getMe().id,
|
539
|
+
}),
|
540
|
+
role: "admin",
|
541
|
+
}),
|
542
|
+
expect.objectContaining({
|
543
|
+
account: expect.objectContaining({
|
544
|
+
id: bob.id,
|
545
|
+
}),
|
546
|
+
role: "reader",
|
547
|
+
}),
|
548
|
+
]);
|
549
|
+
});
|
550
|
+
|
551
|
+
test("should not return everyone", async () => {
|
552
|
+
const childGroup = Group.create();
|
553
|
+
|
554
|
+
childGroup.addMember("everyone", "reader");
|
555
|
+
expect(childGroup.getRoleOf("everyone")).toBe("reader");
|
556
|
+
|
557
|
+
expect(childGroup.members).toEqual([
|
558
|
+
expect.objectContaining({
|
559
|
+
account: expect.objectContaining({
|
560
|
+
id: Account.getMe().id,
|
561
|
+
}),
|
562
|
+
role: "admin",
|
563
|
+
}),
|
564
|
+
]);
|
565
|
+
});
|
566
|
+
|
567
|
+
test("should not return revoked members", async () => {
|
568
|
+
const childGroup = Group.create();
|
569
|
+
|
570
|
+
const bob = await createJazzTestAccount({});
|
571
|
+
await bob.waitForAllCoValuesSync();
|
572
|
+
|
573
|
+
childGroup.addMember(bob, "reader");
|
574
|
+
await childGroup.removeMember(bob);
|
575
|
+
|
576
|
+
expect(childGroup.getRoleOf(bob.id)).toBeUndefined();
|
577
|
+
|
578
|
+
expect(childGroup.members).toEqual([
|
579
|
+
expect.objectContaining({
|
580
|
+
account: expect.objectContaining({
|
581
|
+
id: Account.getMe().id,
|
582
|
+
}),
|
583
|
+
role: "admin",
|
584
|
+
}),
|
585
|
+
]);
|
246
586
|
});
|
247
587
|
});
|
package/src/tests/inbox.test.ts
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
2
|
+
import { Account } from "../coValues/account";
|
2
3
|
import { CoMap } from "../coValues/coMap";
|
3
4
|
import { Group } from "../coValues/group";
|
4
5
|
import { Inbox, InboxSender } from "../coValues/inbox";
|
6
|
+
import { Profile } from "../exports";
|
5
7
|
import { co } from "../internal";
|
6
8
|
import { setupTwoNodes, waitFor } from "./utils";
|
7
9
|
|
@@ -10,6 +12,28 @@ class Message extends CoMap {
|
|
10
12
|
}
|
11
13
|
|
12
14
|
describe("Inbox", () => {
|
15
|
+
describe("Private profile", () => {
|
16
|
+
it("Should throw if the inbox owner profile is private", async () => {
|
17
|
+
class WorkerAccount extends Account {
|
18
|
+
migrate() {
|
19
|
+
this.profile = Profile.create(
|
20
|
+
{ name: "Worker" },
|
21
|
+
Group.create({ owner: this }),
|
22
|
+
);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
const { clientAccount: sender, serverAccount: receiver } =
|
27
|
+
await setupTwoNodes({
|
28
|
+
ServerAccountSchema: WorkerAccount,
|
29
|
+
});
|
30
|
+
|
31
|
+
await expect(() => InboxSender.load(receiver.id, sender)).rejects.toThrow(
|
32
|
+
"Insufficient permissions to access the inbox, make sure its user profile is publicly readable.",
|
33
|
+
);
|
34
|
+
});
|
35
|
+
});
|
36
|
+
|
13
37
|
it("should create inbox and allow message exchange between accounts", async () => {
|
14
38
|
const { clientAccount: sender, serverAccount: receiver } =
|
15
39
|
await setupTwoNodes();
|