jazz-tools 0.7.0-alpha.9 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. package/.eslintrc.cjs +3 -10
  2. package/.prettierrc.js +9 -0
  3. package/.turbo/turbo-build.log +14 -15
  4. package/.turbo/turbo-lint.log +4 -0
  5. package/.turbo/turbo-test.log +140 -0
  6. package/CHANGELOG.md +331 -27
  7. package/LICENSE.txt +1 -1
  8. package/README.md +10 -2
  9. package/dist/coValues/account.js +86 -41
  10. package/dist/coValues/account.js.map +1 -1
  11. package/dist/coValues/coList.js +75 -48
  12. package/dist/coValues/coList.js.map +1 -1
  13. package/dist/coValues/coMap.js +167 -44
  14. package/dist/coValues/coMap.js.map +1 -1
  15. package/dist/coValues/coStream.js +192 -35
  16. package/dist/coValues/coStream.js.map +1 -1
  17. package/dist/coValues/deepLoading.js +60 -0
  18. package/dist/coValues/deepLoading.js.map +1 -0
  19. package/dist/coValues/extensions/imageDef.js +10 -7
  20. package/dist/coValues/extensions/imageDef.js.map +1 -1
  21. package/dist/coValues/group.js +73 -13
  22. package/dist/coValues/group.js.map +1 -1
  23. package/dist/coValues/interfaces.js +58 -35
  24. package/dist/coValues/interfaces.js.map +1 -1
  25. package/dist/implementation/devtoolsFormatters.js +114 -0
  26. package/dist/implementation/devtoolsFormatters.js.map +1 -0
  27. package/dist/implementation/refs.js +58 -18
  28. package/dist/implementation/refs.js.map +1 -1
  29. package/dist/implementation/schema.js +58 -0
  30. package/dist/implementation/schema.js.map +1 -0
  31. package/dist/implementation/subscriptionScope.js +19 -1
  32. package/dist/implementation/subscriptionScope.js.map +1 -1
  33. package/dist/implementation/symbols.js +5 -0
  34. package/dist/implementation/symbols.js.map +1 -0
  35. package/dist/index.js +4 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/internal.js +5 -2
  38. package/dist/internal.js.map +1 -1
  39. package/dist/tests/coList.test.js +51 -48
  40. package/dist/tests/coList.test.js.map +1 -1
  41. package/dist/tests/coMap.test.js +131 -74
  42. package/dist/tests/coMap.test.js.map +1 -1
  43. package/dist/tests/coStream.test.js +56 -41
  44. package/dist/tests/coStream.test.js.map +1 -1
  45. package/dist/tests/deepLoading.test.js +188 -0
  46. package/dist/tests/deepLoading.test.js.map +1 -0
  47. package/dist/tests/groupsAndAccounts.test.js +83 -0
  48. package/dist/tests/groupsAndAccounts.test.js.map +1 -0
  49. package/package.json +17 -9
  50. package/src/coValues/account.ts +186 -128
  51. package/src/coValues/coList.ts +156 -107
  52. package/src/coValues/coMap.ts +272 -148
  53. package/src/coValues/coStream.ts +388 -87
  54. package/src/coValues/deepLoading.ts +229 -0
  55. package/src/coValues/extensions/imageDef.ts +17 -13
  56. package/src/coValues/group.ts +166 -59
  57. package/src/coValues/interfaces.ts +189 -160
  58. package/src/implementation/devtoolsFormatters.ts +110 -0
  59. package/src/implementation/inspect.ts +1 -1
  60. package/src/implementation/refs.ts +80 -28
  61. package/src/implementation/schema.ts +141 -0
  62. package/src/implementation/subscriptionScope.ts +48 -12
  63. package/src/implementation/symbols.ts +11 -0
  64. package/src/index.ts +19 -8
  65. package/src/internal.ts +7 -3
  66. package/src/tests/coList.test.ts +77 -62
  67. package/src/tests/coMap.test.ts +201 -114
  68. package/src/tests/coStream.test.ts +113 -84
  69. package/src/tests/deepLoading.test.ts +304 -0
  70. package/src/tests/groupsAndAccounts.test.ts +91 -0
  71. package/dist/implementation/encoding.js +0 -26
  72. package/dist/implementation/encoding.js.map +0 -1
  73. package/src/implementation/encoding.ts +0 -105
@@ -0,0 +1,304 @@
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(
184
+ this: CustomAccount,
185
+ creationProps?: { name: string } | undefined,
186
+ ) {
187
+ if (creationProps) {
188
+ this.profile = CustomProfile.create(
189
+ {
190
+ name: creationProps.name,
191
+ stream: TestStream.create([], { owner: this }),
192
+ },
193
+ { owner: this },
194
+ );
195
+ this.root = TestMap.create(
196
+ { list: TestList.create([], { owner: this }) },
197
+ { owner: this },
198
+ );
199
+ }
200
+
201
+ const thisLoaded = await this.ensureLoaded({
202
+ profile: { stream: [] },
203
+ root: { list: [] },
204
+ });
205
+ expectTypeOf(thisLoaded).toEqualTypeOf<
206
+ | (CustomAccount & {
207
+ profile: CustomProfile & {
208
+ stream: TestStream;
209
+ };
210
+ root: TestMap & {
211
+ list: TestList;
212
+ };
213
+ })
214
+ | undefined
215
+ >();
216
+ }
217
+ }
218
+
219
+ test("Deep loading within account", async () => {
220
+ const me = await CustomAccount.create({
221
+ creationProps: { name: "Hermes Puggington" },
222
+ crypto: Crypto,
223
+ });
224
+
225
+ const meLoaded = await me.ensureLoaded({
226
+ profile: { stream: [] },
227
+ root: { list: [] },
228
+ });
229
+ expectTypeOf(meLoaded).toEqualTypeOf<
230
+ | (CustomAccount & {
231
+ profile: CustomProfile & {
232
+ stream: TestStream;
233
+ };
234
+ root: TestMap & {
235
+ list: TestList;
236
+ };
237
+ })
238
+ | undefined
239
+ >();
240
+ if (meLoaded === undefined) {
241
+ throw new Error("meLoaded is undefined");
242
+ }
243
+ expect(meLoaded.profile.stream).not.toBe(null);
244
+ expect(meLoaded.root.list).not.toBe(null);
245
+ });
246
+
247
+ class RecordLike extends CoMap.Record(co.ref(TestMap)) {}
248
+
249
+ test("Deep loading a record-like coMap", async () => {
250
+ const me = await Account.create({
251
+ creationProps: { name: "Hermes Puggington" },
252
+ crypto: Crypto,
253
+ });
254
+
255
+ const [initialAsPeer, secondPeer] = connectedPeers("initial", "second", {
256
+ peer1role: "server",
257
+ peer2role: "client",
258
+ });
259
+ if (!isControlledAccount(me)) {
260
+ throw "me is not a controlled account";
261
+ }
262
+ me._raw.core.node.syncManager.addPeer(secondPeer);
263
+ const meOnSecondPeer = await Account.become({
264
+ accountID: me.id,
265
+ accountSecret: me._raw.agentSecret,
266
+ peersToLoadFrom: [initialAsPeer],
267
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
268
+ sessionID: newRandomSessionID(me.id as any),
269
+ crypto: Crypto,
270
+ });
271
+
272
+ const record = RecordLike.create(
273
+ {
274
+ key1: TestMap.create(
275
+ { list: TestList.create([], { owner: me }) },
276
+ { owner: me },
277
+ ),
278
+ key2: TestMap.create(
279
+ { list: TestList.create([], { owner: me }) },
280
+ { owner: me },
281
+ ),
282
+ },
283
+ { owner: me },
284
+ );
285
+
286
+ const recordLoaded = await RecordLike.load(record.id, meOnSecondPeer, [
287
+ { list: [{}] },
288
+ ]);
289
+ expectTypeOf(recordLoaded).toEqualTypeOf<
290
+ | (RecordLike & {
291
+ [key: string]: TestMap & {
292
+ list: TestList & InnerMap[];
293
+ };
294
+ })
295
+ | undefined
296
+ >();
297
+ if (recordLoaded === undefined) {
298
+ throw new Error("recordLoaded is undefined");
299
+ }
300
+ expect(recordLoaded.key1?.list).not.toBe(null);
301
+ expect(recordLoaded.key1?.list).not.toBe(undefined);
302
+ expect(recordLoaded.key2?.list).not.toBe(null);
303
+ expect(recordLoaded.key2?.list).not.toBe(undefined);
304
+ });
@@ -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(this: CustomAccount, 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
+ group.subscribe({}, (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
+ .castAs(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.castAs(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;