jazz-tools 0.18.29 → 0.18.31
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/.svelte-kit/__package__/media/image.svelte +7 -4
- package/.svelte-kit/__package__/media/image.svelte.d.ts.map +1 -1
- package/.svelte-kit/__package__/media/image.types.d.ts +1 -0
- package/.svelte-kit/__package__/media/image.types.d.ts.map +1 -1
- package/.svelte-kit/__package__/tests/media/image.svelte.test.js +63 -0
- package/.turbo/turbo-build.log +60 -60
- package/CHANGELOG.md +26 -0
- package/dist/better-auth/auth/client.d.ts +1 -1
- package/dist/better-auth/auth/server.d.ts +1 -1
- package/dist/better-auth/auth/server.d.ts.map +1 -1
- package/dist/better-auth/auth/server.js.map +1 -1
- package/dist/better-auth/database-adapter/index.d.ts +3 -3
- package/dist/better-auth/database-adapter/index.d.ts.map +1 -1
- package/dist/better-auth/database-adapter/index.js +6 -2
- package/dist/better-auth/database-adapter/index.js.map +1 -1
- package/dist/better-auth/database-adapter/utils.d.ts.map +1 -1
- package/dist/browser/index.d.ts +2 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/{chunk-F55R554M.js → chunk-6BIYT3KH.js} +51 -30
- package/dist/chunk-6BIYT3KH.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/inspector/{custom-element-35MDW4SW.js → custom-element-RQTLPAPJ.js} +584 -298
- package/dist/inspector/custom-element-RQTLPAPJ.js.map +1 -0
- package/dist/inspector/index.js +570 -338
- package/dist/inspector/index.js.map +1 -1
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/inspector/ui/index.d.ts +6 -0
- package/dist/inspector/ui/index.d.ts.map +1 -0
- package/dist/inspector/viewer/group-view.d.ts +3 -2
- package/dist/inspector/viewer/group-view.d.ts.map +1 -1
- package/dist/inspector/viewer/page.d.ts.map +1 -1
- package/dist/react/index.js +2 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react/media/image.d.ts +8 -0
- package/dist/react/media/image.d.ts.map +1 -1
- package/dist/react-native-core/index.js +3 -3
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/media/image.d.ts +15 -0
- package/dist/react-native-core/media/image.d.ts.map +1 -1
- package/dist/svelte/media/image.svelte +7 -4
- package/dist/svelte/media/image.svelte.d.ts.map +1 -1
- package/dist/svelte/media/image.types.d.ts +1 -0
- package/dist/svelte/media/image.types.d.ts.map +1 -1
- package/dist/svelte/tests/media/image.svelte.test.js +63 -0
- package/dist/testing.js +8 -1
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/account.d.ts +1 -0
- package/dist/tools/coValues/account.d.ts.map +1 -1
- package/dist/tools/coValues/group.d.ts +3 -3
- package/dist/tools/coValues/group.d.ts.map +1 -1
- package/dist/tools/implementation/invites.d.ts +2 -2
- package/dist/tools/implementation/invites.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.d.ts +1 -1
- package/dist/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.d.ts +3 -1
- package/dist/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/zodReExport.d.ts +1 -1
- package/dist/tools/implementation/zodSchema/zodReExport.d.ts.map +1 -1
- package/dist/tools/subscribe/CoValueCoreSubscription.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +0 -2
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/testing.d.ts +1 -0
- package/dist/tools/testing.d.ts.map +1 -1
- package/dist/tools/tests/CoValueCoreSubscription.test.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/better-auth/auth/server.ts +7 -2
- package/src/better-auth/auth/tests/server.test.ts +39 -17
- package/src/better-auth/database-adapter/index.ts +8 -5
- package/src/better-auth/database-adapter/utils.ts +4 -0
- package/src/browser/index.ts +2 -1
- package/src/inspector/ui/index.ts +5 -0
- package/src/inspector/viewer/group-view.tsx +304 -20
- package/src/inspector/viewer/new-app.tsx +4 -4
- package/src/inspector/viewer/page.tsx +16 -2
- package/src/react/media/image.tsx +11 -2
- package/src/react/tests/media/image.test.tsx +94 -0
- package/src/react-native-core/media/image.tsx +11 -3
- package/src/svelte/media/image.svelte +7 -4
- package/src/svelte/media/image.types.ts +1 -0
- package/src/svelte/tests/media/image.svelte.test.ts +85 -0
- package/src/tools/coValues/account.ts +30 -5
- package/src/tools/coValues/group.ts +13 -12
- package/src/tools/coValues/inbox.ts +5 -5
- package/src/tools/implementation/invites.ts +3 -8
- package/src/tools/implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.ts +5 -1
- package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -0
- package/src/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.ts +63 -50
- package/src/tools/implementation/zodSchema/zodReExport.ts +2 -2
- package/src/tools/subscribe/CoValueCoreSubscription.ts +17 -0
- package/src/tools/subscribe/SubscriptionScope.ts +1 -27
- package/src/tools/testing.ts +7 -0
- package/src/tools/{subscribe → tests}/CoValueCoreSubscription.test.ts +233 -3
- package/src/tools/tests/coFeed.branch.test.ts +14 -5
- package/src/tools/tests/coMap.test.ts +139 -42
- package/src/tools/tests/coOptional.test.ts +9 -1
- package/src/tools/tests/groupsAndAccounts.test.ts +156 -1
- package/src/tools/tests/load.test.ts +198 -1
- package/src/tools/tests/zod.test-d.ts +0 -2
- package/src/tools/tests/zod.test.ts +43 -40
- package/dist/chunk-F55R554M.js.map +0 -1
- package/dist/inspector/custom-element-35MDW4SW.js.map +0 -1
- package/dist/tools/subscribe/CoValueCoreSubscription.test.d.ts.map +0 -1
- /package/dist/tools/{subscribe → tests}/CoValueCoreSubscription.test.d.ts +0 -0
|
@@ -481,6 +481,9 @@ describe("Account permissions", () => {
|
|
|
481
481
|
const group = Group.create({ owner: admin });
|
|
482
482
|
const testObject = CoMap.create({}, { owner: group });
|
|
483
483
|
|
|
484
|
+
const manager = await co.account().createAs(admin, {
|
|
485
|
+
creationProps: { name: "Manager" },
|
|
486
|
+
});
|
|
484
487
|
const writer = await co.account().createAs(admin, {
|
|
485
488
|
creationProps: { name: "Writer" },
|
|
486
489
|
});
|
|
@@ -492,11 +495,13 @@ describe("Account permissions", () => {
|
|
|
492
495
|
});
|
|
493
496
|
|
|
494
497
|
// Set up roles
|
|
498
|
+
group.addMember(manager, "manager");
|
|
495
499
|
group.addMember(writer, "writer");
|
|
496
500
|
group.addMember(reader, "reader");
|
|
497
501
|
group.addMember(writeOnly, "writeOnly");
|
|
498
502
|
|
|
499
503
|
// Test canRead permissions
|
|
504
|
+
expect(manager.canRead(testObject)).toBe(true);
|
|
500
505
|
expect(admin.canRead(testObject)).toBe(true);
|
|
501
506
|
expect(writer.canRead(testObject)).toBe(true);
|
|
502
507
|
expect(reader.canRead(testObject)).toBe(true);
|
|
@@ -513,6 +518,9 @@ describe("Account permissions", () => {
|
|
|
513
518
|
const group = Group.create({ owner: admin });
|
|
514
519
|
const testObject = CoMap.create({}, { owner: group });
|
|
515
520
|
|
|
521
|
+
const manager = await co.account().createAs(admin, {
|
|
522
|
+
creationProps: { name: "Manager" },
|
|
523
|
+
});
|
|
516
524
|
const writer = await co.account().createAs(admin, {
|
|
517
525
|
creationProps: { name: "Writer" },
|
|
518
526
|
});
|
|
@@ -524,11 +532,13 @@ describe("Account permissions", () => {
|
|
|
524
532
|
});
|
|
525
533
|
|
|
526
534
|
// Set up roles
|
|
535
|
+
group.addMember(manager, "manager");
|
|
527
536
|
group.addMember(writer, "writer");
|
|
528
537
|
group.addMember(reader, "reader");
|
|
529
538
|
group.addMember(writeOnly, "writeOnly");
|
|
530
539
|
|
|
531
540
|
// Test canWrite permissions
|
|
541
|
+
expect(manager.canWrite(testObject)).toBe(true);
|
|
532
542
|
expect(admin.canWrite(testObject)).toBe(true);
|
|
533
543
|
expect(writer.canWrite(testObject)).toBe(true);
|
|
534
544
|
expect(reader.canWrite(testObject)).toBe(false);
|
|
@@ -538,13 +548,17 @@ describe("Account permissions", () => {
|
|
|
538
548
|
test("canAdmin permissions for different roles", async () => {
|
|
539
549
|
// Create test accounts
|
|
540
550
|
const admin = await co.account().create({
|
|
541
|
-
creationProps: { name: "Admin" },
|
|
551
|
+
creationProps: { name: "Super Admin" },
|
|
542
552
|
crypto: Crypto,
|
|
543
553
|
});
|
|
544
554
|
|
|
545
555
|
const group = Group.create({ owner: admin });
|
|
546
556
|
const testObject = CoMap.create({}, { owner: group });
|
|
547
557
|
|
|
558
|
+
const manager = await co.account().createAs(admin, {
|
|
559
|
+
creationProps: { name: "Admin" },
|
|
560
|
+
});
|
|
561
|
+
|
|
548
562
|
const writer = await co.account().createAs(admin, {
|
|
549
563
|
creationProps: { name: "Writer" },
|
|
550
564
|
});
|
|
@@ -556,17 +570,57 @@ describe("Account permissions", () => {
|
|
|
556
570
|
});
|
|
557
571
|
|
|
558
572
|
// Set up roles
|
|
573
|
+
group.addMember(manager, "manager");
|
|
559
574
|
group.addMember(writer, "writer");
|
|
560
575
|
group.addMember(reader, "reader");
|
|
561
576
|
group.addMember(writeOnly, "writeOnly");
|
|
562
577
|
|
|
563
578
|
// Test canAdmin permissions
|
|
564
579
|
expect(admin.canAdmin(testObject)).toBe(true);
|
|
580
|
+
expect(manager.canAdmin(testObject)).toBe(false);
|
|
565
581
|
expect(writer.canAdmin(testObject)).toBe(false);
|
|
566
582
|
expect(reader.canAdmin(testObject)).toBe(false);
|
|
567
583
|
expect(writeOnly.canAdmin(testObject)).toBe(false);
|
|
568
584
|
});
|
|
569
585
|
|
|
586
|
+
test("canManage permissions for different roles", async () => {
|
|
587
|
+
// Create test accounts
|
|
588
|
+
const admin = await co.account().create({
|
|
589
|
+
creationProps: { name: "Super Admin" },
|
|
590
|
+
crypto: Crypto,
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
const group = Group.create({ owner: admin });
|
|
594
|
+
const testObject = CoMap.create({}, { owner: group });
|
|
595
|
+
|
|
596
|
+
const manager = await co.account().createAs(admin, {
|
|
597
|
+
creationProps: { name: "Admin" },
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
const writer = await co.account().createAs(admin, {
|
|
601
|
+
creationProps: { name: "Writer" },
|
|
602
|
+
});
|
|
603
|
+
const reader = await co.account().createAs(admin, {
|
|
604
|
+
creationProps: { name: "Reader" },
|
|
605
|
+
});
|
|
606
|
+
const writeOnly = await co.account().createAs(admin, {
|
|
607
|
+
creationProps: { name: "WriteOnly" },
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// Set up roles
|
|
611
|
+
group.addMember(manager, "manager");
|
|
612
|
+
group.addMember(writer, "writer");
|
|
613
|
+
group.addMember(reader, "reader");
|
|
614
|
+
group.addMember(writeOnly, "writeOnly");
|
|
615
|
+
|
|
616
|
+
// Test canManage permissions
|
|
617
|
+
expect(admin.canManage(testObject)).toBe(true);
|
|
618
|
+
expect(manager.canManage(testObject)).toBe(true);
|
|
619
|
+
expect(writer.canManage(testObject)).toBe(false);
|
|
620
|
+
expect(reader.canManage(testObject)).toBe(false);
|
|
621
|
+
expect(writeOnly.canManage(testObject)).toBe(false);
|
|
622
|
+
});
|
|
623
|
+
|
|
570
624
|
test("permissions for non-members", async () => {
|
|
571
625
|
const admin = await co.account().create({
|
|
572
626
|
creationProps: { name: "Admin" },
|
|
@@ -584,6 +638,7 @@ describe("Account permissions", () => {
|
|
|
584
638
|
expect(nonMember.canRead(testObject)).toBe(false);
|
|
585
639
|
expect(nonMember.canWrite(testObject)).toBe(false);
|
|
586
640
|
expect(nonMember.canAdmin(testObject)).toBe(false);
|
|
641
|
+
expect(nonMember.canManage(testObject)).toBe(false);
|
|
587
642
|
});
|
|
588
643
|
|
|
589
644
|
describe("permissions over Groups and Accounts", () => {
|
|
@@ -810,6 +865,106 @@ describe("Account permissions", () => {
|
|
|
810
865
|
expect(account.canAdmin(group)).toBe(false);
|
|
811
866
|
});
|
|
812
867
|
});
|
|
868
|
+
|
|
869
|
+
describe("manage", () => {
|
|
870
|
+
test("can manage Account if it's itself", async () => {
|
|
871
|
+
const account = await co.account().create({
|
|
872
|
+
creationProps: { name: "Test Account" },
|
|
873
|
+
crypto: Crypto,
|
|
874
|
+
});
|
|
875
|
+
expect(account.canManage(account)).toBe(true);
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
test("cannot manage other accounts", async () => {
|
|
879
|
+
const account = await co.account().create({
|
|
880
|
+
creationProps: { name: "Test Account" },
|
|
881
|
+
crypto: Crypto,
|
|
882
|
+
});
|
|
883
|
+
const otherAccount = await co.account().create({
|
|
884
|
+
creationProps: { name: "Other Account" },
|
|
885
|
+
crypto: Crypto,
|
|
886
|
+
});
|
|
887
|
+
expect(account.canManage(otherAccount)).toBe(false);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
test("can manage Group if it's an manage for that group", async () => {
|
|
891
|
+
const account = await co.account().create({
|
|
892
|
+
creationProps: { name: "Test Account" },
|
|
893
|
+
crypto: Crypto,
|
|
894
|
+
});
|
|
895
|
+
const otherAccount = await co.account().create({
|
|
896
|
+
creationProps: { name: "Other Account" },
|
|
897
|
+
crypto: Crypto,
|
|
898
|
+
});
|
|
899
|
+
const group = Group.create({ owner: otherAccount });
|
|
900
|
+
|
|
901
|
+
group.addMember(account, "manager");
|
|
902
|
+
|
|
903
|
+
expect(account.canManage(group)).toBe(true);
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
test("cannot manage Group if it's a writer for that group", async () => {
|
|
907
|
+
const account = await co.account().create({
|
|
908
|
+
creationProps: { name: "Test Account" },
|
|
909
|
+
crypto: Crypto,
|
|
910
|
+
});
|
|
911
|
+
const otherAccount = await co.account().create({
|
|
912
|
+
creationProps: { name: "Other Account" },
|
|
913
|
+
crypto: Crypto,
|
|
914
|
+
});
|
|
915
|
+
const group = Group.create({ owner: otherAccount });
|
|
916
|
+
|
|
917
|
+
group.addMember(account, "writer");
|
|
918
|
+
|
|
919
|
+
expect(account.canManage(group)).toBe(false);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
test("cannot manage Group if it has writeOnly permissions for that group", async () => {
|
|
923
|
+
const account = await co.account().create({
|
|
924
|
+
creationProps: { name: "Test Account" },
|
|
925
|
+
crypto: Crypto,
|
|
926
|
+
});
|
|
927
|
+
const otherAccount = await co.account().create({
|
|
928
|
+
creationProps: { name: "Other Account" },
|
|
929
|
+
crypto: Crypto,
|
|
930
|
+
});
|
|
931
|
+
const group = Group.create({ owner: otherAccount });
|
|
932
|
+
|
|
933
|
+
group.addMember(account, "writeOnly");
|
|
934
|
+
|
|
935
|
+
expect(account.canManage(group)).toBe(false);
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
test("cannot manage Group if it's a reader for that group", async () => {
|
|
939
|
+
const account = await co.account().create({
|
|
940
|
+
creationProps: { name: "Test Account" },
|
|
941
|
+
crypto: Crypto,
|
|
942
|
+
});
|
|
943
|
+
const otherAccount = await co.account().create({
|
|
944
|
+
creationProps: { name: "Other Account" },
|
|
945
|
+
crypto: Crypto,
|
|
946
|
+
});
|
|
947
|
+
const group = Group.create({ owner: otherAccount });
|
|
948
|
+
|
|
949
|
+
group.addMember(account, "reader");
|
|
950
|
+
|
|
951
|
+
expect(account.canManage(group)).toBe(false);
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
test("cannot manage Group if it has no permissions for that group", async () => {
|
|
955
|
+
const account = await co.account().create({
|
|
956
|
+
creationProps: { name: "Test Account" },
|
|
957
|
+
crypto: Crypto,
|
|
958
|
+
});
|
|
959
|
+
const otherAccount = await co.account().create({
|
|
960
|
+
creationProps: { name: "Other Account" },
|
|
961
|
+
crypto: Crypto,
|
|
962
|
+
});
|
|
963
|
+
const group = Group.create({ owner: otherAccount });
|
|
964
|
+
|
|
965
|
+
expect(account.canManage(group)).toBe(false);
|
|
966
|
+
});
|
|
967
|
+
});
|
|
813
968
|
});
|
|
814
969
|
});
|
|
815
970
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { waitFor } from "@testing-library/dom";
|
|
2
2
|
import { cojsonInternals, emptyKnownState } from "cojson";
|
|
3
3
|
import { assert, beforeEach, expect, test } from "vitest";
|
|
4
|
-
import { Account, Group, co, z } from "../exports.js";
|
|
4
|
+
import { Account, Group, co, exportCoValue, z } from "../exports.js";
|
|
5
5
|
import {
|
|
6
6
|
createJazzTestAccount,
|
|
7
|
+
disableJazzTestSync,
|
|
7
8
|
getPeerConnectedToTestSyncServer,
|
|
8
9
|
setupJazzTestSync,
|
|
9
10
|
} from "../testing.js";
|
|
@@ -270,3 +271,199 @@ test("load a large coValue", async () => {
|
|
|
270
271
|
largeMap.data.$jazz.raw.core.knownState(),
|
|
271
272
|
);
|
|
272
273
|
});
|
|
274
|
+
|
|
275
|
+
test("should wait for the full streaming of the group", async () => {
|
|
276
|
+
disableJazzTestSync();
|
|
277
|
+
|
|
278
|
+
const alice = await createJazzTestAccount({
|
|
279
|
+
isCurrentActiveAccount: true,
|
|
280
|
+
creationProps: { name: "Hermes Puggington" },
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const Person = co.map({
|
|
284
|
+
name: z.string(),
|
|
285
|
+
update: z.number(),
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const group = Group.create();
|
|
289
|
+
|
|
290
|
+
const person = Person.create(
|
|
291
|
+
{
|
|
292
|
+
name: "Bob",
|
|
293
|
+
update: 1,
|
|
294
|
+
},
|
|
295
|
+
group,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// Make the group to grow big enough to trigger the streaming
|
|
299
|
+
for (let i = 0; i <= 300; i++) {
|
|
300
|
+
group.$jazz.raw.rotateReadKey();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
group.addMember("everyone", "reader");
|
|
304
|
+
|
|
305
|
+
const bob = await createJazzTestAccount({
|
|
306
|
+
isCurrentActiveAccount: true,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const personContent = await exportCoValue(Person, person.$jazz.id, {
|
|
310
|
+
loadAs: alice,
|
|
311
|
+
});
|
|
312
|
+
assert(personContent);
|
|
313
|
+
|
|
314
|
+
const lastGroupPiece = personContent.findLast(
|
|
315
|
+
(content) => content.id === group.$jazz.id,
|
|
316
|
+
);
|
|
317
|
+
assert(lastGroupPiece);
|
|
318
|
+
|
|
319
|
+
for (const content of personContent.filter(
|
|
320
|
+
(content) => content !== lastGroupPiece,
|
|
321
|
+
)) {
|
|
322
|
+
bob.$jazz.localNode.syncManager.handleNewContent(content, "import");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Simulate the streaming delay on the last piece of the group
|
|
326
|
+
setTimeout(() => {
|
|
327
|
+
bob.$jazz.localNode.syncManager.handleNewContent(lastGroupPiece, "import");
|
|
328
|
+
}, 10);
|
|
329
|
+
|
|
330
|
+
// Load the value and expect the migration to run only once
|
|
331
|
+
const loadedPerson = await Person.load(person.$jazz.id, { loadAs: bob });
|
|
332
|
+
expect(loadedPerson).not.toBeNull();
|
|
333
|
+
assert(loadedPerson);
|
|
334
|
+
|
|
335
|
+
expect(loadedPerson.$jazz.owner.$jazz.raw.core.verified.isStreaming()).toBe(
|
|
336
|
+
false,
|
|
337
|
+
);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test.skip("should wait for the full streaming of the parent groups", async () => {
|
|
341
|
+
disableJazzTestSync();
|
|
342
|
+
|
|
343
|
+
const alice = await createJazzTestAccount({
|
|
344
|
+
isCurrentActiveAccount: true,
|
|
345
|
+
creationProps: { name: "Hermes Puggington" },
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const Person = co.map({
|
|
349
|
+
name: z.string(),
|
|
350
|
+
update: z.number(),
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const parentGroup = Group.create();
|
|
354
|
+
const group = Group.create();
|
|
355
|
+
|
|
356
|
+
const person = Person.create(
|
|
357
|
+
{
|
|
358
|
+
name: "Bob",
|
|
359
|
+
update: 1,
|
|
360
|
+
},
|
|
361
|
+
group,
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Make the parent group to grow big enough to trigger the streaming
|
|
365
|
+
for (let i = 0; i <= 300; i++) {
|
|
366
|
+
parentGroup.$jazz.raw.rotateReadKey();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
group.addMember(parentGroup);
|
|
370
|
+
parentGroup.addMember("everyone", "reader");
|
|
371
|
+
|
|
372
|
+
const bob = await createJazzTestAccount({
|
|
373
|
+
isCurrentActiveAccount: true,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
const personContent = await exportCoValue(Person, person.$jazz.id, {
|
|
377
|
+
loadAs: alice,
|
|
378
|
+
});
|
|
379
|
+
assert(personContent);
|
|
380
|
+
|
|
381
|
+
const lastParentGroupPiece = personContent.findLast(
|
|
382
|
+
(content) => content.id === parentGroup.$jazz.id,
|
|
383
|
+
);
|
|
384
|
+
assert(lastParentGroupPiece);
|
|
385
|
+
|
|
386
|
+
for (const content of personContent.filter(
|
|
387
|
+
(content) => content !== lastParentGroupPiece,
|
|
388
|
+
)) {
|
|
389
|
+
bob.$jazz.localNode.syncManager.handleNewContent(content, "import");
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Simulate the streaming delay on the last piece of the parent group
|
|
393
|
+
setTimeout(() => {
|
|
394
|
+
bob.$jazz.localNode.syncManager.handleNewContent(
|
|
395
|
+
lastParentGroupPiece,
|
|
396
|
+
"import",
|
|
397
|
+
);
|
|
398
|
+
}, 10);
|
|
399
|
+
|
|
400
|
+
// Load the value and expect the migration to run only once
|
|
401
|
+
const loadedPerson = await Person.load(person.$jazz.id, { loadAs: bob });
|
|
402
|
+
expect(loadedPerson).not.toBeNull();
|
|
403
|
+
assert(loadedPerson);
|
|
404
|
+
|
|
405
|
+
expect(loadedPerson.$jazz.owner.$jazz.raw.core.verified.isStreaming()).toBe(
|
|
406
|
+
false,
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test("should correctly reject the load if after the group streaming the account has no access", async () => {
|
|
411
|
+
disableJazzTestSync();
|
|
412
|
+
|
|
413
|
+
const alice = await createJazzTestAccount({
|
|
414
|
+
isCurrentActiveAccount: true,
|
|
415
|
+
creationProps: { name: "Hermes Puggington" },
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
const Person = co.map({
|
|
419
|
+
name: z.string(),
|
|
420
|
+
update: z.number(),
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const group = Group.create();
|
|
424
|
+
|
|
425
|
+
const person = Person.create(
|
|
426
|
+
{
|
|
427
|
+
name: "Bob",
|
|
428
|
+
update: 1,
|
|
429
|
+
},
|
|
430
|
+
group,
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
group.addMember("everyone", "reader");
|
|
434
|
+
|
|
435
|
+
for (let i = 0; i <= 150; i++) {
|
|
436
|
+
group.$jazz.raw.rotateReadKey();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
group.removeMember("everyone");
|
|
440
|
+
|
|
441
|
+
const bob = await createJazzTestAccount({
|
|
442
|
+
isCurrentActiveAccount: true,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const personContent = await exportCoValue(Person, person.$jazz.id, {
|
|
446
|
+
loadAs: alice,
|
|
447
|
+
});
|
|
448
|
+
assert(personContent);
|
|
449
|
+
|
|
450
|
+
const lastGroupPiece = personContent.findLast(
|
|
451
|
+
(content) => content.id === group.$jazz.id,
|
|
452
|
+
);
|
|
453
|
+
assert(lastGroupPiece);
|
|
454
|
+
|
|
455
|
+
for (const content of personContent.filter(
|
|
456
|
+
(content) => content !== lastGroupPiece,
|
|
457
|
+
)) {
|
|
458
|
+
bob.$jazz.localNode.syncManager.handleNewContent(content, "import");
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Simulate the streaming delay on the last piece of the group
|
|
462
|
+
setTimeout(() => {
|
|
463
|
+
bob.$jazz.localNode.syncManager.handleNewContent(lastGroupPiece, "import");
|
|
464
|
+
}, 10);
|
|
465
|
+
|
|
466
|
+
// Load the value and expect the migration to run only once
|
|
467
|
+
const loadedPerson = await Person.load(person.$jazz.id, { loadAs: bob });
|
|
468
|
+
expect(loadedPerson).toBeNull();
|
|
469
|
+
});
|
|
@@ -10,7 +10,6 @@ describe("CoValue and Zod schema compatibility", () => {
|
|
|
10
10
|
|
|
11
11
|
const Person = co.map({
|
|
12
12
|
// @ts-expect-error: cannot use z.record with a CoValue schema
|
|
13
|
-
// (z.record is not exported by jazz-tools)
|
|
14
13
|
pets: z.record(z.string(), Dog),
|
|
15
14
|
});
|
|
16
15
|
});
|
|
@@ -68,7 +67,6 @@ describe("CoValue and Zod schema compatibility", () => {
|
|
|
68
67
|
|
|
69
68
|
const Person = co.map({
|
|
70
69
|
// @ts-expect-error: cannot use z.intersection with a CoValue schema
|
|
71
|
-
// (z.intersection is not exported by jazz-tools)
|
|
72
70
|
pets: z.intersection(Dog, Cat),
|
|
73
71
|
});
|
|
74
72
|
});
|
|
@@ -369,6 +369,18 @@ describe("co.map and Zod schema compatibility", () => {
|
|
|
369
369
|
expect(map.person).toEqual({ name: "John" });
|
|
370
370
|
});
|
|
371
371
|
|
|
372
|
+
it("should handle record fields", async () => {
|
|
373
|
+
const schema = co.map({
|
|
374
|
+
record: z.record(z.string(), z.string()),
|
|
375
|
+
});
|
|
376
|
+
const account = await createJazzTestAccount();
|
|
377
|
+
const map = schema.create(
|
|
378
|
+
{ record: { key1: "value1", key2: "value2" } },
|
|
379
|
+
account,
|
|
380
|
+
);
|
|
381
|
+
expect(map.record).toEqual({ key1: "value1", key2: "value2" });
|
|
382
|
+
});
|
|
383
|
+
|
|
372
384
|
it("should handle tuple fields", async () => {
|
|
373
385
|
const schema = co.map({
|
|
374
386
|
tuple: z.tuple([z.string(), z.number(), z.boolean()]),
|
|
@@ -402,46 +414,37 @@ describe("co.map and Zod schema compatibility", () => {
|
|
|
402
414
|
expect(map2.value).toBe(42);
|
|
403
415
|
});
|
|
404
416
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
// it("should handle record types", async () => {
|
|
438
|
-
// const schema = co.map({
|
|
439
|
-
// cache: z.record(z.string(), z.string()),
|
|
440
|
-
// });
|
|
441
|
-
// const account = await createJazzTestAccount();
|
|
442
|
-
// const map = schema.create({ cache: { key1: "value1", key2: "value2" } }, account);
|
|
443
|
-
// expect(map.cache).toEqual({ key1: "value1", key2: "value2" });
|
|
444
|
-
// });
|
|
417
|
+
it("should handle discriminated unions of primitives", async () => {
|
|
418
|
+
const schema = co.map({
|
|
419
|
+
result: z.discriminatedUnion("status", [
|
|
420
|
+
z.object({ status: z.literal("success"), data: z.string() }),
|
|
421
|
+
z.object({ status: z.literal("failed"), error: z.string() }),
|
|
422
|
+
]),
|
|
423
|
+
});
|
|
424
|
+
const account = await createJazzTestAccount();
|
|
425
|
+
const successMap = schema.create(
|
|
426
|
+
{ result: { status: "success", data: "data" } },
|
|
427
|
+
account,
|
|
428
|
+
);
|
|
429
|
+
const failedMap = schema.create(
|
|
430
|
+
{ result: { status: "failed", error: "error" } },
|
|
431
|
+
account,
|
|
432
|
+
);
|
|
433
|
+
expect(successMap.result).toEqual({ status: "success", data: "data" });
|
|
434
|
+
expect(failedMap.result).toEqual({ status: "failed", error: "error" });
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it("should handle intersections", async () => {
|
|
438
|
+
const schema = co.map({
|
|
439
|
+
value: z.intersection(
|
|
440
|
+
z.union([z.number(), z.string()]),
|
|
441
|
+
z.union([z.number(), z.boolean()]),
|
|
442
|
+
),
|
|
443
|
+
});
|
|
444
|
+
const account = await createJazzTestAccount();
|
|
445
|
+
const map = schema.create({ value: 42 }, account);
|
|
446
|
+
expect(map.value).toBe(42);
|
|
447
|
+
});
|
|
445
448
|
|
|
446
449
|
it("should handle refined types", async () => {
|
|
447
450
|
const schema = co.map({
|