jazz-tools 0.16.4 → 0.16.6

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 (57) hide show
  1. package/.turbo/turbo-build.log +47 -47
  2. package/CHANGELOG.md +34 -0
  3. package/dist/{chunk-74LZG2M3.js → chunk-R2VNCMG6.js} +5 -5
  4. package/dist/chunk-R2VNCMG6.js.map +1 -0
  5. package/dist/index.js +1 -3
  6. package/dist/index.js.map +1 -1
  7. package/dist/inspector/{custom-element-TUXKXSZU.js → custom-element-I7L56H6B.js} +3 -5
  8. package/dist/inspector/{custom-element-TUXKXSZU.js.map → custom-element-I7L56H6B.js.map} +1 -1
  9. package/dist/inspector/index.js +2 -4
  10. package/dist/inspector/index.js.map +1 -1
  11. package/dist/inspector/register-custom-element.js +1 -1
  12. package/dist/inspector/viewer/co-plain-text-view.d.ts +1 -1
  13. package/dist/inspector/viewer/co-plain-text-view.d.ts.map +1 -1
  14. package/dist/inspector/viewer/role-display.d.ts.map +1 -1
  15. package/dist/react/ssr.d.ts.map +1 -1
  16. package/dist/react/ssr.js.map +1 -1
  17. package/dist/react/tests/testUtils.d.ts.map +1 -1
  18. package/dist/react-core/auth/PassphraseAuth.d.ts +1 -1
  19. package/dist/react-core/auth/PassphraseAuth.d.ts.map +1 -1
  20. package/dist/react-core/index.js +1 -3
  21. package/dist/react-core/index.js.map +1 -1
  22. package/dist/react-core/tests/testUtils.d.ts.map +1 -1
  23. package/dist/testing.js +1 -1
  24. package/dist/testing.js.map +1 -1
  25. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  26. package/dist/tools/coValues/deepLoading.d.ts +10 -10
  27. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  28. package/dist/tools/coValues/group.d.ts +2 -2
  29. package/dist/tools/coValues/group.d.ts.map +1 -1
  30. package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
  31. package/dist/tools/index.d.ts +1 -1
  32. package/dist/tools/index.d.ts.map +1 -1
  33. package/dist/tools/testing.d.ts.map +1 -1
  34. package/package.json +4 -4
  35. package/src/inspector/viewer/co-plain-text-view.tsx +1 -5
  36. package/src/inspector/viewer/co-stream-view.tsx +1 -1
  37. package/src/inspector/viewer/role-display.tsx +4 -1
  38. package/src/react/ssr.ts +1 -3
  39. package/src/react/tests/testUtils.tsx +2 -10
  40. package/src/react-core/auth/PassphraseAuth.tsx +1 -5
  41. package/src/react-core/tests/testUtils.tsx +2 -10
  42. package/src/tools/coValues/coFeed.ts +3 -2
  43. package/src/tools/coValues/deepLoading.ts +46 -32
  44. package/src/tools/coValues/group.ts +3 -3
  45. package/src/tools/implementation/zodSchema/unionUtils.ts +7 -2
  46. package/src/tools/index.ts +0 -1
  47. package/src/tools/testing.ts +3 -1
  48. package/src/tools/tests/coDiscriminatedUnion.test.ts +50 -0
  49. package/src/tools/tests/coList.test.ts +1 -1
  50. package/src/tools/tests/coMap.record.test-d.ts +105 -0
  51. package/src/tools/tests/coMap.record.test.ts +45 -0
  52. package/src/tools/tests/coMap.test-d.ts +50 -0
  53. package/vitest.config.ts +1 -21
  54. package/dist/browser-media-images/index.test.browser.d.ts +0 -2
  55. package/dist/browser-media-images/index.test.browser.d.ts.map +0 -1
  56. package/dist/chunk-74LZG2M3.js.map +0 -1
  57. package/src/browser-media-images/index.test.browser.ts +0 -73
@@ -97,6 +97,27 @@ type onErrorNullEnabled<Depth> = Depth extends { $onError: null }
97
97
  ? null
98
98
  : never;
99
99
 
100
+ type CoMapLikeLoaded<
101
+ V extends object,
102
+ Depth,
103
+ DepthLimit extends number,
104
+ CurrentDepth extends number[],
105
+ > = {
106
+ -readonly [Key in keyof Depth]-?: Key extends CoKeys<V>
107
+ ? NonNullable<V[Key]> extends CoValue
108
+ ?
109
+ | DeeplyLoaded<
110
+ NonNullable<V[Key]>,
111
+ Depth[Key],
112
+ DepthLimit,
113
+ [0, ...CurrentDepth]
114
+ >
115
+ | (undefined extends V[Key] ? undefined : never)
116
+ | onErrorNullEnabled<Depth[Key]>
117
+ : never
118
+ : never;
119
+ } & V;
120
+
100
121
  export type DeeplyLoaded<
101
122
  V,
102
123
  Depth,
@@ -126,38 +147,31 @@ export type DeeplyLoaded<
126
147
  : V
127
148
  : // Basically V extends CoMap | Group | Account - but if we used that we'd introduce circularity into the definition of CoMap itself
128
149
  [V] extends [{ _type: "CoMap" | "Group" | "Account" }]
129
- ? ItemsSym extends keyof V
130
- ? Depth extends { $each: infer ItemDepth }
131
- ? // Deeply loaded Record-like CoMap
132
- {
133
- [key: string]:
134
- | DeeplyLoaded<
135
- NonNullable<V[ItemsSym]>,
136
- ItemDepth,
137
- DepthLimit,
138
- [0, ...CurrentDepth]
139
- >
140
- | onErrorNullEnabled<Depth["$each"]>;
141
- } & V // same reason as in CoList
142
- : never
143
- : keyof Depth extends never // Depth = {}
144
- ? V
145
- : // Deeply loaded CoMap
146
- {
147
- -readonly [Key in keyof Depth]-?: Key extends CoKeys<V>
148
- ? NonNullable<V[Key]> extends CoValue
149
- ?
150
- | DeeplyLoaded<
151
- NonNullable<V[Key]>,
152
- Depth[Key],
153
- DepthLimit,
154
- [0, ...CurrentDepth]
155
- >
156
- | (undefined extends V[Key] ? undefined : never)
157
- | onErrorNullEnabled<Depth[Key]>
158
- : never
159
- : never;
160
- } & V // same reason as in CoList
150
+ ? // If Depth = {} return V in any case
151
+ keyof Depth extends never
152
+ ? V
153
+ : // 1. Record-like CoMap
154
+ ItemsSym extends keyof V
155
+ ? // 1.1. Deeply loaded Record-like CoMap with { $each: true | {$onError: null} }
156
+ Depth extends { $each: infer ItemDepth }
157
+ ? {
158
+ [key: string]:
159
+ | DeeplyLoaded<
160
+ NonNullable<V[ItemsSym]>,
161
+ ItemDepth,
162
+ DepthLimit,
163
+ [0, ...CurrentDepth]
164
+ >
165
+ | onErrorNullEnabled<Depth["$each"]>;
166
+ } & V // same reason as in CoList
167
+ : // 1.2. Deeply loaded Record-like CoMap with { [key: string]: true }
168
+ string extends keyof Depth
169
+ ? // if at least one key is `string`, then we treat the resolve as it was empty
170
+ DeeplyLoaded<V, {}, DepthLimit, [0, ...CurrentDepth]> & V
171
+ : // 1.3 Deeply loaded Record-like CoMap with single keys
172
+ CoMapLikeLoaded<V, Depth, DepthLimit, CurrentDepth>
173
+ : // 2. Deeply loaded CoMap
174
+ CoMapLikeLoaded<V, Depth, DepthLimit, CurrentDepth>
161
175
  : [V] extends [
162
176
  {
163
177
  _type: "CoStream";
@@ -167,15 +167,15 @@ export class Group extends CoValueBase implements CoValue {
167
167
  }
168
168
  }
169
169
 
170
- removeMember(member: Everyone | Account): Promise<void>;
170
+ removeMember(member: Everyone | Account): void;
171
171
  /** @category Identity & Permissions
172
172
  * Revokes membership from members a parent group.
173
173
  * @param member The group that will lose access to this group.
174
174
  */
175
- removeMember(member: Group): Promise<void>;
175
+ removeMember(member: Group): void;
176
176
  removeMember(member: Group | Everyone | Account) {
177
177
  if (member !== "everyone" && member._type === "Group") {
178
- return this._raw.revokeExtend(member._raw);
178
+ this._raw.revokeExtend(member._raw);
179
179
  } else {
180
180
  return this._raw.removeMember(
181
181
  member === "everyone" ? member : member._raw,
@@ -81,8 +81,7 @@ export function schemaUnionDiscriminatorFor(
81
81
  continue;
82
82
  }
83
83
  }
84
-
85
- if (discriminatorDef._zod.def.type !== "literal") {
84
+ if (discriminatorDef._zod?.def.type !== "literal") {
86
85
  break;
87
86
  }
88
87
 
@@ -141,3 +140,9 @@ export function isUnionOfPrimitivesDeeply(schema: AnyZodOrCoValueSchema) {
141
140
  return !isAnyCoValueSchema(schema);
142
141
  }
143
142
  }
143
+
144
+ function isCoDiscriminatedUnion(
145
+ def: any,
146
+ ): def is CoreCoDiscriminatedUnionSchema<any> {
147
+ return def.builtin === "CoDiscriminatedUnion";
148
+ }
@@ -1,7 +1,6 @@
1
1
  export * from "./exports.js";
2
2
 
3
3
  export {
4
- MAX_RECOMMENDED_TX_SIZE,
5
4
  cojsonInternals,
6
5
  logger,
7
6
  LogLevel,
@@ -305,7 +305,9 @@ export async function linkAccounts(
305
305
 
306
306
  export async function setupJazzTestSync({
307
307
  asyncPeers = false,
308
- }: { asyncPeers?: boolean } = {}) {
308
+ }: {
309
+ asyncPeers?: boolean;
310
+ } = {}) {
309
311
  if (syncServer.current) {
310
312
  syncServer.current.gracefulShutdown();
311
313
  }
@@ -308,4 +308,54 @@ describe("co.discriminatedUnion", () => {
308
308
 
309
309
  expect(updates[0]?.name).toEqual("Rex");
310
310
  });
311
+
312
+ test("should work when one of the options has a dicriminated union field", async () => {
313
+ const Collie = co.map({
314
+ type: z.literal("collie"),
315
+ });
316
+ const BorderCollie = co.map({
317
+ type: z.literal("border-collie"),
318
+ });
319
+ const Breed = co.discriminatedUnion("type", [Collie, BorderCollie]);
320
+
321
+ const Dog = co.map({
322
+ type: z.literal("dog"),
323
+ breed: Breed,
324
+ });
325
+
326
+ const Animal = co.discriminatedUnion("type", [Dog]);
327
+
328
+ const animal = Dog.create({
329
+ type: "dog",
330
+ breed: {
331
+ type: "collie",
332
+ },
333
+ });
334
+
335
+ const loadedAnimal = await Animal.load(animal.id);
336
+
337
+ expect(loadedAnimal?.breed?.type).toEqual("collie");
338
+ });
339
+
340
+ test("should work with a nested co.discriminatedUnion", async () => {
341
+ const Collie = co.map({
342
+ type: z.literal("collie"),
343
+ });
344
+ const BorderCollie = co.map({
345
+ type: z.literal("border-collie"),
346
+ });
347
+ const Breed = co.discriminatedUnion("type", [Collie, BorderCollie]);
348
+
349
+ const Dog = co.discriminatedUnion("type", [Breed]);
350
+
351
+ const Animal = co.discriminatedUnion("type", [Dog]);
352
+
353
+ const animal = Collie.create({
354
+ type: "collie",
355
+ });
356
+
357
+ const loadedAnimal = await Animal.load(animal.id);
358
+
359
+ expect(loadedAnimal?.type).toEqual("collie");
360
+ });
311
361
  });
@@ -1,5 +1,5 @@
1
1
  import { WasmCrypto } from "cojson/crypto/WasmCrypto";
2
- import { beforeEach, describe, expect, test, vi } from "vitest";
2
+ import { assert, beforeEach, describe, expect, test, vi } from "vitest";
3
3
  import { Account, Group, subscribeToCoValue, z } from "../index.js";
4
4
  import {
5
5
  Loaded,
@@ -173,6 +173,111 @@ describe("CoMap.Record", () => {
173
173
  matches(loadedPerson);
174
174
  });
175
175
 
176
+ test("loading a record with property resolve", async () => {
177
+ const Dog = co.map({
178
+ name: z.string(),
179
+ breed: z.string(),
180
+ });
181
+
182
+ const Person = co.record(z.string(), Dog);
183
+
184
+ const person = Person.create({
185
+ pet1: Dog.create({ name: "Rex", breed: "Labrador" }),
186
+ pet2: Dog.create({ name: "Fido", breed: "Poodle" }),
187
+ });
188
+
189
+ const loadedPerson = await Person.load(person.id, {
190
+ resolve: {
191
+ pet1: true,
192
+ },
193
+ });
194
+
195
+ type Expect = NonNullable<typeof loadedPerson> extends never
196
+ ? "error: is never"
197
+ : "ok";
198
+
199
+ expectTypeOf("ok" as const).toEqualTypeOf<Expect>();
200
+
201
+ expectTypeOf(loadedPerson?.pet1).toEqualTypeOf<
202
+ Loaded<typeof Dog> | undefined
203
+ >();
204
+ expectTypeOf(loadedPerson?.pet3).toEqualTypeOf<
205
+ Loaded<typeof Dog> | undefined | null
206
+ >();
207
+ });
208
+
209
+ test("loading a record with generic string resolve", async () => {
210
+ const Dog = co.map({
211
+ name: z.string(),
212
+ breed: z.string(),
213
+ });
214
+
215
+ const Person = co.record(z.string(), Dog);
216
+
217
+ const person = Person.create({
218
+ pet1: Dog.create({ name: "Rex", breed: "Labrador" }),
219
+ pet2: Dog.create({ name: "Fido", breed: "Poodle" }),
220
+ });
221
+
222
+ const userId: string = "pet1";
223
+ const userId2: string = "pet3";
224
+
225
+ const loadedPerson = await Person.load(person.id, {
226
+ resolve: {
227
+ [userId]: true,
228
+ pet2: true,
229
+ [userId2]: {
230
+ $onError: null,
231
+ },
232
+ },
233
+ });
234
+
235
+ type Expect = NonNullable<typeof loadedPerson> extends never
236
+ ? "error: is never"
237
+ : "ok";
238
+
239
+ expectTypeOf("ok" as const).toEqualTypeOf<Expect>();
240
+
241
+ expectTypeOf(loadedPerson?.pet1).toEqualTypeOf<
242
+ Loaded<typeof Dog> | undefined | null
243
+ >();
244
+ expectTypeOf(loadedPerson?.pet2).toEqualTypeOf<
245
+ Loaded<typeof Dog> | undefined | null
246
+ >();
247
+ expectTypeOf(loadedPerson?.pet3).toEqualTypeOf<
248
+ Loaded<typeof Dog> | undefined | null
249
+ >();
250
+ });
251
+
252
+ test("loading a record with empty resolve", async () => {
253
+ const Dog = co.map({
254
+ name: z.string(),
255
+ breed: z.string(),
256
+ });
257
+
258
+ const Person = co.record(z.string(), Dog);
259
+
260
+ const person = Person.create({
261
+ pet1: Dog.create({ name: "Rex", breed: "Labrador" }),
262
+ pet2: Dog.create({ name: "Fido", breed: "Poodle" }),
263
+ });
264
+
265
+ const loadedPerson = await Person.load(person.id);
266
+
267
+ type Expect = NonNullable<typeof loadedPerson> extends never
268
+ ? "error: is never"
269
+ : "ok";
270
+
271
+ expectTypeOf("ok" as const).toEqualTypeOf<Expect>();
272
+
273
+ expectTypeOf(loadedPerson?.pet1).toEqualTypeOf<
274
+ Loaded<typeof Dog> | undefined | null
275
+ >();
276
+ expectTypeOf(loadedPerson?.pet3).toEqualTypeOf<
277
+ Loaded<typeof Dog> | undefined | null
278
+ >();
279
+ });
280
+
176
281
  test("loading a record with $onError", async () => {
177
282
  const Dog = co.map({
178
283
  name: z.string(),
@@ -213,6 +213,51 @@ describe("CoMap.Record", async () => {
213
213
  expect(loadedPerson.pet2?.name).toEqual("Fido");
214
214
  });
215
215
 
216
+ test("loading a locally available record with single resolve", async () => {
217
+ const Dog = co.map({
218
+ name: z.string(),
219
+ breed: z.string(),
220
+ });
221
+
222
+ const Person = co.record(z.string(), Dog);
223
+
224
+ const person = Person.create({
225
+ pet1: Dog.create({ name: "Rex", breed: "Labrador" }),
226
+ pet2: Dog.create({ name: "Fido", breed: "Poodle" }),
227
+ });
228
+
229
+ const loadedPerson = await Person.load(person.id, {
230
+ resolve: {
231
+ pet1: true,
232
+ },
233
+ });
234
+
235
+ assert(loadedPerson);
236
+ expect(loadedPerson.pet1?.name).toEqual("Rex");
237
+ });
238
+
239
+ test("loading a locally available record with unavailable single resolve", async () => {
240
+ const Dog = co.map({
241
+ name: z.string(),
242
+ breed: z.string(),
243
+ });
244
+
245
+ const Person = co.record(z.string(), Dog);
246
+
247
+ const person = Person.create({
248
+ pet1: Dog.create({ name: "Rex", breed: "Labrador" }),
249
+ pet2: Dog.create({ name: "Fido", breed: "Poodle" }),
250
+ });
251
+
252
+ const loadedPerson = await Person.load(person.id, {
253
+ resolve: {
254
+ pet3: true,
255
+ },
256
+ });
257
+
258
+ expect(loadedPerson).toEqual(null);
259
+ });
260
+
216
261
  test("loading a locally available record using autoload for the refs", async () => {
217
262
  const Dog = co.map({
218
263
  name: z.string(),
@@ -542,6 +542,56 @@ describe("CoMap resolution", async () => {
542
542
  > | null>();
543
543
  });
544
544
 
545
+ test("partial loading a map with string resolve", async () => {
546
+ const Dog = co.map({
547
+ name: z.string(),
548
+ breed: z.string(),
549
+ });
550
+
551
+ const Person = co.map({
552
+ name: z.string(),
553
+ age: z.number(),
554
+ dog1: Dog,
555
+ dog2: Dog,
556
+ });
557
+
558
+ const person = Person.create({
559
+ name: "John",
560
+ age: 20,
561
+ dog1: Dog.create({ name: "Rex", breed: "Labrador" }),
562
+ dog2: Dog.create({ name: "Fido", breed: "Poodle" }),
563
+ });
564
+
565
+ const userId: string = "dog1";
566
+
567
+ const loadedPerson = await Person.load(person.id, {
568
+ resolve: {
569
+ [userId]: true,
570
+ },
571
+ });
572
+
573
+ type ExpectedType = {
574
+ name: string;
575
+ age: number;
576
+ dog1: Loaded<typeof Dog> | null;
577
+ dog2: Loaded<typeof Dog> | null;
578
+ } | null;
579
+
580
+ function matches(value: ExpectedType) {
581
+ return value;
582
+ }
583
+
584
+ matches(loadedPerson);
585
+
586
+ assert(loadedPerson);
587
+ expectTypeOf<typeof loadedPerson.dog1>().toEqualTypeOf<Loaded<
588
+ typeof Dog
589
+ > | null>();
590
+ expectTypeOf<typeof loadedPerson.dog2>().toEqualTypeOf<Loaded<
591
+ typeof Dog
592
+ > | null>();
593
+ });
594
+
545
595
  test("loading a map with deep resolve and $onError", async () => {
546
596
  const Dog = co.map({
547
597
  name: z.string(),
package/vitest.config.ts CHANGED
@@ -3,30 +3,10 @@ import { defineProject } from "vitest/config";
3
3
  export default defineProject({
4
4
  test: {
5
5
  name: "jazz-tools",
6
+ include: ["src/**/*.test.{js,ts,svelte}"],
6
7
  typecheck: {
7
8
  enabled: true,
8
9
  checker: "tsc",
9
10
  },
10
- projects: [
11
- {
12
- test: {
13
- include: ["src/**/*.test.browser.ts"],
14
- browser: {
15
- enabled: true,
16
- provider: "playwright",
17
- headless: true,
18
- screenshotFailures: false,
19
- instances: [{ browser: "chromium" }],
20
- },
21
- name: "browser",
22
- },
23
- },
24
- {
25
- test: {
26
- include: ["src/**/*.test.{js,ts,svelte}"],
27
- name: "unit",
28
- },
29
- },
30
- ],
31
11
  },
32
12
  });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.browser.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.browser.d.ts","sourceRoot":"","sources":["../../src/browser-media-images/index.test.browser.ts"],"names":[],"mappings":""}