jazz-tools 0.7.0-alpha.9 → 0.7.1

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 (72) hide show
  1. package/.eslintrc.cjs +3 -10
  2. package/.prettierrc.js +9 -0
  3. package/.turbo/turbo-build.log +3 -19
  4. package/.turbo/turbo-lint.log +4 -0
  5. package/.turbo/turbo-test.log +140 -0
  6. package/CHANGELOG.md +298 -0
  7. package/README.md +10 -2
  8. package/dist/coValues/account.js +59 -41
  9. package/dist/coValues/account.js.map +1 -1
  10. package/dist/coValues/coList.js +49 -46
  11. package/dist/coValues/coList.js.map +1 -1
  12. package/dist/coValues/coMap.js +143 -44
  13. package/dist/coValues/coMap.js.map +1 -1
  14. package/dist/coValues/coStream.js +144 -35
  15. package/dist/coValues/coStream.js.map +1 -1
  16. package/dist/coValues/deepLoading.js +60 -0
  17. package/dist/coValues/deepLoading.js.map +1 -0
  18. package/dist/coValues/extensions/imageDef.js +10 -7
  19. package/dist/coValues/extensions/imageDef.js.map +1 -1
  20. package/dist/coValues/group.js +49 -13
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/coValues/interfaces.js +70 -31
  23. package/dist/coValues/interfaces.js.map +1 -1
  24. package/dist/implementation/devtoolsFormatters.js +114 -0
  25. package/dist/implementation/devtoolsFormatters.js.map +1 -0
  26. package/dist/implementation/refs.js +58 -18
  27. package/dist/implementation/refs.js.map +1 -1
  28. package/dist/implementation/schema.js +58 -0
  29. package/dist/implementation/schema.js.map +1 -0
  30. package/dist/implementation/subscriptionScope.js +19 -1
  31. package/dist/implementation/subscriptionScope.js.map +1 -1
  32. package/dist/implementation/symbols.js +5 -0
  33. package/dist/implementation/symbols.js.map +1 -0
  34. package/dist/index.js +3 -5
  35. package/dist/index.js.map +1 -1
  36. package/dist/internal.js +5 -2
  37. package/dist/internal.js.map +1 -1
  38. package/dist/tests/coList.test.js +51 -48
  39. package/dist/tests/coList.test.js.map +1 -1
  40. package/dist/tests/coMap.test.js +131 -74
  41. package/dist/tests/coMap.test.js.map +1 -1
  42. package/dist/tests/coStream.test.js +56 -41
  43. package/dist/tests/coStream.test.js.map +1 -1
  44. package/dist/tests/deepLoading.test.js +188 -0
  45. package/dist/tests/deepLoading.test.js.map +1 -0
  46. package/dist/tests/groupsAndAccounts.test.js +83 -0
  47. package/dist/tests/groupsAndAccounts.test.js.map +1 -0
  48. package/package.json +17 -9
  49. package/src/coValues/account.ts +113 -125
  50. package/src/coValues/coList.ts +87 -103
  51. package/src/coValues/coMap.ts +200 -147
  52. package/src/coValues/coStream.ts +264 -80
  53. package/src/coValues/deepLoading.ts +229 -0
  54. package/src/coValues/extensions/imageDef.ts +17 -13
  55. package/src/coValues/group.ts +92 -58
  56. package/src/coValues/interfaces.ts +215 -115
  57. package/src/implementation/devtoolsFormatters.ts +110 -0
  58. package/src/implementation/inspect.ts +1 -1
  59. package/src/implementation/refs.ts +80 -28
  60. package/src/implementation/schema.ts +138 -0
  61. package/src/implementation/subscriptionScope.ts +48 -12
  62. package/src/implementation/symbols.ts +11 -0
  63. package/src/index.ts +12 -8
  64. package/src/internal.ts +7 -3
  65. package/src/tests/coList.test.ts +77 -62
  66. package/src/tests/coMap.test.ts +201 -114
  67. package/src/tests/coStream.test.ts +113 -84
  68. package/src/tests/deepLoading.test.ts +301 -0
  69. package/src/tests/groupsAndAccounts.test.ts +91 -0
  70. package/dist/implementation/encoding.js +0 -26
  71. package/dist/implementation/encoding.js.map +0 -1
  72. package/src/implementation/encoding.ts +0 -105
@@ -0,0 +1,301 @@
1
+ const Crypto = await WasmCrypto.create();
2
+ import { expect, describe, test, expectTypeOf } from "vitest";
3
+ import { connectedPeers } from "cojson/src/streamUtils.js";
4
+ import {
5
+ Account,
6
+ CoList,
7
+ CoMap,
8
+ CoStream,
9
+ SessionID,
10
+ WasmCrypto,
11
+ co,
12
+ Profile,
13
+ isControlledAccount,
14
+ ID,
15
+ } from "../index.js";
16
+ import { newRandomSessionID } from "cojson/src/coValueCore.js";
17
+
18
+ class TestMap extends CoMap {
19
+ list = co.ref(TestList);
20
+ optionalRef = co.ref(InnermostMap, { optional: true });
21
+ }
22
+
23
+ class TestList extends CoList.Of(co.ref(() => InnerMap)) {}
24
+
25
+ class InnerMap extends CoMap {
26
+ stream = co.ref(TestStream);
27
+ }
28
+
29
+ class TestStream extends CoStream.Of(co.ref(() => InnermostMap)) {}
30
+
31
+ class InnermostMap extends CoMap {
32
+ value = co.string;
33
+ }
34
+
35
+ describe("Deep loading with depth arg", async () => {
36
+ const me = await Account.create({
37
+ creationProps: { name: "Hermes Puggington" },
38
+ crypto: Crypto,
39
+ });
40
+
41
+ const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
42
+ peer1role: "server",
43
+ peer2role: "client",
44
+ });
45
+ if (!isControlledAccount(me)) {
46
+ throw "me is not a controlled account";
47
+ }
48
+ me._raw.core.node.syncManager.addPeer(secondPeer);
49
+ const meOnSecondPeer = await Account.become({
50
+ accountID: me.id,
51
+ accountSecret: me._raw.agentSecret,
52
+ peersToLoadFrom: [initialAsPeer],
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ sessionID: newRandomSessionID(me.id as any),
55
+ crypto: Crypto,
56
+ });
57
+
58
+ test("loading a deeply nested object will wait until all required refs are loaded", async () => {
59
+ const map = TestMap.create(
60
+ {
61
+ list: TestList.create(
62
+ [
63
+ InnerMap.create(
64
+ {
65
+ stream: TestStream.create(
66
+ [
67
+ InnermostMap.create(
68
+ { value: "hello" },
69
+ { owner: me },
70
+ ),
71
+ ],
72
+ { owner: me },
73
+ ),
74
+ },
75
+ { owner: me },
76
+ ),
77
+ ],
78
+ { owner: me },
79
+ ),
80
+ },
81
+ { owner: me },
82
+ );
83
+
84
+ const map1 = await TestMap.load(map.id, meOnSecondPeer, {});
85
+ expectTypeOf(map1).toEqualTypeOf<TestMap | undefined>();
86
+ if (map1 === undefined) {
87
+ throw new Error("map1 is undefined");
88
+ }
89
+ expect(map1.list).toBe(null);
90
+
91
+ const map2 = await TestMap.load(map.id, meOnSecondPeer, { list: [] });
92
+ expectTypeOf(map2).toEqualTypeOf<
93
+ | (TestMap & {
94
+ list: TestList;
95
+ })
96
+ | undefined
97
+ >();
98
+ if (map2 === undefined) {
99
+ throw new Error("map2 is undefined");
100
+ }
101
+ expect(map2.list).not.toBe(null);
102
+ expect(map2.list[0]).toBe(null);
103
+
104
+ const map3 = await TestMap.load(map.id, meOnSecondPeer, { list: [{}] });
105
+ expectTypeOf(map3).toEqualTypeOf<
106
+ | (TestMap & {
107
+ list: TestList & InnerMap[];
108
+ })
109
+ | undefined
110
+ >();
111
+ if (map3 === undefined) {
112
+ throw new Error("map3 is undefined");
113
+ }
114
+ expect(map3.list[0]).not.toBe(null);
115
+ expect(map3.list[0]?.stream).toBe(null);
116
+
117
+ const map3a = await TestMap.load(map.id, meOnSecondPeer, {
118
+ optionalRef: {},
119
+ });
120
+ expectTypeOf(map3a).toEqualTypeOf<
121
+ | (TestMap & {
122
+ optionalRef: InnermostMap | undefined;
123
+ })
124
+ | undefined
125
+ >();
126
+
127
+ const map4 = await TestMap.load(map.id, meOnSecondPeer, {
128
+ list: [{ stream: [] }],
129
+ });
130
+ expectTypeOf(map4).toEqualTypeOf<
131
+ | (TestMap & {
132
+ list: TestList & (InnerMap & { stream: TestStream })[];
133
+ })
134
+ | undefined
135
+ >();
136
+ if (map4 === undefined) {
137
+ throw new Error("map4 is undefined");
138
+ }
139
+ expect(map4.list[0]?.stream).not.toBe(null);
140
+ // TODO: we should expect null here, but apparently we don't even have the id/ref?
141
+ expect(map4.list[0]?.stream?.[me.id]?.value).not.toBeDefined();
142
+ expect(map4.list[0]?.stream?.byMe?.value).not.toBeDefined();
143
+
144
+ const map5 = await TestMap.load(map.id, meOnSecondPeer, {
145
+ list: [{ stream: [{}] }],
146
+ });
147
+ type ExpectedMap5 =
148
+ | (TestMap & {
149
+ list: TestList &
150
+ (InnerMap & {
151
+ stream: TestStream & {
152
+ byMe?: { value: InnermostMap };
153
+ inCurrentSession?: { value: InnermostMap };
154
+ perSession: {
155
+ [sessionID: SessionID]: {
156
+ value: InnermostMap;
157
+ };
158
+ };
159
+ } & {
160
+ [key: ID<Account>]: { value: InnermostMap };
161
+ };
162
+ })[];
163
+ })
164
+ | undefined;
165
+
166
+ expectTypeOf(map5).toEqualTypeOf<ExpectedMap5>();
167
+ if (map5 === undefined) {
168
+ throw new Error("map5 is undefined");
169
+ }
170
+ expect(map5.list[0]?.stream?.[me.id]?.value).not.toBe(null);
171
+ expect(map5.list[0]?.stream?.byMe?.value).not.toBe(null);
172
+ });
173
+ });
174
+
175
+ class CustomProfile extends Profile {
176
+ stream = co.ref(TestStream);
177
+ }
178
+
179
+ class CustomAccount extends Account {
180
+ profile = co.ref(CustomProfile);
181
+ root = co.ref(TestMap);
182
+
183
+ async migrate(creationProps?: { name: string } | undefined) {
184
+ if (creationProps) {
185
+ this.profile = CustomProfile.create(
186
+ {
187
+ name: creationProps.name,
188
+ stream: TestStream.create([], { owner: this }),
189
+ },
190
+ { owner: this },
191
+ );
192
+ this.root = TestMap.create(
193
+ { list: TestList.create([], { owner: this }) },
194
+ { owner: this },
195
+ );
196
+ }
197
+
198
+ const thisLoaded = await CustomAccount.load(this, {
199
+ profile: { stream: [] },
200
+ root: { list: [] },
201
+ });
202
+ expectTypeOf(thisLoaded).toEqualTypeOf<
203
+ | (CustomAccount & {
204
+ profile: CustomProfile & {
205
+ stream: TestStream;
206
+ };
207
+ root: TestMap & {
208
+ list: TestList;
209
+ };
210
+ })
211
+ | undefined
212
+ >();
213
+ }
214
+ }
215
+
216
+ test("Deep loading within account", async () => {
217
+ const me = await CustomAccount.create({
218
+ creationProps: { name: "Hermes Puggington" },
219
+ crypto: Crypto,
220
+ });
221
+
222
+ const meLoaded = await CustomAccount.load(me, {
223
+ profile: { stream: [] },
224
+ root: { list: [] },
225
+ });
226
+ expectTypeOf(meLoaded).toEqualTypeOf<
227
+ | (CustomAccount & {
228
+ profile: CustomProfile & {
229
+ stream: TestStream;
230
+ };
231
+ root: TestMap & {
232
+ list: TestList;
233
+ };
234
+ })
235
+ | undefined
236
+ >();
237
+ if (meLoaded === undefined) {
238
+ throw new Error("meLoaded is undefined");
239
+ }
240
+ expect(meLoaded.profile.stream).not.toBe(null);
241
+ expect(meLoaded.root.list).not.toBe(null);
242
+ });
243
+
244
+ class RecordLike extends CoMap.Record(co.ref(TestMap)) {}
245
+
246
+ test("Deep loading a record-like coMap", async () => {
247
+ const me = await Account.create({
248
+ creationProps: { name: "Hermes Puggington" },
249
+ crypto: Crypto,
250
+ });
251
+
252
+ const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
253
+ peer1role: "server",
254
+ peer2role: "client",
255
+ });
256
+ if (!isControlledAccount(me)) {
257
+ throw "me is not a controlled account";
258
+ }
259
+ me._raw.core.node.syncManager.addPeer(secondPeer);
260
+ const meOnSecondPeer = await Account.become({
261
+ accountID: me.id,
262
+ accountSecret: me._raw.agentSecret,
263
+ peersToLoadFrom: [initialAsPeer],
264
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
265
+ sessionID: newRandomSessionID(me.id as any),
266
+ crypto: Crypto,
267
+ });
268
+
269
+ const record = RecordLike.create(
270
+ {
271
+ key1: TestMap.create(
272
+ { list: TestList.create([], { owner: me }) },
273
+ { owner: me },
274
+ ),
275
+ key2: TestMap.create(
276
+ { list: TestList.create([], { owner: me }) },
277
+ { owner: me },
278
+ ),
279
+ },
280
+ { owner: me },
281
+ );
282
+
283
+ const recordLoaded = await RecordLike.load(record.id, meOnSecondPeer, [
284
+ { list: [{}] },
285
+ ]);
286
+ expectTypeOf(recordLoaded).toEqualTypeOf<
287
+ | (RecordLike & {
288
+ [key: string]: TestMap & {
289
+ list: TestList & InnerMap[];
290
+ };
291
+ })
292
+ | undefined
293
+ >();
294
+ if (recordLoaded === undefined) {
295
+ throw new Error("recordLoaded is undefined");
296
+ }
297
+ expect(recordLoaded.key1?.list).not.toBe(null);
298
+ expect(recordLoaded.key1?.list).not.toBe(undefined);
299
+ expect(recordLoaded.key2?.list).not.toBe(null);
300
+ expect(recordLoaded.key2?.list).not.toBe(undefined);
301
+ });
@@ -0,0 +1,91 @@
1
+ import { expect, describe, test } from "vitest";
2
+ import { Account, CoMap, co, Group, WasmCrypto } from "../index.js";
3
+
4
+ const Crypto = await WasmCrypto.create();
5
+
6
+ describe("Custom accounts and groups", async () => {
7
+ class CustomProfile extends CoMap {
8
+ name = co.string;
9
+ color = co.string;
10
+ }
11
+
12
+ class CustomAccount extends Account {
13
+ profile = co.ref(CustomProfile);
14
+ root = co.ref(CoMap);
15
+
16
+ migrate(creationProps?: { name: string }) {
17
+ if (creationProps) {
18
+ const profileGroup = Group.create({ owner: this });
19
+ profileGroup.addMember("everyone", "reader");
20
+ this.profile = CustomProfile.create(
21
+ { name: creationProps.name, color: "blue" },
22
+ { owner: this },
23
+ );
24
+ }
25
+ }
26
+ }
27
+
28
+ class CustomGroup extends Group {
29
+ profile = co.null;
30
+ root = co.null;
31
+ [co.members] = co.ref(CustomAccount);
32
+
33
+ get nMembers() {
34
+ return this.members.length;
35
+ }
36
+ }
37
+
38
+ test("Custom account and group", async () => {
39
+ const me = await CustomAccount.create({
40
+ creationProps: { name: "Hermes Puggington" },
41
+ crypto: Crypto,
42
+ });
43
+
44
+ expect(me.profile).toBeDefined();
45
+ expect(me.profile?.name).toBe("Hermes Puggington");
46
+ expect(me.profile?.color).toBe("blue");
47
+
48
+ const group = new CustomGroup({ owner: me });
49
+ group.addMember("everyone", "reader");
50
+
51
+ expect(group.members).toMatchObject([
52
+ { id: me.id, role: "admin" },
53
+ { id: "everyone", role: "reader" },
54
+ ]);
55
+
56
+ expect(group.nMembers).toBe(2);
57
+
58
+ await new Promise<void>((resolve) => {
59
+ CustomGroup.subscribe(group, {}, (update) => {
60
+ const meAsMember = update.members.find((member) => {
61
+ return member.id === me.id && member.account?.profile;
62
+ });
63
+ if (meAsMember) {
64
+ expect(meAsMember.account?.profile?.name).toBe(
65
+ "Hermes Puggington",
66
+ );
67
+ expect(meAsMember.account?.profile?.color).toBe("blue");
68
+ resolve();
69
+ }
70
+ });
71
+ });
72
+
73
+ class MyMap extends CoMap {
74
+ name = co.string;
75
+ }
76
+
77
+ const map = MyMap.create({ name: "test" }, { owner: group });
78
+
79
+ const meAsCastMember = map._owner
80
+ .as(CustomGroup)
81
+ .members.find((member) => member.id === me.id);
82
+ expect(meAsCastMember?.account?.profile?.name).toBe(
83
+ "Hermes Puggington",
84
+ );
85
+ expect(meAsCastMember?.account?.profile?.color).toBe("blue");
86
+
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ expect((map._owner as any).nMembers).toBeUndefined();
89
+ expect(map._owner.as(CustomGroup).nMembers).toBe(2);
90
+ });
91
+ });
@@ -1,26 +0,0 @@
1
- export const SchemaInit = Symbol.for("SchemaInit");
2
- export const InitValues = Symbol.for("InitValues");
3
- export const ItemsSym = Symbol.for("items");
4
- export const val = {
5
- string: { [SchemaInit]: "json" },
6
- number: { [SchemaInit]: "json" },
7
- boolean: { [SchemaInit]: "json" },
8
- literal: (_lit) => {
9
- return { [SchemaInit]: "json" };
10
- },
11
- json: () => {
12
- return { [SchemaInit]: "json" };
13
- },
14
- encoded: (arg) => {
15
- return { [SchemaInit]: { encoded: arg } };
16
- },
17
- ref: (arg) => {
18
- return { [SchemaInit]: { ref: arg } };
19
- },
20
- items: ItemsSym,
21
- };
22
- import { Date } from "@effect/schema/Schema";
23
- export const Encoders = {
24
- Date,
25
- };
26
- //# sourceMappingURL=encoding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/implementation/encoding.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAGnD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAGnD,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAG5C,MAAM,CAAC,MAAM,GAAG,GAAG;IACf,MAAM,EAAE,EAAC,CAAC,UAAU,CAAC,EAAE,MAAyB,EAA4B;IAC5E,MAAM,EAAE,EAAC,CAAC,UAAU,CAAC,EAAE,MAAyB,EAA4B;IAC5E,OAAO,EAAE,EAAC,CAAC,UAAU,CAAC,EAAE,MAAyB,EAA6B;IAC9E,OAAO,EAAE,CACL,IAAO,EACD,EAAE;QACR,OAAO,EAAC,CAAC,UAAU,CAAC,EAAE,MAAyB,EAAS,CAAC;IAC7D,CAAC;IACD,IAAI,EAAE,GAAgC,EAAE;QACpC,OAAO,EAAC,CAAC,UAAU,CAAC,EAAE,MAAyB,EAAS,CAAC;IAC7D,CAAC;IACD,OAAO,EAAE,CAAI,GAAe,EAAU,EAAE;QACpC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAqB,EAAS,CAAC;IACxE,CAAC;IACD,GAAG,EAAE,CACD,GAAyC,EACd,EAAE;QAC7B,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAqB,EAAS,CAAC;IACpE,CAAC;IACD,KAAK,EAAE,QAAoB;CAC9B,CAAA;AA6BD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,MAAM,CAAC,MAAM,QAAQ,GAAG;IACpB,IAAI;CACP,CAAC"}
@@ -1,105 +0,0 @@
1
- import type { JsonValue, RawCoValue } from "cojson";
2
- import type { CoValue, CoValueClass } from "../internal.js";
3
- import type { Schema, TypeId } from "@effect/schema/Schema";
4
-
5
- export type ValMarker = { readonly __field: unique symbol };
6
- export type val<T> = T | (T & ValMarker);
7
- export type IsVal<C, R> = C extends infer _A | infer B
8
- ? B extends ValMarker
9
- ? R
10
- : never
11
- : never;
12
-
13
- export const SchemaInit = Symbol.for("SchemaInit");
14
- export type SchemaInit = typeof SchemaInit;
15
-
16
- export const InitValues = Symbol.for("InitValues");
17
- export type InitValues = typeof InitValues;
18
-
19
- export const ItemsSym = Symbol.for("items");
20
- export type ItemsSym = typeof ItemsSym;
21
-
22
- export const val = {
23
- string: {[SchemaInit]: "json" satisfies Encoding } as unknown as val<string>,
24
- number: {[SchemaInit]: "json" satisfies Encoding } as unknown as val<number>,
25
- boolean: {[SchemaInit]: "json" satisfies Encoding } as unknown as val<boolean>,
26
- literal: <T extends string | number | boolean>(
27
- _lit: T
28
- ): val<T> => {
29
- return {[SchemaInit]: "json" satisfies Encoding } as any;
30
- },
31
- json: <T extends JsonValue>(): val<T> => {
32
- return {[SchemaInit]: "json" satisfies Encoding } as any;
33
- },
34
- encoded: <T>(arg: Encoder<T>): val<T> => {
35
- return { [SchemaInit]: { encoded: arg } satisfies Encoding } as any;
36
- },
37
- ref: <C extends CoValueClass>(
38
- arg: (_raw: InstanceType<C>['_raw']) => C
39
- ): val<InstanceType<C> | null> => {
40
- return { [SchemaInit]: { ref: arg } satisfies Encoding } as any;
41
- },
42
- items: ItemsSym as ItemsSym,
43
- }
44
-
45
- export type JsonEncoded = "json";
46
- export type EncodedAs<V> = { encoded: Encoder<V> };
47
- export type RefEncoded<V extends CoValue> = {
48
- ref: (raw: RawCoValue) => CoValueClass<V>;
49
- };
50
-
51
- export type Encoding = JsonEncoded | RefEncoded<CoValue> | EncodedAs<any>;
52
-
53
- export type EncodingFor<Field> = NonNullable<Field> extends CoValue
54
- ? RefEncoded<NonNullable<Field>>
55
- : NonNullable<Field> extends JsonValue
56
- ? JsonEncoded
57
- : EncodedAs<NonNullable<Field>>;
58
-
59
- export type EffectSchemaWithInputAndOutput<A, I = A> = Schema<
60
- any,
61
- any,
62
- never
63
- > & {
64
- [TypeId]: {
65
- _A: (_: any) => A;
66
- _I: (_: any) => I;
67
- };
68
- };
69
-
70
- export type Encoder<V> = EffectSchemaWithInputAndOutput<V, JsonValue>;
71
-
72
- import { Date } from "@effect/schema/Schema";
73
-
74
- export const Encoders = {
75
- Date,
76
- };
77
-
78
- export type EnsureCoValueNullable<
79
- V,
80
- Key extends string | ItemsSym,
81
- > = NonNullable<V> extends CoValue
82
- ? null extends V
83
- ? V
84
- : Key extends string
85
- ? [
86
- `👋 CoMap fields that are CoValue references should be nullable, declare ${Key} as:`,
87
- V | null,
88
- ]
89
- : [
90
- `👋 CoMap fields that are CoValue references should be nullable, declare _item as:`,
91
- V | null,
92
- ]
93
- : V;
94
-
95
- export type ValidItem<
96
- Item,
97
- ContainerType extends string,
98
- > = NonNullable<Item> extends CoValue
99
- ? null extends Item
100
- ? any
101
- : [
102
- `👋 CoList items that are CoValue references should be nullable, make sure the Item generic parameter of ${ContainerType} is:`,
103
- Item | null,
104
- ]
105
- : any;