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.
- package/.turbo/turbo-build.log +47 -47
- package/CHANGELOG.md +34 -0
- package/dist/{chunk-74LZG2M3.js → chunk-R2VNCMG6.js} +5 -5
- package/dist/chunk-R2VNCMG6.js.map +1 -0
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/inspector/{custom-element-TUXKXSZU.js → custom-element-I7L56H6B.js} +3 -5
- package/dist/inspector/{custom-element-TUXKXSZU.js.map → custom-element-I7L56H6B.js.map} +1 -1
- package/dist/inspector/index.js +2 -4
- package/dist/inspector/index.js.map +1 -1
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/inspector/viewer/co-plain-text-view.d.ts +1 -1
- package/dist/inspector/viewer/co-plain-text-view.d.ts.map +1 -1
- package/dist/inspector/viewer/role-display.d.ts.map +1 -1
- package/dist/react/ssr.d.ts.map +1 -1
- package/dist/react/ssr.js.map +1 -1
- package/dist/react/tests/testUtils.d.ts.map +1 -1
- package/dist/react-core/auth/PassphraseAuth.d.ts +1 -1
- package/dist/react-core/auth/PassphraseAuth.d.ts.map +1 -1
- package/dist/react-core/index.js +1 -3
- package/dist/react-core/index.js.map +1 -1
- package/dist/react-core/tests/testUtils.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/tools/coValues/coFeed.d.ts.map +1 -1
- package/dist/tools/coValues/deepLoading.d.ts +10 -10
- package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
- package/dist/tools/coValues/group.d.ts +2 -2
- package/dist/tools/coValues/group.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/testing.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/inspector/viewer/co-plain-text-view.tsx +1 -5
- package/src/inspector/viewer/co-stream-view.tsx +1 -1
- package/src/inspector/viewer/role-display.tsx +4 -1
- package/src/react/ssr.ts +1 -3
- package/src/react/tests/testUtils.tsx +2 -10
- package/src/react-core/auth/PassphraseAuth.tsx +1 -5
- package/src/react-core/tests/testUtils.tsx +2 -10
- package/src/tools/coValues/coFeed.ts +3 -2
- package/src/tools/coValues/deepLoading.ts +46 -32
- package/src/tools/coValues/group.ts +3 -3
- package/src/tools/implementation/zodSchema/unionUtils.ts +7 -2
- package/src/tools/index.ts +0 -1
- package/src/tools/testing.ts +3 -1
- package/src/tools/tests/coDiscriminatedUnion.test.ts +50 -0
- package/src/tools/tests/coList.test.ts +1 -1
- package/src/tools/tests/coMap.record.test-d.ts +105 -0
- package/src/tools/tests/coMap.record.test.ts +45 -0
- package/src/tools/tests/coMap.test-d.ts +50 -0
- package/vitest.config.ts +1 -21
- package/dist/browser-media-images/index.test.browser.d.ts +0 -2
- package/dist/browser-media-images/index.test.browser.d.ts.map +0 -1
- package/dist/chunk-74LZG2M3.js.map +0 -1
- 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
|
-
?
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
{
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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):
|
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):
|
175
|
+
removeMember(member: Group): void;
|
176
176
|
removeMember(member: Group | Everyone | Account) {
|
177
177
|
if (member !== "everyone" && member._type === "Group") {
|
178
|
-
|
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
|
+
}
|
package/src/tools/index.ts
CHANGED
package/src/tools/testing.ts
CHANGED
@@ -305,7 +305,9 @@ export async function linkAccounts(
|
|
305
305
|
|
306
306
|
export async function setupJazzTestSync({
|
307
307
|
asyncPeers = false,
|
308
|
-
}: {
|
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 +0,0 @@
|
|
1
|
-
{"version":3,"file":"index.test.browser.d.ts","sourceRoot":"","sources":["../../src/browser-media-images/index.test.browser.ts"],"names":[],"mappings":""}
|