jazz-tools 0.18.26 → 0.18.28

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 (68) hide show
  1. package/.turbo/turbo-build.log +61 -61
  2. package/CHANGELOG.md +24 -0
  3. package/dist/{chunk-ZIAN4UY5.js → chunk-YOL3XDDW.js} +158 -120
  4. package/dist/chunk-YOL3XDDW.js.map +1 -0
  5. package/dist/index.js +97 -5
  6. package/dist/index.js.map +1 -1
  7. package/dist/media/{chunk-W3S526L3.js → chunk-K6GCHLQU.js} +1 -1
  8. package/dist/media/chunk-K6GCHLQU.js.map +1 -0
  9. package/dist/media/create-image/browser.d.ts +1 -1
  10. package/dist/media/create-image/react-native.d.ts +1 -1
  11. package/dist/media/create-image/react-native.d.ts.map +1 -1
  12. package/dist/media/create-image/server.d.ts +1 -1
  13. package/dist/media/create-image-factory.d.ts +5 -2
  14. package/dist/media/create-image-factory.d.ts.map +1 -1
  15. package/dist/media/index.browser.js +1 -1
  16. package/dist/media/index.d.ts +3 -4
  17. package/dist/media/index.d.ts.map +1 -1
  18. package/dist/media/index.js +1 -1
  19. package/dist/media/index.native.js +63 -28
  20. package/dist/media/index.native.js.map +1 -1
  21. package/dist/media/index.server.js +1 -1
  22. package/dist/react/index.js.map +1 -1
  23. package/dist/react-core/hooks.d.ts +4 -0
  24. package/dist/react-core/hooks.d.ts.map +1 -1
  25. package/dist/react-core/index.js +5 -0
  26. package/dist/react-core/index.js.map +1 -1
  27. package/dist/testing.js +1 -1
  28. package/dist/tools/coValues/coList.d.ts +11 -3
  29. package/dist/tools/coValues/coList.d.ts.map +1 -1
  30. package/dist/tools/coValues/coMap.d.ts +21 -5
  31. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  32. package/dist/tools/coValues/group.d.ts +2 -2
  33. package/dist/tools/coValues/group.d.ts.map +1 -1
  34. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  35. package/dist/tools/coValues/interfaces.d.ts +9 -0
  36. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  37. package/dist/tools/coValues/request.d.ts +70 -0
  38. package/dist/tools/coValues/request.d.ts.map +1 -1
  39. package/dist/tools/exports.d.ts +2 -2
  40. package/dist/tools/exports.d.ts.map +1 -1
  41. package/dist/tools/tests/authenticate-request.test.d.ts +2 -0
  42. package/dist/tools/tests/authenticate-request.test.d.ts.map +1 -0
  43. package/dist/tools/tests/coList.unique.test.d.ts +2 -0
  44. package/dist/tools/tests/coList.unique.test.d.ts.map +1 -0
  45. package/dist/tools/tests/coMap.unique.test.d.ts +2 -0
  46. package/dist/tools/tests/coMap.unique.test.d.ts.map +1 -0
  47. package/package.json +8 -4
  48. package/src/media/create-image/react-native.ts +75 -30
  49. package/src/media/create-image-factory.test.ts +18 -0
  50. package/src/media/create-image-factory.ts +6 -1
  51. package/src/media/index.ts +7 -4
  52. package/src/react-core/hooks.ts +8 -0
  53. package/src/react-core/tests/useAccount.test.ts +61 -1
  54. package/src/react-core/tests/usePassPhraseAuth.test.ts +74 -2
  55. package/src/tools/coValues/coList.ts +38 -35
  56. package/src/tools/coValues/coMap.ts +38 -38
  57. package/src/tools/coValues/group.ts +5 -1
  58. package/src/tools/coValues/inbox.ts +4 -3
  59. package/src/tools/coValues/interfaces.ts +88 -0
  60. package/src/tools/coValues/request.ts +188 -4
  61. package/src/tools/exports.ts +4 -0
  62. package/src/tools/tests/authenticate-request.test.ts +194 -0
  63. package/src/tools/tests/coList.test.ts +0 -190
  64. package/src/tools/tests/coList.unique.test.ts +244 -0
  65. package/src/tools/tests/coMap.test.ts +0 -433
  66. package/src/tools/tests/coMap.unique.test.ts +474 -0
  67. package/dist/chunk-ZIAN4UY5.js.map +0 -1
  68. package/dist/media/chunk-W3S526L3.js.map +0 -1
@@ -0,0 +1,474 @@
1
+ import { cojsonInternals } from "cojson";
2
+ import { assert, beforeEach, describe, expect, test } from "vitest";
3
+ import {
4
+ setupJazzTestSync,
5
+ createJazzTestAccount,
6
+ runWithoutActiveAccount,
7
+ } from "../testing";
8
+ import { Group, co, activeAccountContext } from "../internal";
9
+ import { z } from "../exports";
10
+
11
+ beforeEach(async () => {
12
+ cojsonInternals.CO_VALUE_LOADING_CONFIG.RETRY_DELAY = 1000;
13
+
14
+ await setupJazzTestSync();
15
+
16
+ await createJazzTestAccount({
17
+ isCurrentActiveAccount: true,
18
+ creationProps: { name: "Hermes Puggington" },
19
+ });
20
+ });
21
+
22
+ describe("Creating and finding unique CoMaps", async () => {
23
+ test("Creating and finding unique CoMaps", async () => {
24
+ const group = Group.create();
25
+
26
+ const Person = co.map({
27
+ name: z.string(),
28
+ _height: z.number(),
29
+ birthday: z.date(),
30
+ color: z.string(),
31
+ });
32
+
33
+ const alice = Person.create(
34
+ {
35
+ name: "Alice",
36
+ _height: 100,
37
+ birthday: new Date("1990-01-01"),
38
+ color: "red",
39
+ },
40
+ { owner: group, unique: { name: "Alice" } },
41
+ );
42
+
43
+ const foundAlice = await Person.loadUnique(
44
+ { name: "Alice" },
45
+ group.$jazz.id,
46
+ );
47
+ expect(foundAlice).toEqual(alice);
48
+ });
49
+
50
+ test("manual upserting pattern", async () => {
51
+ // Schema
52
+ const Event = co.map({
53
+ title: z.string(),
54
+ identifier: z.string(),
55
+ external_id: z.string(),
56
+ });
57
+
58
+ // Data
59
+ const sourceData = {
60
+ title: "Test Event Title",
61
+ identifier: "test-event-identifier",
62
+ _id: "test-event-external-id",
63
+ };
64
+ const workspace = Group.create();
65
+
66
+ // Pattern
67
+ let activeEvent = await Event.loadUnique(
68
+ { identifier: sourceData.identifier },
69
+ workspace.$jazz.id,
70
+ );
71
+ if (!activeEvent) {
72
+ activeEvent = Event.create(
73
+ {
74
+ title: sourceData.title,
75
+ identifier: sourceData.identifier,
76
+ external_id: sourceData._id,
77
+ },
78
+ workspace,
79
+ );
80
+ } else {
81
+ activeEvent.$jazz.applyDiff({
82
+ title: sourceData.title,
83
+ identifier: sourceData.identifier,
84
+ external_id: sourceData._id,
85
+ });
86
+ }
87
+ expect(activeEvent).toEqual({
88
+ title: sourceData.title,
89
+ identifier: sourceData.identifier,
90
+ external_id: sourceData._id,
91
+ });
92
+ });
93
+
94
+ test("upserting a non-existent value", async () => {
95
+ // Schema
96
+ const Event = co.map({
97
+ title: z.string(),
98
+ identifier: z.string(),
99
+ external_id: z.string(),
100
+ });
101
+
102
+ // Data
103
+ const sourceData = {
104
+ title: "Test Event Title",
105
+ identifier: "test-event-identifier",
106
+ _id: "test-event-external-id",
107
+ };
108
+ const workspace = Group.create();
109
+
110
+ // Upserting
111
+ const activeEvent = await Event.upsertUnique({
112
+ value: {
113
+ title: sourceData.title,
114
+ identifier: sourceData.identifier,
115
+ external_id: sourceData._id,
116
+ },
117
+ unique: sourceData.identifier,
118
+ owner: workspace,
119
+ });
120
+ expect(activeEvent).toEqual({
121
+ title: sourceData.title,
122
+ identifier: sourceData.identifier,
123
+ external_id: sourceData._id,
124
+ });
125
+ });
126
+
127
+ test("upserting without an active account", async () => {
128
+ const account = activeAccountContext.get();
129
+
130
+ // Schema
131
+ const Event = co.map({
132
+ title: z.string(),
133
+ identifier: z.string(),
134
+ external_id: z.string(),
135
+ });
136
+
137
+ // Data
138
+ const sourceData = {
139
+ title: "Test Event Title",
140
+ identifier: "test-event-identifier",
141
+ _id: "test-event-external-id",
142
+ };
143
+
144
+ const activeEvent = await runWithoutActiveAccount(() => {
145
+ return Event.upsertUnique({
146
+ value: {
147
+ title: sourceData.title,
148
+ identifier: sourceData.identifier,
149
+ external_id: sourceData._id,
150
+ },
151
+ unique: sourceData.identifier,
152
+ owner: account,
153
+ });
154
+ });
155
+
156
+ expect(activeEvent).toEqual({
157
+ title: sourceData.title,
158
+ identifier: sourceData.identifier,
159
+ external_id: sourceData._id,
160
+ });
161
+
162
+ assert(activeEvent);
163
+
164
+ expect(activeEvent.$jazz.owner).toEqual(account);
165
+ });
166
+
167
+ test("upserting an existing value", async () => {
168
+ // Schema
169
+ const Event = co.map({
170
+ title: z.string(),
171
+ identifier: z.string(),
172
+ external_id: z.string(),
173
+ });
174
+
175
+ // Data
176
+ const oldSourceData = {
177
+ title: "Old Event Title",
178
+ identifier: "test-event-identifier",
179
+ _id: "test-event-external-id",
180
+ };
181
+ const newSourceData = {
182
+ title: "New Event Title",
183
+ identifier: "test-event-identifier",
184
+ _id: "test-event-external-id",
185
+ };
186
+ expect(oldSourceData.identifier).toEqual(newSourceData.identifier);
187
+ const workspace = Group.create();
188
+ const oldActiveEvent = Event.create(
189
+ {
190
+ title: oldSourceData.title,
191
+ identifier: oldSourceData.identifier,
192
+ external_id: oldSourceData._id,
193
+ },
194
+ workspace,
195
+ );
196
+
197
+ // Upserting
198
+ const activeEvent = await Event.upsertUnique({
199
+ value: {
200
+ title: newSourceData.title,
201
+ identifier: newSourceData.identifier,
202
+ external_id: newSourceData._id,
203
+ },
204
+ unique: newSourceData.identifier,
205
+ owner: workspace,
206
+ });
207
+ expect(activeEvent).toEqual({
208
+ title: newSourceData.title,
209
+ identifier: newSourceData.identifier,
210
+ external_id: newSourceData._id,
211
+ });
212
+ expect(activeEvent).not.toEqual(oldActiveEvent);
213
+ });
214
+
215
+ test("upserting a non-existent value with resolve", async () => {
216
+ const Project = co.map({
217
+ name: z.string(),
218
+ });
219
+ const Organisation = co.map({
220
+ name: z.string(),
221
+ projects: co.list(Project),
222
+ });
223
+ const workspace = Group.create();
224
+
225
+ const myOrg = await Organisation.upsertUnique({
226
+ value: {
227
+ name: "My organisation",
228
+ projects: co.list(Project).create(
229
+ [
230
+ Project.create(
231
+ {
232
+ name: "My project",
233
+ },
234
+ workspace,
235
+ ),
236
+ ],
237
+ workspace,
238
+ ),
239
+ },
240
+ unique: { name: "My organisation" },
241
+ owner: workspace,
242
+ resolve: {
243
+ projects: {
244
+ $each: true,
245
+ },
246
+ },
247
+ });
248
+ assert(myOrg);
249
+ expect(myOrg).not.toBeNull();
250
+ expect(myOrg.name).toEqual("My organisation");
251
+ expect(myOrg.projects.length).toBe(1);
252
+ expect(myOrg.projects[0]).toMatchObject({
253
+ name: "My project",
254
+ });
255
+ });
256
+
257
+ test("upserting an existing value with resolve", async () => {
258
+ const Project = co.map({
259
+ name: z.string(),
260
+ });
261
+ const Organisation = co.map({
262
+ name: z.string(),
263
+ projects: co.list(Project),
264
+ });
265
+ const workspace = Group.create();
266
+ const initialProject = await Project.upsertUnique({
267
+ value: {
268
+ name: "My project",
269
+ },
270
+ unique: { unique: "First project" },
271
+ owner: workspace,
272
+ });
273
+ assert(initialProject);
274
+ expect(initialProject).not.toBeNull();
275
+ expect(initialProject.name).toEqual("My project");
276
+
277
+ const myOrg = await Organisation.upsertUnique({
278
+ value: {
279
+ name: "My organisation",
280
+ projects: co.list(Project).create([initialProject], workspace),
281
+ },
282
+ unique: { name: "My organisation" },
283
+ owner: workspace,
284
+ resolve: {
285
+ projects: {
286
+ $each: true,
287
+ },
288
+ },
289
+ });
290
+ assert(myOrg);
291
+ expect(myOrg).not.toBeNull();
292
+ expect(myOrg.name).toEqual("My organisation");
293
+ expect(myOrg.projects.length).toBe(1);
294
+ expect(myOrg.projects.at(0)?.name).toEqual("My project");
295
+
296
+ const updatedProject = await Project.upsertUnique({
297
+ value: {
298
+ name: "My updated project",
299
+ },
300
+ unique: { unique: "First project" },
301
+ owner: workspace,
302
+ });
303
+
304
+ assert(updatedProject);
305
+ expect(updatedProject).not.toBeNull();
306
+ expect(updatedProject).toEqual(initialProject);
307
+ expect(updatedProject.name).toEqual("My updated project");
308
+ expect(myOrg.projects.length).toBe(1);
309
+ expect(myOrg.projects.at(0)?.name).toEqual("My updated project");
310
+ });
311
+
312
+ test("upserting a partially loaded value on an new value with resolve", async () => {
313
+ const Project = co.map({
314
+ name: z.string(),
315
+ });
316
+ const Organisation = co.map({
317
+ name: z.string(),
318
+ projects: co.list(Project),
319
+ });
320
+ const publicAccess = Group.create();
321
+ publicAccess.addMember("everyone", "writer");
322
+
323
+ const initialProject = await Project.upsertUnique({
324
+ value: {
325
+ name: "My project",
326
+ },
327
+ unique: { unique: "First project" },
328
+ owner: publicAccess,
329
+ });
330
+ assert(initialProject);
331
+ expect(initialProject).not.toBeNull();
332
+ expect(initialProject.name).toEqual("My project");
333
+
334
+ const fullProjectList = co
335
+ .list(Project)
336
+ .create([initialProject], publicAccess);
337
+
338
+ const account = await createJazzTestAccount({
339
+ isCurrentActiveAccount: true,
340
+ });
341
+
342
+ const shallowProjectList = await co
343
+ .list(Project)
344
+ .load(fullProjectList.$jazz.id, {
345
+ loadAs: account,
346
+ });
347
+ assert(shallowProjectList);
348
+
349
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
350
+ loadAs: account,
351
+ });
352
+ assert(publicAccessAsNewAccount);
353
+
354
+ const updatedOrg = await Organisation.upsertUnique({
355
+ value: {
356
+ name: "My organisation",
357
+ projects: shallowProjectList,
358
+ },
359
+ unique: { name: "My organisation" },
360
+ owner: publicAccessAsNewAccount,
361
+ resolve: {
362
+ projects: {
363
+ $each: true,
364
+ },
365
+ },
366
+ });
367
+
368
+ assert(updatedOrg);
369
+
370
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
371
+ expect(updatedOrg.projects.length).toBe(1);
372
+ expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
373
+ });
374
+
375
+ test("upserting a partially loaded value on an existing value with resolve", async () => {
376
+ const Project = co.map({
377
+ name: z.string(),
378
+ });
379
+ const Organisation = co.map({
380
+ name: z.string(),
381
+ projects: co.list(Project),
382
+ });
383
+ const publicAccess = Group.create();
384
+ publicAccess.addMember("everyone", "writer");
385
+
386
+ const initialProject = await Project.upsertUnique({
387
+ value: {
388
+ name: "My project",
389
+ },
390
+ unique: { unique: "First project" },
391
+ owner: publicAccess,
392
+ });
393
+ assert(initialProject);
394
+
395
+ const myOrg = await Organisation.upsertUnique({
396
+ value: {
397
+ name: "My organisation",
398
+ projects: co.list(Project).create([], publicAccess),
399
+ },
400
+ unique: { name: "My organisation" },
401
+ owner: publicAccess,
402
+ resolve: {
403
+ projects: {
404
+ $each: true,
405
+ },
406
+ },
407
+ });
408
+ assert(myOrg);
409
+
410
+ const fullProjectList = co
411
+ .list(Project)
412
+ .create([initialProject], publicAccess);
413
+
414
+ const account = await createJazzTestAccount({
415
+ isCurrentActiveAccount: true,
416
+ });
417
+
418
+ const shallowProjectList = await co
419
+ .list(Project)
420
+ .load(fullProjectList.$jazz.id, {
421
+ loadAs: account,
422
+ });
423
+ assert(shallowProjectList);
424
+
425
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
426
+ loadAs: account,
427
+ });
428
+ assert(publicAccessAsNewAccount);
429
+
430
+ const updatedOrg = await Organisation.upsertUnique({
431
+ value: {
432
+ name: "My organisation",
433
+ projects: shallowProjectList,
434
+ },
435
+ unique: { name: "My organisation" },
436
+ owner: publicAccessAsNewAccount,
437
+ resolve: {
438
+ projects: {
439
+ $each: true,
440
+ },
441
+ },
442
+ });
443
+
444
+ assert(updatedOrg);
445
+
446
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
447
+ expect(updatedOrg.projects.length).toBe(1);
448
+ expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
449
+ expect(updatedOrg.$jazz.id).toEqual(myOrg.$jazz.id);
450
+ });
451
+
452
+ test("concurrently upserting the same value", async () => {
453
+ const Project = co.map({
454
+ name: z.string(),
455
+ });
456
+
457
+ const owner = Group.create();
458
+
459
+ const promises = Array.from({ length: 3 }, (_, i) =>
460
+ Project.upsertUnique({
461
+ owner,
462
+ unique: "concurrent",
463
+ value: { name: `Project ${i}` },
464
+ }),
465
+ );
466
+
467
+ await Promise.all(promises);
468
+
469
+ const result = await Project.loadUnique("concurrent", owner.$jazz.id);
470
+ assert(result);
471
+
472
+ expect(result.name).toBe(`Project 2`);
473
+ });
474
+ });