jazz-tools 0.13.30 → 0.13.33
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 +23 -22
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +144 -0
- package/CHANGELOG.md +16 -0
- package/dist/auth/DemoAuth.d.ts.map +1 -1
- package/dist/auth/PassphraseAuth.d.ts +1 -3
- package/dist/auth/PassphraseAuth.d.ts.map +1 -1
- package/dist/{chunk-LMV6J7GN.js → chunk-WLOZKDOH.js} +3532 -3269
- package/dist/chunk-WLOZKDOH.js.map +1 -0
- package/dist/coValues/CoValueBase.d.ts +22 -0
- package/dist/coValues/CoValueBase.d.ts.map +1 -0
- package/dist/coValues/account.d.ts +12 -12
- package/dist/coValues/account.d.ts.map +1 -1
- package/dist/coValues/coFeed.d.ts +24 -25
- package/dist/coValues/coFeed.d.ts.map +1 -1
- package/dist/coValues/coList.d.ts +10 -13
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coMap.d.ts +32 -35
- package/dist/coValues/coMap.d.ts.map +1 -1
- package/dist/coValues/coPlainText.d.ts.map +1 -1
- package/dist/coValues/deepLoading.d.ts +28 -22
- package/dist/coValues/deepLoading.d.ts.map +1 -1
- package/dist/coValues/extensions/imageDef.d.ts +12 -11
- package/dist/coValues/extensions/imageDef.d.ts.map +1 -1
- package/dist/coValues/group.d.ts +5 -9
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/inbox.d.ts +2 -3
- package/dist/coValues/inbox.d.ts.map +1 -1
- package/dist/coValues/interfaces.d.ts +8 -34
- package/dist/coValues/interfaces.d.ts.map +1 -1
- package/dist/coValues/profile.d.ts +4 -14
- package/dist/coValues/profile.d.ts.map +1 -1
- package/dist/coValues/registeredSchemas.d.ts +1 -3
- package/dist/coValues/registeredSchemas.d.ts.map +1 -1
- package/dist/coValues/schemaUnion.d.ts +6 -6
- package/dist/exports.d.ts +12 -16
- package/dist/exports.d.ts.map +1 -1
- package/dist/implementation/ContextManager.d.ts +1 -1
- package/dist/implementation/ContextManager.d.ts.map +1 -1
- package/dist/implementation/activeAccountContext.d.ts +1 -1
- package/dist/implementation/activeAccountContext.d.ts.map +1 -1
- package/dist/implementation/createContext.d.ts +10 -10
- package/dist/implementation/createContext.d.ts.map +1 -1
- package/dist/implementation/invites.d.ts +6 -6
- package/dist/implementation/invites.d.ts.map +1 -1
- package/dist/implementation/refs.d.ts +2 -2
- package/dist/implementation/refs.d.ts.map +1 -1
- package/dist/implementation/schema.d.ts +21 -28
- package/dist/implementation/schema.d.ts.map +1 -1
- package/dist/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.d.ts +9 -0
- package/dist/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.d.ts.map +1 -0
- package/dist/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.d.ts +28 -0
- package/dist/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +65 -0
- package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +28 -0
- package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +24 -0
- package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +44 -0
- package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +35 -0
- package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +9 -0
- package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +20 -0
- package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +18 -0
- package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +24 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +21 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts +29 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts.map +1 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts +29 -0
- package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts.map +1 -0
- package/dist/implementation/zodSchema/unionUtils.d.ts +6 -0
- package/dist/implementation/zodSchema/unionUtils.d.ts.map +1 -0
- package/dist/implementation/zodSchema/zodCo.d.ts +35 -0
- package/dist/implementation/zodSchema/zodCo.d.ts.map +1 -0
- package/dist/implementation/zodSchema/zodSchema.d.ts +38 -0
- package/dist/implementation/zodSchema/zodSchema.d.ts.map +1 -0
- package/dist/index.js +295 -10
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +34 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/subscribe/SubscriptionScope.d.ts +2 -2
- package/dist/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/subscribe/utils.d.ts +2 -2
- package/dist/subscribe/utils.d.ts.map +1 -1
- package/dist/testing.d.ts +10 -8
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/tests/utils.d.ts +6 -2
- package/dist/tests/utils.d.ts.map +1 -1
- package/dist/types.d.ts +1 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/coValues/deepLoading.ts +49 -31
- package/src/subscribe/SubscriptionScope.ts +27 -2
- package/src/tests/deepLoading.test-d.ts +393 -0
- package/src/tests/deepLoading.test.ts +249 -0
- package/dist/chunk-LMV6J7GN.js.map +0 -1
@@ -0,0 +1,393 @@
|
|
1
|
+
import { cojsonInternals } from "cojson";
|
2
|
+
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
3
|
+
import { assert, describe, expect, expectTypeOf, test, vi } from "vitest";
|
4
|
+
import {
|
5
|
+
Account,
|
6
|
+
CoFeed,
|
7
|
+
CoList,
|
8
|
+
CoMap,
|
9
|
+
Group,
|
10
|
+
ID,
|
11
|
+
Profile,
|
12
|
+
SessionID,
|
13
|
+
co,
|
14
|
+
createJazzContextFromExistingCredentials,
|
15
|
+
isControlledAccount,
|
16
|
+
} from "../index.js";
|
17
|
+
import { randomSessionProvider } from "../internal.js";
|
18
|
+
import { createJazzTestAccount } from "../testing.js";
|
19
|
+
|
20
|
+
const Crypto = await WasmCrypto.create();
|
21
|
+
const { connectedPeers } = cojsonInternals;
|
22
|
+
|
23
|
+
class TestMap extends CoMap {
|
24
|
+
list = co.ref(TestList);
|
25
|
+
optionalRef = co.ref(InnermostMap, { optional: true });
|
26
|
+
}
|
27
|
+
|
28
|
+
class TestList extends CoList.Of(co.ref(() => InnerMap)) {}
|
29
|
+
|
30
|
+
class InnerMap extends CoMap {
|
31
|
+
stream = co.ref(TestStream);
|
32
|
+
}
|
33
|
+
|
34
|
+
class TestStream extends CoFeed.Of(co.ref(() => InnermostMap)) {}
|
35
|
+
|
36
|
+
class InnermostMap extends CoMap {
|
37
|
+
value = co.string;
|
38
|
+
}
|
39
|
+
|
40
|
+
const me = await createJazzTestAccount({});
|
41
|
+
const map = TestMap.create({
|
42
|
+
list: TestList.create([], { owner: me }),
|
43
|
+
});
|
44
|
+
|
45
|
+
describe("Deep loading with depth arg", async () => {
|
46
|
+
test("load without resolve", async () => {
|
47
|
+
const map1 = await TestMap.load(map.id);
|
48
|
+
|
49
|
+
function validateType(map: TestMap | null) {
|
50
|
+
map;
|
51
|
+
}
|
52
|
+
|
53
|
+
validateType(map1);
|
54
|
+
});
|
55
|
+
|
56
|
+
test("load with resolve { list: true }", async () => {
|
57
|
+
const map2 = await TestMap.load(map.id, {
|
58
|
+
resolve: { list: true },
|
59
|
+
});
|
60
|
+
expectTypeOf(map2).toEqualTypeOf<
|
61
|
+
| (TestMap & {
|
62
|
+
list: TestList;
|
63
|
+
})
|
64
|
+
| null
|
65
|
+
>();
|
66
|
+
});
|
67
|
+
|
68
|
+
test("load with resolve { list: { $each: true } }", async () => {
|
69
|
+
const map3 = await TestMap.load(map.id, {
|
70
|
+
resolve: { list: { $each: true } },
|
71
|
+
});
|
72
|
+
expectTypeOf(map3).toEqualTypeOf<
|
73
|
+
| (TestMap & {
|
74
|
+
list: TestList & InnerMap[];
|
75
|
+
})
|
76
|
+
| null
|
77
|
+
>();
|
78
|
+
});
|
79
|
+
|
80
|
+
test("load with resolve { optionalRef: true }", async () => {
|
81
|
+
const map3a = await TestMap.load(map.id, {
|
82
|
+
resolve: { optionalRef: true } as const,
|
83
|
+
});
|
84
|
+
expectTypeOf(map3a).toEqualTypeOf<
|
85
|
+
| (TestMap & {
|
86
|
+
optionalRef: InnermostMap | undefined;
|
87
|
+
})
|
88
|
+
| null
|
89
|
+
>();
|
90
|
+
});
|
91
|
+
|
92
|
+
test("load with resolve { list: { $each: { stream: true } } }", async () => {
|
93
|
+
const map4 = await TestMap.load(map.id, {
|
94
|
+
resolve: { list: { $each: { stream: true } } },
|
95
|
+
});
|
96
|
+
expectTypeOf(map4).toEqualTypeOf<
|
97
|
+
| (TestMap & {
|
98
|
+
list: TestList & (InnerMap & { stream: TestStream })[];
|
99
|
+
})
|
100
|
+
| null
|
101
|
+
>();
|
102
|
+
});
|
103
|
+
|
104
|
+
test("load with resolve { list: { $each: { stream: { $each: true } } } }", async () => {
|
105
|
+
const map5 = await TestMap.load(map.id, {
|
106
|
+
resolve: { list: { $each: { stream: { $each: true } } } },
|
107
|
+
});
|
108
|
+
type ExpectedMap5 =
|
109
|
+
| (TestMap & {
|
110
|
+
list: TestList &
|
111
|
+
(InnerMap & {
|
112
|
+
stream: TestStream & {
|
113
|
+
byMe?: { value: InnermostMap };
|
114
|
+
inCurrentSession?: { value: InnermostMap };
|
115
|
+
perSession: {
|
116
|
+
[sessionID: SessionID]: {
|
117
|
+
value: InnermostMap;
|
118
|
+
};
|
119
|
+
};
|
120
|
+
} & {
|
121
|
+
[key: ID<Account>]: { value: InnermostMap };
|
122
|
+
};
|
123
|
+
})[];
|
124
|
+
})
|
125
|
+
| null;
|
126
|
+
expectTypeOf(map5).toEqualTypeOf<ExpectedMap5>();
|
127
|
+
});
|
128
|
+
|
129
|
+
test("should handle $onError on CoList items", async () => {
|
130
|
+
class List extends CoList.Of(co.ref(() => InnerMap)) {}
|
131
|
+
|
132
|
+
const result = await List.load("x" as ID<List>, {
|
133
|
+
resolve: { $each: { $onError: null } },
|
134
|
+
});
|
135
|
+
function validateType(map: ((InnerMap | null)[] & List) | null) {
|
136
|
+
map;
|
137
|
+
}
|
138
|
+
|
139
|
+
validateType(result);
|
140
|
+
expectTypeOf(result).toEqualTypeOf<((InnerMap | null)[] & List) | null>();
|
141
|
+
});
|
142
|
+
|
143
|
+
test("should handle $onError on a child CoList", async () => {
|
144
|
+
class InnerMap extends CoMap {
|
145
|
+
value = co.string;
|
146
|
+
}
|
147
|
+
class List extends CoList.Of(co.ref(InnerMap)) {}
|
148
|
+
class MyMap extends CoMap {
|
149
|
+
list = co.ref(List);
|
150
|
+
}
|
151
|
+
|
152
|
+
const result = await MyMap.load("x" as ID<MyMap>, {
|
153
|
+
resolve: { list: { $each: { $onError: null } } },
|
154
|
+
});
|
155
|
+
|
156
|
+
function validateType(map: (InnerMap | null)[] & List) {
|
157
|
+
map;
|
158
|
+
}
|
159
|
+
|
160
|
+
assert(result);
|
161
|
+
|
162
|
+
validateType(result.list);
|
163
|
+
});
|
164
|
+
|
165
|
+
test("should handle $onError on CoMap.Record", async () => {
|
166
|
+
class Record extends CoMap.Record(co.ref(() => InnerMap)) {}
|
167
|
+
|
168
|
+
const result = await Record.load("x" as ID<Record>, {
|
169
|
+
resolve: { $each: { $onError: null } },
|
170
|
+
});
|
171
|
+
|
172
|
+
type ExpectedResult =
|
173
|
+
| ({
|
174
|
+
[key: string]: InnerMap | null;
|
175
|
+
} & Record)
|
176
|
+
| null;
|
177
|
+
|
178
|
+
function validateType(map: ExpectedResult) {
|
179
|
+
map;
|
180
|
+
}
|
181
|
+
|
182
|
+
validateType(result);
|
183
|
+
expectTypeOf(result).toEqualTypeOf<ExpectedResult>();
|
184
|
+
});
|
185
|
+
|
186
|
+
test("should handle $onError on a child CoMap.Record", async () => {
|
187
|
+
class Record extends CoMap.Record(co.ref(() => InnerMap)) {}
|
188
|
+
class MyMap extends CoMap {
|
189
|
+
record = co.ref(Record);
|
190
|
+
}
|
191
|
+
|
192
|
+
const result = await MyMap.load("x" as ID<MyMap>, {
|
193
|
+
resolve: { record: { $each: { $onError: null } } },
|
194
|
+
});
|
195
|
+
|
196
|
+
type ExpectedResult = {
|
197
|
+
[key: string]: InnerMap | null;
|
198
|
+
} & Record &
|
199
|
+
co<Record | null>;
|
200
|
+
|
201
|
+
function validateType(map: ExpectedResult) {
|
202
|
+
map;
|
203
|
+
}
|
204
|
+
|
205
|
+
assert(result);
|
206
|
+
|
207
|
+
validateType(result.record);
|
208
|
+
expectTypeOf(result.record).toEqualTypeOf<ExpectedResult>();
|
209
|
+
});
|
210
|
+
|
211
|
+
test("should handle $onError on a ref", async () => {
|
212
|
+
class Person extends CoMap {
|
213
|
+
name = co.string;
|
214
|
+
dog = co.ref(Dog);
|
215
|
+
}
|
216
|
+
|
217
|
+
class Dog extends CoMap {
|
218
|
+
name = co.string;
|
219
|
+
}
|
220
|
+
|
221
|
+
const result = await Person.load("x" as ID<Person>, {
|
222
|
+
resolve: { dog: { $onError: null } },
|
223
|
+
});
|
224
|
+
|
225
|
+
type ExpectedResult =
|
226
|
+
| (Person & {
|
227
|
+
dog: Dog | null;
|
228
|
+
})
|
229
|
+
| null;
|
230
|
+
|
231
|
+
function validateType(map: ExpectedResult) {
|
232
|
+
map;
|
233
|
+
}
|
234
|
+
|
235
|
+
validateType(result);
|
236
|
+
expectTypeOf(result).toEqualTypeOf<ExpectedResult>();
|
237
|
+
});
|
238
|
+
});
|
239
|
+
|
240
|
+
class CustomProfile extends Profile {
|
241
|
+
stream = co.ref(TestStream);
|
242
|
+
}
|
243
|
+
|
244
|
+
class CustomAccount extends Account {
|
245
|
+
profile = co.ref(CustomProfile);
|
246
|
+
root = co.ref(TestMap);
|
247
|
+
|
248
|
+
async migrate(
|
249
|
+
this: CustomAccount,
|
250
|
+
creationProps?: { name: string } | undefined,
|
251
|
+
) {
|
252
|
+
if (creationProps) {
|
253
|
+
const profileGroup = Group.create(this);
|
254
|
+
this.profile = CustomProfile.create(
|
255
|
+
{
|
256
|
+
name: creationProps.name,
|
257
|
+
stream: TestStream.create([], this),
|
258
|
+
},
|
259
|
+
profileGroup,
|
260
|
+
);
|
261
|
+
this.root = TestMap.create({ list: TestList.create([], this) }, this);
|
262
|
+
}
|
263
|
+
|
264
|
+
const thisLoaded = await this.ensureLoaded({
|
265
|
+
resolve: {
|
266
|
+
profile: { stream: true },
|
267
|
+
root: { list: true },
|
268
|
+
},
|
269
|
+
});
|
270
|
+
expectTypeOf(thisLoaded).toEqualTypeOf<
|
271
|
+
CustomAccount & {
|
272
|
+
profile: CustomProfile & {
|
273
|
+
stream: TestStream;
|
274
|
+
};
|
275
|
+
root: TestMap & {
|
276
|
+
list: TestList;
|
277
|
+
};
|
278
|
+
}
|
279
|
+
>();
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
test("Deep loading within account", async () => {
|
284
|
+
const me = await CustomAccount.create({
|
285
|
+
creationProps: { name: "Hermes Puggington" },
|
286
|
+
crypto: Crypto,
|
287
|
+
});
|
288
|
+
|
289
|
+
const meLoaded = await me.ensureLoaded({
|
290
|
+
resolve: {
|
291
|
+
profile: { stream: true },
|
292
|
+
root: { list: true },
|
293
|
+
},
|
294
|
+
});
|
295
|
+
expectTypeOf(meLoaded).toEqualTypeOf<
|
296
|
+
CustomAccount & {
|
297
|
+
profile: CustomProfile & {
|
298
|
+
stream: TestStream;
|
299
|
+
};
|
300
|
+
root: TestMap & {
|
301
|
+
list: TestList;
|
302
|
+
};
|
303
|
+
}
|
304
|
+
>();
|
305
|
+
});
|
306
|
+
|
307
|
+
class RecordLike extends CoMap.Record(co.ref(TestMap)) {}
|
308
|
+
|
309
|
+
test("Deep loading a record-like coMap", async () => {
|
310
|
+
const me = await Account.create({
|
311
|
+
creationProps: { name: "Hermes Puggington" },
|
312
|
+
crypto: Crypto,
|
313
|
+
});
|
314
|
+
|
315
|
+
const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
|
316
|
+
peer1role: "server",
|
317
|
+
peer2role: "client",
|
318
|
+
});
|
319
|
+
|
320
|
+
if (!isControlledAccount(me)) {
|
321
|
+
throw "me is not a controlled account";
|
322
|
+
}
|
323
|
+
|
324
|
+
me._raw.core.node.syncManager.addPeer(secondPeer);
|
325
|
+
const { account: meOnSecondPeer } =
|
326
|
+
await createJazzContextFromExistingCredentials({
|
327
|
+
credentials: {
|
328
|
+
accountID: me.id,
|
329
|
+
secret: me._raw.core.node.agentSecret,
|
330
|
+
},
|
331
|
+
sessionProvider: randomSessionProvider,
|
332
|
+
peersToLoadFrom: [initialAsPeer],
|
333
|
+
crypto: Crypto,
|
334
|
+
});
|
335
|
+
|
336
|
+
const record = RecordLike.create(
|
337
|
+
{
|
338
|
+
key1: TestMap.create(
|
339
|
+
{ list: TestList.create([], { owner: me }) },
|
340
|
+
{ owner: me },
|
341
|
+
),
|
342
|
+
key2: TestMap.create(
|
343
|
+
{ list: TestList.create([], { owner: me }) },
|
344
|
+
{ owner: me },
|
345
|
+
),
|
346
|
+
},
|
347
|
+
{ owner: me },
|
348
|
+
);
|
349
|
+
|
350
|
+
const recordLoaded = await RecordLike.load(record.id, {
|
351
|
+
loadAs: meOnSecondPeer,
|
352
|
+
resolve: {
|
353
|
+
$each: { list: { $each: true } },
|
354
|
+
},
|
355
|
+
});
|
356
|
+
expectTypeOf(recordLoaded).toEqualTypeOf<
|
357
|
+
| (RecordLike & {
|
358
|
+
[key: string]: TestMap & {
|
359
|
+
list: TestList & InnerMap[];
|
360
|
+
};
|
361
|
+
})
|
362
|
+
| null
|
363
|
+
>();
|
364
|
+
});
|
365
|
+
|
366
|
+
test("The resolve type doesn't accept extra keys", async () => {
|
367
|
+
const me = await CustomAccount.create({
|
368
|
+
creationProps: { name: "Hermes Puggington" },
|
369
|
+
crypto: Crypto,
|
370
|
+
});
|
371
|
+
|
372
|
+
const meLoaded = await me.ensureLoaded({
|
373
|
+
resolve: {
|
374
|
+
// @ts-expect-error
|
375
|
+
profile: { stream: true, extraKey: true },
|
376
|
+
// @ts-expect-error
|
377
|
+
root: { list: true, extraKey: true },
|
378
|
+
},
|
379
|
+
});
|
380
|
+
|
381
|
+
expectTypeOf(meLoaded).toEqualTypeOf<
|
382
|
+
CustomAccount & {
|
383
|
+
profile: CustomProfile & {
|
384
|
+
stream: TestStream;
|
385
|
+
extraKey: never;
|
386
|
+
};
|
387
|
+
root: TestMap & {
|
388
|
+
list: TestList;
|
389
|
+
extraKey: never;
|
390
|
+
};
|
391
|
+
}
|
392
|
+
>();
|
393
|
+
});
|
@@ -612,6 +612,254 @@ describe("Deep loading with unauthorized account", async () => {
|
|
612
612
|
|
613
613
|
expect(loadedMap?.id).toBe(map.id);
|
614
614
|
});
|
615
|
+
|
616
|
+
test("unaccessible record element with $onError", async () => {
|
617
|
+
class Person extends CoMap {
|
618
|
+
name = co.string;
|
619
|
+
}
|
620
|
+
class Friends extends CoMap.Record(co.ref(Person)) {}
|
621
|
+
|
622
|
+
const map = Friends.create(
|
623
|
+
{
|
624
|
+
jane: Person.create({ name: "Jane" }, onlyBob),
|
625
|
+
alice: Person.create({ name: "Alice" }, group),
|
626
|
+
},
|
627
|
+
group,
|
628
|
+
);
|
629
|
+
|
630
|
+
const friendsOnAlice = await Friends.load(map.id, {
|
631
|
+
resolve: { $each: { $onError: null } },
|
632
|
+
loadAs: alice,
|
633
|
+
});
|
634
|
+
|
635
|
+
assert(friendsOnAlice, "friendsOnAlice is null");
|
636
|
+
|
637
|
+
expect(friendsOnAlice.jane).toBeNull();
|
638
|
+
expect(friendsOnAlice.alice).not.toBeNull();
|
639
|
+
});
|
640
|
+
|
641
|
+
test("unaccessible nested record element with $onError", async () => {
|
642
|
+
class Person extends CoMap {
|
643
|
+
name = co.string;
|
644
|
+
}
|
645
|
+
class Friends extends CoMap.Record(co.ref(Person)) {}
|
646
|
+
|
647
|
+
class User extends CoMap {
|
648
|
+
name = co.string;
|
649
|
+
friends = co.ref(Friends);
|
650
|
+
}
|
651
|
+
|
652
|
+
const map = User.create(
|
653
|
+
{
|
654
|
+
name: "John",
|
655
|
+
friends: Friends.create(
|
656
|
+
{
|
657
|
+
jane: Person.create({ name: "Jane" }, onlyBob),
|
658
|
+
alice: Person.create({ name: "Alice" }, group),
|
659
|
+
},
|
660
|
+
group,
|
661
|
+
),
|
662
|
+
},
|
663
|
+
group,
|
664
|
+
);
|
665
|
+
|
666
|
+
const user = await User.load(map.id, {
|
667
|
+
resolve: { friends: { $each: { $onError: null } } },
|
668
|
+
loadAs: alice,
|
669
|
+
});
|
670
|
+
|
671
|
+
assert(user, "user is null");
|
672
|
+
|
673
|
+
expect(user.friends.jane).toBeNull();
|
674
|
+
expect(user.friends.alice).not.toBeNull();
|
675
|
+
});
|
676
|
+
|
677
|
+
test("unaccessible element down the chain with $onError on a record", async () => {
|
678
|
+
class Person extends CoMap {
|
679
|
+
name = co.string;
|
680
|
+
dog = co.ref(Dog);
|
681
|
+
}
|
682
|
+
class Dog extends CoMap {
|
683
|
+
name = co.string;
|
684
|
+
}
|
685
|
+
class Friends extends CoMap.Record(co.ref(Person)) {}
|
686
|
+
|
687
|
+
class User extends CoMap {
|
688
|
+
name = co.string;
|
689
|
+
friends = co.ref(Friends);
|
690
|
+
}
|
691
|
+
|
692
|
+
const map = User.create(
|
693
|
+
{
|
694
|
+
name: "John",
|
695
|
+
friends: Friends.create(
|
696
|
+
{
|
697
|
+
jane: Person.create(
|
698
|
+
{
|
699
|
+
name: "Jane",
|
700
|
+
dog: Dog.create({ name: "Rex" }, onlyBob), // Jane dog is inaccessible
|
701
|
+
},
|
702
|
+
group,
|
703
|
+
),
|
704
|
+
alice: Person.create(
|
705
|
+
{ name: "Alice", dog: Dog.create({ name: "Giggino" }, group) },
|
706
|
+
group,
|
707
|
+
),
|
708
|
+
},
|
709
|
+
group,
|
710
|
+
),
|
711
|
+
},
|
712
|
+
group,
|
713
|
+
);
|
714
|
+
|
715
|
+
const user = await User.load(map.id, {
|
716
|
+
resolve: { friends: { $each: { dog: true, $onError: null } } },
|
717
|
+
loadAs: alice,
|
718
|
+
});
|
719
|
+
|
720
|
+
assert(user);
|
721
|
+
|
722
|
+
expect(user.friends.jane).toBeNull(); // jane is null because her dog is inaccessible
|
723
|
+
expect(user.friends.alice?.dog).not.toBeNull(); // alice is not null because we have read access to her and her dog
|
724
|
+
});
|
725
|
+
|
726
|
+
test("unaccessible list element with $onError and $each with depth", async () => {
|
727
|
+
class Person extends CoMap {
|
728
|
+
name = co.string;
|
729
|
+
friends = co.optional.ref(Friends);
|
730
|
+
}
|
731
|
+
class Friends extends CoList.Of(co.ref(Person)) {}
|
732
|
+
|
733
|
+
const list = Friends.create(
|
734
|
+
[
|
735
|
+
Person.create(
|
736
|
+
{
|
737
|
+
name: "Jane",
|
738
|
+
friends: Friends.create(
|
739
|
+
[Person.create({ name: "Bob" }, onlyBob)],
|
740
|
+
group,
|
741
|
+
),
|
742
|
+
},
|
743
|
+
group,
|
744
|
+
),
|
745
|
+
Person.create(
|
746
|
+
{
|
747
|
+
name: "Alice",
|
748
|
+
friends: Friends.create(
|
749
|
+
[Person.create({ name: "Bob" }, group)],
|
750
|
+
group,
|
751
|
+
),
|
752
|
+
},
|
753
|
+
group,
|
754
|
+
),
|
755
|
+
],
|
756
|
+
group,
|
757
|
+
);
|
758
|
+
|
759
|
+
// The error List -> Jane -> Bob should be propagated to the list element Jane
|
760
|
+
// and we should have [null, Alice]
|
761
|
+
const listOnAlice = await Friends.load(list.id, {
|
762
|
+
resolve: { $each: { friends: { $each: true }, $onError: null } },
|
763
|
+
loadAs: alice,
|
764
|
+
});
|
765
|
+
|
766
|
+
assert(listOnAlice, "listOnAlice is null");
|
767
|
+
|
768
|
+
expect(listOnAlice[0]).toBeNull();
|
769
|
+
expect(listOnAlice[1]).not.toBeNull();
|
770
|
+
expect(listOnAlice[1]?.name).toBe("Alice");
|
771
|
+
expect(listOnAlice[1]?.friends).not.toBeNull();
|
772
|
+
expect(listOnAlice[1]?.friends?.[0]?.name).toBe("Bob");
|
773
|
+
expect(listOnAlice).toHaveLength(2);
|
774
|
+
});
|
775
|
+
|
776
|
+
test("unaccessible record element with $onError", async () => {
|
777
|
+
class Person extends CoMap {
|
778
|
+
name = co.string;
|
779
|
+
}
|
780
|
+
class Friend extends CoMap.Record(co.ref(Person)) {}
|
781
|
+
|
782
|
+
const map = Friend.create(
|
783
|
+
{
|
784
|
+
jane: Person.create({ name: "Jane" }, onlyBob),
|
785
|
+
alice: Person.create({ name: "Alice" }, group),
|
786
|
+
},
|
787
|
+
group,
|
788
|
+
);
|
789
|
+
|
790
|
+
const friendsOnAlice = await Friend.load(map.id, {
|
791
|
+
resolve: { $each: { $onError: null } },
|
792
|
+
loadAs: alice,
|
793
|
+
});
|
794
|
+
|
795
|
+
assert(friendsOnAlice, "friendsOnAlice is null");
|
796
|
+
|
797
|
+
expect(friendsOnAlice.jane).toBeNull();
|
798
|
+
expect(friendsOnAlice.alice).not.toBeNull();
|
799
|
+
});
|
800
|
+
|
801
|
+
test("unaccessible ref catched with $onError", async () => {
|
802
|
+
class Person extends CoMap {
|
803
|
+
name = co.string;
|
804
|
+
dog = co.ref(Dog);
|
805
|
+
}
|
806
|
+
class Dog extends CoMap {
|
807
|
+
name = co.string;
|
808
|
+
}
|
809
|
+
class Friends extends CoMap.Record(co.ref(Person)) {}
|
810
|
+
|
811
|
+
class User extends CoMap {
|
812
|
+
name = co.string;
|
813
|
+
friends = co.ref(Friends);
|
814
|
+
}
|
815
|
+
|
816
|
+
const map = User.create(
|
817
|
+
{
|
818
|
+
name: "John",
|
819
|
+
friends: Friends.create(
|
820
|
+
{
|
821
|
+
jane: Person.create(
|
822
|
+
{
|
823
|
+
name: "Jane",
|
824
|
+
dog: Dog.create({ name: "Rex" }, onlyBob), // Jane dog is inaccessible
|
825
|
+
},
|
826
|
+
group,
|
827
|
+
),
|
828
|
+
alice: Person.create(
|
829
|
+
{ name: "Alice", dog: Dog.create({ name: "Giggino" }, group) },
|
830
|
+
group,
|
831
|
+
),
|
832
|
+
},
|
833
|
+
group,
|
834
|
+
),
|
835
|
+
},
|
836
|
+
group,
|
837
|
+
);
|
838
|
+
|
839
|
+
const user = await User.load(map.id, {
|
840
|
+
resolve: { friends: { $each: { dog: { $onError: null } } } },
|
841
|
+
loadAs: alice,
|
842
|
+
});
|
843
|
+
|
844
|
+
assert(user);
|
845
|
+
|
846
|
+
expect(user.friends.jane?.dog).toBeNull(); // jane is null because her dog is inaccessible
|
847
|
+
expect(user.friends.alice?.dog?.name).toBe("Giggino"); // alice is not null because we have read access to her and her dog
|
848
|
+
});
|
849
|
+
|
850
|
+
test("using $onError on the resolve root", async () => {
|
851
|
+
class Person extends CoMap {
|
852
|
+
name = co.string;
|
853
|
+
}
|
854
|
+
|
855
|
+
const map = Person.create({ name: "John" }, onlyBob);
|
856
|
+
const user = await Person.load(map.id, {
|
857
|
+
resolve: { $onError: null },
|
858
|
+
loadAs: alice,
|
859
|
+
});
|
860
|
+
|
861
|
+
expect(user).toBeNull();
|
862
|
+
});
|
615
863
|
});
|
616
864
|
|
617
865
|
test("doesn't break on Map.Record key deletion when the key is referenced in the depth", async () => {
|
@@ -689,6 +937,7 @@ test("throw when calling ensureLoaded on a ref that is not defined in the schema
|
|
689
937
|
|
690
938
|
await expect(
|
691
939
|
root.ensureLoaded({
|
940
|
+
// @ts-expect-error missing required ref
|
692
941
|
resolve: { profile: true },
|
693
942
|
}),
|
694
943
|
).rejects.toThrow("Failed to deeply load CoValue " + root.id);
|