jazz-tools 0.13.30 → 0.14.0
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 +8 -8
- package/CHANGELOG.md +23 -3
- 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-2ASOGEYA.js} +3531 -3269
- package/dist/chunk-2ASOGEYA.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 +41 -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 +3 -2
- package/src/auth/DemoAuth.ts +1 -2
- package/src/auth/PassphraseAuth.ts +1 -1
- package/src/coValues/CoValueBase.ts +83 -0
- package/src/coValues/account.ts +53 -43
- package/src/coValues/coFeed.ts +65 -83
- package/src/coValues/coList.ts +28 -21
- package/src/coValues/coMap.ts +54 -38
- package/src/coValues/coPlainText.ts +4 -1
- package/src/coValues/deepLoading.ts +46 -36
- package/src/coValues/extensions/imageDef.ts +21 -19
- package/src/coValues/group.ts +37 -38
- package/src/coValues/inbox.ts +24 -11
- package/src/coValues/interfaces.ts +29 -93
- package/src/coValues/profile.ts +12 -13
- package/src/coValues/registeredSchemas.ts +1 -3
- package/src/coValues/schemaUnion.ts +6 -6
- package/src/exports.ts +47 -25
- package/src/implementation/activeAccountContext.ts +1 -1
- package/src/implementation/createContext.ts +39 -24
- package/src/implementation/invites.ts +15 -12
- package/src/implementation/refs.ts +6 -4
- package/src/implementation/schema.ts +22 -34
- package/src/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.ts +101 -0
- package/src/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.ts +191 -0
- package/src/implementation/zodSchema/schemaTypes/AccountSchema.ts +102 -0
- package/src/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +70 -0
- package/src/implementation/zodSchema/schemaTypes/CoListSchema.ts +59 -0
- package/src/implementation/zodSchema/schemaTypes/CoMapSchema.ts +126 -0
- package/src/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +98 -0
- package/src/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +9 -0
- package/src/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +27 -0
- package/src/implementation/zodSchema/schemaTypes/RichTextSchema.ts +25 -0
- package/src/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +61 -0
- package/src/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +77 -0
- package/src/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.ts +90 -0
- package/src/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.ts +103 -0
- package/src/implementation/zodSchema/unionUtils.ts +139 -0
- package/src/implementation/zodSchema/zodCo.ts +409 -0
- package/src/implementation/zodSchema/zodSchema.ts +116 -0
- package/src/internal.ts +38 -0
- package/src/subscribe/SubscriptionScope.ts +30 -3
- package/src/subscribe/utils.ts +7 -2
- package/src/testing.ts +14 -16
- package/src/tests/ContextManager.test.ts +73 -47
- package/src/tests/DemoAuth.test.ts +1 -1
- package/src/tests/account.test.ts +6 -9
- package/src/tests/coFeed.test.ts +102 -63
- package/src/tests/coList.test.ts +82 -95
- package/src/tests/coMap.record.test.ts +53 -87
- package/src/tests/coMap.test.ts +297 -312
- package/src/tests/coPlainText.test.ts +19 -39
- package/src/tests/createContext.test.ts +33 -15
- package/src/tests/deepLoading.test.ts +397 -131
- package/src/tests/groupsAndAccounts.test.ts +81 -72
- package/src/tests/imageDef.test.ts +22 -13
- package/src/tests/inbox.test.ts +36 -29
- package/src/tests/load.test.ts +10 -10
- package/src/tests/patterns/requestToJoin.test.ts +31 -31
- package/src/tests/schema.test.ts +37 -38
- package/src/tests/schemaUnion.test.ts +54 -64
- package/src/tests/subscribe.test.ts +118 -116
- package/src/tests/testing.test.ts +33 -33
- package/src/tests/utils.ts +3 -2
- package/src/types.ts +1 -8
- package/dist/chunk-LMV6J7GN.js.map +0 -1
package/src/tests/coMap.test.ts
CHANGED
@@ -9,13 +9,12 @@ import {
|
|
9
9
|
test,
|
10
10
|
vi,
|
11
11
|
} from "vitest";
|
12
|
-
import { Group,
|
13
|
-
import { Account
|
12
|
+
import { Group, co, subscribeToCoValue, z } from "../exports.js";
|
13
|
+
import { Account } from "../index.js";
|
14
|
+
import { CoKeys, Loaded, zodSchemaToCoSchema } from "../internal.js";
|
14
15
|
import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
|
15
16
|
import { setupTwoNodes, waitFor } from "./utils.js";
|
16
17
|
|
17
|
-
const { connectedPeers } = cojsonInternals;
|
18
|
-
|
19
18
|
const Crypto = await WasmCrypto.create();
|
20
19
|
|
21
20
|
beforeEach(async () => {
|
@@ -30,21 +29,17 @@ beforeEach(async () => {
|
|
30
29
|
describe("CoMap", async () => {
|
31
30
|
describe("init", () => {
|
32
31
|
test("create a CoMap with basic property access", () => {
|
33
|
-
|
34
|
-
color
|
35
|
-
_height
|
36
|
-
birthday
|
37
|
-
name
|
38
|
-
nullable
|
39
|
-
|
40
|
-
|
41
|
-
})
|
42
|
-
optionalDate
|
43
|
-
|
44
|
-
get roughColor() {
|
45
|
-
return this.color + "ish";
|
46
|
-
}
|
47
|
-
}
|
32
|
+
const Person = co.map({
|
33
|
+
color: z.string(),
|
34
|
+
_height: z.number(),
|
35
|
+
birthday: z.date(),
|
36
|
+
name: z.string(),
|
37
|
+
// nullable: z.optional.encoded<string | undefined>({
|
38
|
+
// encode: (value: string | undefined) => value || null,
|
39
|
+
// decode: (value: unknown) => (value as string) || undefined,
|
40
|
+
// })
|
41
|
+
optionalDate: z.date().optional(),
|
42
|
+
});
|
48
43
|
|
49
44
|
const birthday = new Date("1989-11-27");
|
50
45
|
|
@@ -56,7 +51,6 @@ describe("CoMap", async () => {
|
|
56
51
|
});
|
57
52
|
|
58
53
|
expect(john.color).toEqual("red");
|
59
|
-
expect(john.roughColor).toEqual("redish");
|
60
54
|
expect(john._height).toEqual(10);
|
61
55
|
expect(john.birthday).toEqual(birthday);
|
62
56
|
expect(john._raw.get("birthday")).toEqual(birthday.toISOString());
|
@@ -69,9 +63,9 @@ describe("CoMap", async () => {
|
|
69
63
|
});
|
70
64
|
|
71
65
|
test("property existence", () => {
|
72
|
-
|
73
|
-
name
|
74
|
-
}
|
66
|
+
const Person = co.map({
|
67
|
+
name: z.string(),
|
68
|
+
});
|
75
69
|
|
76
70
|
const john = Person.create({ name: "John" });
|
77
71
|
|
@@ -80,9 +74,9 @@ describe("CoMap", async () => {
|
|
80
74
|
});
|
81
75
|
|
82
76
|
test("create a CoMap with an account as owner", () => {
|
83
|
-
|
84
|
-
name
|
85
|
-
}
|
77
|
+
const Person = co.map({
|
78
|
+
name: z.string(),
|
79
|
+
});
|
86
80
|
|
87
81
|
const john = Person.create({ name: "John" }, Account.getMe());
|
88
82
|
|
@@ -91,9 +85,9 @@ describe("CoMap", async () => {
|
|
91
85
|
});
|
92
86
|
|
93
87
|
test("create a CoMap with a group as owner", () => {
|
94
|
-
|
95
|
-
name
|
96
|
-
}
|
88
|
+
const Person = co.map({
|
89
|
+
name: z.string(),
|
90
|
+
});
|
97
91
|
|
98
92
|
const john = Person.create({ name: "John" }, Group.create());
|
99
93
|
|
@@ -102,28 +96,24 @@ describe("CoMap", async () => {
|
|
102
96
|
});
|
103
97
|
|
104
98
|
test("Empty schema", () => {
|
105
|
-
const emptyMap =
|
99
|
+
const emptyMap = co.map({}).create({});
|
106
100
|
|
107
101
|
// @ts-expect-error
|
108
102
|
expect(emptyMap.color).toEqual(undefined);
|
109
103
|
});
|
110
104
|
|
111
105
|
test("setting date as undefined should throw", () => {
|
112
|
-
|
113
|
-
color
|
114
|
-
_height
|
115
|
-
birthday
|
116
|
-
name
|
117
|
-
nullable
|
118
|
-
|
119
|
-
|
120
|
-
});
|
121
|
-
optionalDate
|
122
|
-
|
123
|
-
get roughColor() {
|
124
|
-
return this.color + "ish";
|
125
|
-
}
|
126
|
-
}
|
106
|
+
const Person = co.map({
|
107
|
+
color: z.string(),
|
108
|
+
_height: z.number(),
|
109
|
+
birthday: z.date(),
|
110
|
+
name: z.string(),
|
111
|
+
// nullable: z.optional.encoded<string | undefined>({
|
112
|
+
// encode: (value: string | undefined) => value || null,
|
113
|
+
// decode: (value: unknown) => (value as string) || undefined,
|
114
|
+
// });
|
115
|
+
optionalDate: z.date().optional(),
|
116
|
+
});
|
127
117
|
|
128
118
|
expect(() =>
|
129
119
|
Person.create({
|
@@ -136,16 +126,16 @@ describe("CoMap", async () => {
|
|
136
126
|
});
|
137
127
|
|
138
128
|
test("CoMap with reference", () => {
|
139
|
-
|
140
|
-
name
|
141
|
-
breed
|
142
|
-
}
|
129
|
+
const Dog = co.map({
|
130
|
+
name: z.string(),
|
131
|
+
breed: z.string(),
|
132
|
+
});
|
143
133
|
|
144
|
-
|
145
|
-
name
|
146
|
-
age
|
147
|
-
dog
|
148
|
-
}
|
134
|
+
const Person = co.map({
|
135
|
+
name: z.string(),
|
136
|
+
age: z.number(),
|
137
|
+
dog: Dog,
|
138
|
+
});
|
149
139
|
|
150
140
|
const person = Person.create({
|
151
141
|
name: "John",
|
@@ -158,11 +148,14 @@ describe("CoMap", async () => {
|
|
158
148
|
});
|
159
149
|
|
160
150
|
test("CoMap with self reference", () => {
|
161
|
-
|
162
|
-
name
|
163
|
-
age
|
164
|
-
|
165
|
-
|
151
|
+
const Person = co.map({
|
152
|
+
name: z.string(),
|
153
|
+
age: z.number(),
|
154
|
+
// TODO: would be nice if this didn't need a type annotation
|
155
|
+
get friend(): z.ZodOptional<typeof Person> {
|
156
|
+
return z.optional(Person);
|
157
|
+
},
|
158
|
+
});
|
166
159
|
|
167
160
|
const person = Person.create({
|
168
161
|
name: "John",
|
@@ -175,10 +168,10 @@ describe("CoMap", async () => {
|
|
175
168
|
});
|
176
169
|
|
177
170
|
test("toJSON should not fail when there is a key in the raw value not represented in the schema", () => {
|
178
|
-
|
179
|
-
name
|
180
|
-
age
|
181
|
-
}
|
171
|
+
const Person = co.map({
|
172
|
+
name: z.string(),
|
173
|
+
age: z.number(),
|
174
|
+
});
|
182
175
|
|
183
176
|
const person = Person.create({ name: "John", age: 20 });
|
184
177
|
|
@@ -193,11 +186,13 @@ describe("CoMap", async () => {
|
|
193
186
|
});
|
194
187
|
|
195
188
|
test("toJSON should handle references", () => {
|
196
|
-
|
197
|
-
name
|
198
|
-
age
|
199
|
-
friend
|
200
|
-
|
189
|
+
const Person = co.map({
|
190
|
+
name: z.string(),
|
191
|
+
age: z.number(),
|
192
|
+
get friend(): z.ZodOptional<typeof Person> {
|
193
|
+
return z.optional(Person);
|
194
|
+
},
|
195
|
+
});
|
201
196
|
|
202
197
|
const person = Person.create({
|
203
198
|
name: "John",
|
@@ -220,11 +215,13 @@ describe("CoMap", async () => {
|
|
220
215
|
});
|
221
216
|
|
222
217
|
test("toJSON should handle circular references", () => {
|
223
|
-
|
224
|
-
name
|
225
|
-
age
|
226
|
-
friend
|
227
|
-
|
218
|
+
const Person = co.map({
|
219
|
+
name: z.string(),
|
220
|
+
age: z.number(),
|
221
|
+
get friend(): z.ZodOptional<typeof Person> {
|
222
|
+
return z.optional(Person);
|
223
|
+
},
|
224
|
+
});
|
228
225
|
|
229
226
|
const person = Person.create({
|
230
227
|
name: "John",
|
@@ -245,11 +242,11 @@ describe("CoMap", async () => {
|
|
245
242
|
});
|
246
243
|
|
247
244
|
test("testing toJSON on a CoMap with a Date field", () => {
|
248
|
-
|
249
|
-
name
|
250
|
-
age
|
251
|
-
birthday
|
252
|
-
}
|
245
|
+
const Person = co.map({
|
246
|
+
name: z.string(),
|
247
|
+
age: z.number(),
|
248
|
+
birthday: z.date(),
|
249
|
+
});
|
253
250
|
|
254
251
|
const birthday = new Date();
|
255
252
|
|
@@ -269,11 +266,11 @@ describe("CoMap", async () => {
|
|
269
266
|
});
|
270
267
|
|
271
268
|
test("setting optional date as undefined should not throw", () => {
|
272
|
-
|
273
|
-
name
|
274
|
-
age
|
275
|
-
birthday
|
276
|
-
}
|
269
|
+
const Person = co.map({
|
270
|
+
name: z.string(),
|
271
|
+
age: z.number(),
|
272
|
+
birthday: z.date().optional(),
|
273
|
+
});
|
277
274
|
|
278
275
|
const john = Person.create({
|
279
276
|
name: "John",
|
@@ -287,10 +284,10 @@ describe("CoMap", async () => {
|
|
287
284
|
});
|
288
285
|
|
289
286
|
it("should disallow extra properties", () => {
|
290
|
-
|
291
|
-
name
|
292
|
-
age
|
293
|
-
}
|
287
|
+
const Person = co.map({
|
288
|
+
name: z.string(),
|
289
|
+
age: z.number(),
|
290
|
+
});
|
294
291
|
|
295
292
|
// @ts-expect-error - x is not a valid property
|
296
293
|
const john = Person.create({ name: "John", age: 30, x: 1 });
|
@@ -306,10 +303,10 @@ describe("CoMap", async () => {
|
|
306
303
|
|
307
304
|
describe("Mutation", () => {
|
308
305
|
test("change a primitive value", () => {
|
309
|
-
|
310
|
-
name
|
311
|
-
age
|
312
|
-
}
|
306
|
+
const Person = co.map({
|
307
|
+
name: z.string(),
|
308
|
+
age: z.number(),
|
309
|
+
});
|
313
310
|
|
314
311
|
const john = Person.create({ name: "John", age: 20 });
|
315
312
|
|
@@ -320,10 +317,10 @@ describe("CoMap", async () => {
|
|
320
317
|
});
|
321
318
|
|
322
319
|
test("delete an optional value", () => {
|
323
|
-
|
324
|
-
name
|
325
|
-
age
|
326
|
-
}
|
320
|
+
const Person = co.map({
|
321
|
+
name: z.string(),
|
322
|
+
age: z.number().optional(),
|
323
|
+
});
|
327
324
|
|
328
325
|
const john = Person.create({ name: "John", age: 20 });
|
329
326
|
|
@@ -340,15 +337,15 @@ describe("CoMap", async () => {
|
|
340
337
|
});
|
341
338
|
|
342
339
|
test("update a reference", () => {
|
343
|
-
|
344
|
-
name
|
345
|
-
}
|
340
|
+
const Dog = co.map({
|
341
|
+
name: z.string(),
|
342
|
+
});
|
346
343
|
|
347
|
-
|
348
|
-
name
|
349
|
-
age
|
350
|
-
dog
|
351
|
-
}
|
344
|
+
const Person = co.map({
|
345
|
+
name: z.string(),
|
346
|
+
age: z.number(),
|
347
|
+
dog: Dog,
|
348
|
+
});
|
352
349
|
|
353
350
|
const john = Person.create({
|
354
351
|
name: "John",
|
@@ -362,10 +359,10 @@ describe("CoMap", async () => {
|
|
362
359
|
});
|
363
360
|
|
364
361
|
test("changes should be listed in _edits", () => {
|
365
|
-
|
366
|
-
name
|
367
|
-
age
|
368
|
-
}
|
362
|
+
const Person = co.map({
|
363
|
+
name: z.string(),
|
364
|
+
age: z.number(),
|
365
|
+
});
|
369
366
|
|
370
367
|
const john = Person.create({ name: "John", age: 20 });
|
371
368
|
|
@@ -373,42 +370,46 @@ describe("CoMap", async () => {
|
|
373
370
|
|
374
371
|
john.age = 21;
|
375
372
|
|
376
|
-
expect(john._edits.age
|
377
|
-
{
|
378
|
-
by: expect.objectContaining({ _type: "Account", id: me.id }),
|
373
|
+
expect(john._edits.age?.all).toEqual([
|
374
|
+
expect.objectContaining({
|
379
375
|
value: 20,
|
380
376
|
key: "age",
|
381
377
|
ref: undefined,
|
382
378
|
madeAt: expect.any(Date),
|
383
|
-
},
|
384
|
-
{
|
385
|
-
by: expect.objectContaining({ _type: "Account", id: me.id }),
|
379
|
+
}),
|
380
|
+
expect.objectContaining({
|
386
381
|
value: 21,
|
387
382
|
key: "age",
|
388
383
|
ref: undefined,
|
389
384
|
madeAt: expect.any(Date),
|
390
|
-
},
|
385
|
+
}),
|
391
386
|
]);
|
387
|
+
expect(john._edits.age?.all[0]?.by).toMatchObject({
|
388
|
+
_type: "Account",
|
389
|
+
id: me.id,
|
390
|
+
});
|
391
|
+
expect(john._edits.age?.all[1]?.by).toMatchObject({
|
392
|
+
_type: "Account",
|
393
|
+
id: me.id,
|
394
|
+
});
|
392
395
|
});
|
393
396
|
});
|
394
397
|
|
395
398
|
test("Enum of maps", () => {
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
value = co.string;
|
411
|
-
}
|
399
|
+
const ChildA = co.map({
|
400
|
+
type: z.literal("a"),
|
401
|
+
value: z.number(),
|
402
|
+
});
|
403
|
+
|
404
|
+
const ChildB = co.map({
|
405
|
+
type: z.literal("b"),
|
406
|
+
value: z.string(),
|
407
|
+
});
|
408
|
+
|
409
|
+
const MapWithEnumOfMaps = co.map({
|
410
|
+
name: z.string(),
|
411
|
+
child: z.discriminatedUnion([ChildA, ChildB]),
|
412
|
+
});
|
412
413
|
|
413
414
|
const mapWithEnum = MapWithEnumOfMaps.create({
|
414
415
|
name: "enum",
|
@@ -422,21 +423,26 @@ describe("CoMap", async () => {
|
|
422
423
|
expect(mapWithEnum.child?.type).toEqual("a");
|
423
424
|
expect(mapWithEnum.child?.value).toEqual(5);
|
424
425
|
expect(mapWithEnum.child?.id).toBeDefined();
|
426
|
+
|
427
|
+
// TODO: properly support narrowing once we get rid of the coField marker
|
428
|
+
// if (mapWithEnum.child?.type === "a") {
|
429
|
+
// expectTypeOf(mapWithEnum.child).toEqualTypeOf<Loaded<typeof ChildA>>();
|
430
|
+
// }
|
425
431
|
});
|
426
432
|
});
|
427
433
|
|
428
434
|
describe("CoMap resolution", async () => {
|
429
435
|
test("loading a locally available map with deep resolve", async () => {
|
430
|
-
|
431
|
-
name
|
432
|
-
breed
|
433
|
-
}
|
436
|
+
const Dog = co.map({
|
437
|
+
name: z.string(),
|
438
|
+
breed: z.string(),
|
439
|
+
});
|
434
440
|
|
435
|
-
|
436
|
-
name
|
437
|
-
age
|
438
|
-
dog
|
439
|
-
}
|
441
|
+
const Person = co.map({
|
442
|
+
name: z.string(),
|
443
|
+
age: z.number(),
|
444
|
+
dog: Dog,
|
445
|
+
});
|
440
446
|
|
441
447
|
const person = Person.create({
|
442
448
|
name: "John",
|
@@ -455,16 +461,16 @@ describe("CoMap resolution", async () => {
|
|
455
461
|
});
|
456
462
|
|
457
463
|
test("loading a locally available map using autoload for the refs", async () => {
|
458
|
-
|
459
|
-
name
|
460
|
-
breed
|
461
|
-
}
|
464
|
+
const Dog = co.map({
|
465
|
+
name: z.string(),
|
466
|
+
breed: z.string(),
|
467
|
+
});
|
462
468
|
|
463
|
-
|
464
|
-
name
|
465
|
-
age
|
466
|
-
dog
|
467
|
-
}
|
469
|
+
const Person = co.map({
|
470
|
+
name: z.string(),
|
471
|
+
age: z.number(),
|
472
|
+
dog: Dog,
|
473
|
+
});
|
468
474
|
|
469
475
|
const person = Person.create({
|
470
476
|
name: "John",
|
@@ -479,16 +485,16 @@ describe("CoMap resolution", async () => {
|
|
479
485
|
});
|
480
486
|
|
481
487
|
test("loading a remotely available map with deep resolve", async () => {
|
482
|
-
|
483
|
-
name
|
484
|
-
breed
|
485
|
-
}
|
488
|
+
const Dog = co.map({
|
489
|
+
name: z.string(),
|
490
|
+
breed: z.string(),
|
491
|
+
});
|
486
492
|
|
487
|
-
|
488
|
-
name
|
489
|
-
age
|
490
|
-
dog
|
491
|
-
}
|
493
|
+
const Person = co.map({
|
494
|
+
name: z.string(),
|
495
|
+
age: z.number(),
|
496
|
+
dog: Dog,
|
497
|
+
});
|
492
498
|
|
493
499
|
const group = Group.create();
|
494
500
|
group.addMember("everyone", "writer");
|
@@ -516,16 +522,16 @@ describe("CoMap resolution", async () => {
|
|
516
522
|
});
|
517
523
|
|
518
524
|
test("loading a remotely available map using autoload for the refs", async () => {
|
519
|
-
|
520
|
-
name
|
521
|
-
breed
|
522
|
-
}
|
525
|
+
const Dog = co.map({
|
526
|
+
name: z.string(),
|
527
|
+
breed: z.string(),
|
528
|
+
});
|
523
529
|
|
524
|
-
|
525
|
-
name
|
526
|
-
age
|
527
|
-
dog
|
528
|
-
}
|
530
|
+
const Person = co.map({
|
531
|
+
name: z.string(),
|
532
|
+
age: z.number(),
|
533
|
+
dog: Dog,
|
534
|
+
});
|
529
535
|
|
530
536
|
const group = Group.create();
|
531
537
|
group.addMember("everyone", "writer");
|
@@ -553,16 +559,16 @@ describe("CoMap resolution", async () => {
|
|
553
559
|
});
|
554
560
|
|
555
561
|
test("accessing the value refs", async () => {
|
556
|
-
|
557
|
-
name
|
558
|
-
breed
|
559
|
-
}
|
562
|
+
const Dog = co.map({
|
563
|
+
name: z.string(),
|
564
|
+
breed: z.string(),
|
565
|
+
});
|
560
566
|
|
561
|
-
|
562
|
-
name
|
563
|
-
age
|
564
|
-
dog
|
565
|
-
}
|
567
|
+
const Person = co.map({
|
568
|
+
name: z.string(),
|
569
|
+
age: z.number(),
|
570
|
+
dog: Dog,
|
571
|
+
});
|
566
572
|
|
567
573
|
const group = Group.create();
|
568
574
|
group.addMember("everyone", "writer");
|
@@ -583,9 +589,9 @@ describe("CoMap resolution", async () => {
|
|
583
589
|
|
584
590
|
assert(loadedPerson);
|
585
591
|
|
586
|
-
expect(loadedPerson._refs.dog
|
592
|
+
expect(loadedPerson._refs.dog?.id).toBe(person.dog!.id);
|
587
593
|
|
588
|
-
const dog = await loadedPerson._refs.dog
|
594
|
+
const dog = await loadedPerson._refs.dog?.load();
|
589
595
|
|
590
596
|
assert(dog);
|
591
597
|
|
@@ -593,16 +599,16 @@ describe("CoMap resolution", async () => {
|
|
593
599
|
});
|
594
600
|
|
595
601
|
test("subscription on a locally available map with deep resolve", async () => {
|
596
|
-
|
597
|
-
name
|
598
|
-
breed
|
599
|
-
}
|
602
|
+
const Dog = co.map({
|
603
|
+
name: z.string(),
|
604
|
+
breed: z.string(),
|
605
|
+
});
|
600
606
|
|
601
|
-
|
602
|
-
name
|
603
|
-
age
|
604
|
-
dog
|
605
|
-
}
|
607
|
+
const Person = co.map({
|
608
|
+
name: z.string(),
|
609
|
+
age: z.number(),
|
610
|
+
dog: Dog,
|
611
|
+
});
|
606
612
|
|
607
613
|
const person = Person.create({
|
608
614
|
name: "John",
|
@@ -610,7 +616,7 @@ describe("CoMap resolution", async () => {
|
|
610
616
|
dog: Dog.create({ name: "Rex", breed: "Labrador" }),
|
611
617
|
});
|
612
618
|
|
613
|
-
const updates:
|
619
|
+
const updates: Loaded<typeof Person, { dog: true }>[] = [];
|
614
620
|
const spy = vi.fn((person) => updates.push(person));
|
615
621
|
|
616
622
|
Person.subscribe(
|
@@ -641,16 +647,16 @@ describe("CoMap resolution", async () => {
|
|
641
647
|
});
|
642
648
|
|
643
649
|
test("subscription on a locally available map with autoload", async () => {
|
644
|
-
|
645
|
-
name
|
646
|
-
breed
|
647
|
-
}
|
650
|
+
const Dog = co.map({
|
651
|
+
name: z.string(),
|
652
|
+
breed: z.string(),
|
653
|
+
});
|
648
654
|
|
649
|
-
|
650
|
-
name
|
651
|
-
age
|
652
|
-
dog
|
653
|
-
}
|
655
|
+
const Person = co.map({
|
656
|
+
name: z.string(),
|
657
|
+
age: z.number(),
|
658
|
+
dog: Dog,
|
659
|
+
});
|
654
660
|
|
655
661
|
const person = Person.create({
|
656
662
|
name: "John",
|
@@ -658,7 +664,7 @@ describe("CoMap resolution", async () => {
|
|
658
664
|
dog: Dog.create({ name: "Rex", breed: "Labrador" }),
|
659
665
|
});
|
660
666
|
|
661
|
-
const updates: Person[] = [];
|
667
|
+
const updates: Loaded<typeof Person>[] = [];
|
662
668
|
const spy = vi.fn((person) => updates.push(person));
|
663
669
|
|
664
670
|
Person.subscribe(person.id, {}, spy);
|
@@ -681,16 +687,16 @@ describe("CoMap resolution", async () => {
|
|
681
687
|
});
|
682
688
|
|
683
689
|
test("subscription on a locally available map with syncResolution", async () => {
|
684
|
-
|
685
|
-
name
|
686
|
-
breed
|
687
|
-
}
|
690
|
+
const Dog = co.map({
|
691
|
+
name: z.string(),
|
692
|
+
breed: z.string(),
|
693
|
+
});
|
688
694
|
|
689
|
-
|
690
|
-
name
|
691
|
-
age
|
692
|
-
dog
|
693
|
-
}
|
695
|
+
const Person = co.map({
|
696
|
+
name: z.string(),
|
697
|
+
age: z.number(),
|
698
|
+
dog: Dog,
|
699
|
+
});
|
694
700
|
|
695
701
|
const person = Person.create({
|
696
702
|
name: "John",
|
@@ -698,11 +704,11 @@ describe("CoMap resolution", async () => {
|
|
698
704
|
dog: Dog.create({ name: "Rex", breed: "Labrador" }),
|
699
705
|
});
|
700
706
|
|
701
|
-
const updates: Person[] = [];
|
707
|
+
const updates: Loaded<typeof Person>[] = [];
|
702
708
|
const spy = vi.fn((person) => updates.push(person));
|
703
709
|
|
704
710
|
subscribeToCoValue(
|
705
|
-
Person,
|
711
|
+
zodSchemaToCoSchema(Person), // TODO: we should get rid of the conversion in the future
|
706
712
|
person.id,
|
707
713
|
{
|
708
714
|
syncResolution: true,
|
@@ -728,16 +734,16 @@ describe("CoMap resolution", async () => {
|
|
728
734
|
});
|
729
735
|
|
730
736
|
test("subscription on a remotely available map with deep resolve", async () => {
|
731
|
-
|
732
|
-
name
|
733
|
-
breed
|
734
|
-
}
|
737
|
+
const Dog = co.map({
|
738
|
+
name: z.string(),
|
739
|
+
breed: z.string(),
|
740
|
+
});
|
735
741
|
|
736
|
-
|
737
|
-
name
|
738
|
-
age
|
739
|
-
dog
|
740
|
-
}
|
742
|
+
const Person = co.map({
|
743
|
+
name: z.string(),
|
744
|
+
age: z.number(),
|
745
|
+
dog: Dog,
|
746
|
+
});
|
741
747
|
|
742
748
|
const group = Group.create();
|
743
749
|
group.addMember("everyone", "writer");
|
@@ -753,7 +759,7 @@ describe("CoMap resolution", async () => {
|
|
753
759
|
|
754
760
|
const userB = await createJazzTestAccount();
|
755
761
|
|
756
|
-
const updates:
|
762
|
+
const updates: Loaded<typeof Person, { dog: true }>[] = [];
|
757
763
|
const spy = vi.fn((person) => updates.push(person));
|
758
764
|
|
759
765
|
Person.subscribe(
|
@@ -785,16 +791,16 @@ describe("CoMap resolution", async () => {
|
|
785
791
|
});
|
786
792
|
|
787
793
|
test("subscription on a remotely available map with autoload", async () => {
|
788
|
-
|
789
|
-
name
|
790
|
-
breed
|
791
|
-
}
|
794
|
+
const Dog = co.map({
|
795
|
+
name: z.string(),
|
796
|
+
breed: z.string(),
|
797
|
+
});
|
792
798
|
|
793
|
-
|
794
|
-
name
|
795
|
-
age
|
796
|
-
dog
|
797
|
-
}
|
799
|
+
const Person = co.map({
|
800
|
+
name: z.string(),
|
801
|
+
age: z.number(),
|
802
|
+
dog: Dog,
|
803
|
+
});
|
798
804
|
|
799
805
|
const group = Group.create();
|
800
806
|
group.addMember("everyone", "writer");
|
@@ -808,7 +814,7 @@ describe("CoMap resolution", async () => {
|
|
808
814
|
group,
|
809
815
|
);
|
810
816
|
|
811
|
-
const updates: Person[] = [];
|
817
|
+
const updates: Loaded<typeof Person>[] = [];
|
812
818
|
const spy = vi.fn((person) => updates.push(person));
|
813
819
|
|
814
820
|
const userB = await createJazzTestAccount();
|
@@ -839,16 +845,16 @@ describe("CoMap resolution", async () => {
|
|
839
845
|
});
|
840
846
|
|
841
847
|
test("replacing nested object triggers updates", async () => {
|
842
|
-
|
843
|
-
name
|
844
|
-
breed
|
845
|
-
}
|
848
|
+
const Dog = co.map({
|
849
|
+
name: z.string(),
|
850
|
+
breed: z.string(),
|
851
|
+
});
|
846
852
|
|
847
|
-
|
848
|
-
name
|
849
|
-
age
|
850
|
-
dog
|
851
|
-
}
|
853
|
+
const Person = co.map({
|
854
|
+
name: z.string(),
|
855
|
+
age: z.number(),
|
856
|
+
dog: Dog,
|
857
|
+
});
|
852
858
|
|
853
859
|
const person = Person.create({
|
854
860
|
name: "John",
|
@@ -856,7 +862,7 @@ describe("CoMap resolution", async () => {
|
|
856
862
|
dog: Dog.create({ name: "Rex", breed: "Labrador" }),
|
857
863
|
});
|
858
864
|
|
859
|
-
const updates:
|
865
|
+
const updates: Loaded<typeof Person, { dog: true }>[] = [];
|
860
866
|
const spy = vi.fn((person) => updates.push(person));
|
861
867
|
|
862
868
|
Person.subscribe(
|
@@ -893,19 +899,19 @@ describe("CoMap applyDiff", async () => {
|
|
893
899
|
crypto: Crypto,
|
894
900
|
});
|
895
901
|
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
isActive = co.boolean;
|
900
|
-
birthday = co.encoded(Encoders.Date);
|
901
|
-
nested = co.ref(NestedMap);
|
902
|
-
optionalField = co.optional.string;
|
903
|
-
optionalNested = co.optional.ref(NestedMap);
|
904
|
-
}
|
902
|
+
const NestedMap = co.map({
|
903
|
+
value: z.string(),
|
904
|
+
});
|
905
905
|
|
906
|
-
|
907
|
-
|
908
|
-
|
906
|
+
const TestMap = co.map({
|
907
|
+
name: z.string(),
|
908
|
+
age: z.number(),
|
909
|
+
isActive: z.boolean(),
|
910
|
+
birthday: z.date(),
|
911
|
+
nested: NestedMap,
|
912
|
+
optionalField: z.string().optional(),
|
913
|
+
optionalNested: z.optional(NestedMap),
|
914
|
+
});
|
909
915
|
|
910
916
|
test("Basic applyDiff", () => {
|
911
917
|
const map = TestMap.create(
|
@@ -1047,7 +1053,7 @@ describe("CoMap applyDiff", async () => {
|
|
1047
1053
|
expect((map as any).invalidField).toBeUndefined();
|
1048
1054
|
});
|
1049
1055
|
|
1050
|
-
test("applyDiff with optional reference set to
|
1056
|
+
test("applyDiff with optional reference set to undefined", () => {
|
1051
1057
|
const map = TestMap.create(
|
1052
1058
|
{
|
1053
1059
|
name: "Jack",
|
@@ -1061,15 +1067,15 @@ describe("CoMap applyDiff", async () => {
|
|
1061
1067
|
);
|
1062
1068
|
|
1063
1069
|
const newValues = {
|
1064
|
-
optionalNested:
|
1070
|
+
optionalNested: undefined,
|
1065
1071
|
};
|
1066
1072
|
|
1067
1073
|
map.applyDiff(newValues);
|
1068
1074
|
|
1069
|
-
expect(map.optionalNested).
|
1075
|
+
expect(map.optionalNested).toBeUndefined();
|
1070
1076
|
});
|
1071
1077
|
|
1072
|
-
test("applyDiff with required reference set to
|
1078
|
+
test("applyDiff with required reference set to undefined should throw", () => {
|
1073
1079
|
const map = TestMap.create(
|
1074
1080
|
{
|
1075
1081
|
name: "Kate",
|
@@ -1082,12 +1088,11 @@ describe("CoMap applyDiff", async () => {
|
|
1082
1088
|
);
|
1083
1089
|
|
1084
1090
|
const newValues = {
|
1085
|
-
nested:
|
1091
|
+
nested: undefined,
|
1086
1092
|
};
|
1087
1093
|
|
1088
|
-
// @ts-expect-error testing invalid usage
|
1089
1094
|
expect(() => map.applyDiff(newValues)).toThrowError(
|
1090
|
-
"Cannot set required reference nested to
|
1095
|
+
"Cannot set required reference nested to undefined",
|
1091
1096
|
);
|
1092
1097
|
});
|
1093
1098
|
});
|
@@ -1099,16 +1104,16 @@ describe("CoMap Typescript validation", async () => {
|
|
1099
1104
|
});
|
1100
1105
|
|
1101
1106
|
test("Is not ok to pass null into a required ref", () => {
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
}
|
1107
|
+
const NestedMap = co.map({
|
1108
|
+
value: z.string(),
|
1109
|
+
});
|
1106
1110
|
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1111
|
+
const TestMap = co.map({
|
1112
|
+
required: NestedMap,
|
1113
|
+
optional: NestedMap.optional(),
|
1114
|
+
});
|
1110
1115
|
|
1111
|
-
expectTypeOf<typeof TestMap.create
|
1116
|
+
expectTypeOf<typeof TestMap.create>().toBeCallableWith(
|
1112
1117
|
{
|
1113
1118
|
optional: NestedMap.create({ value: "" }, { owner: me }),
|
1114
1119
|
// @ts-expect-error null can't be passed to a non-optional field
|
@@ -1119,16 +1124,16 @@ describe("CoMap Typescript validation", async () => {
|
|
1119
1124
|
});
|
1120
1125
|
|
1121
1126
|
test("Is not ok if a required ref is omitted", () => {
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
}
|
1127
|
+
const NestedMap = co.map({
|
1128
|
+
value: z.string(),
|
1129
|
+
});
|
1126
1130
|
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1131
|
+
const TestMap = co.map({
|
1132
|
+
required: NestedMap,
|
1133
|
+
optional: NestedMap.optional(),
|
1134
|
+
});
|
1130
1135
|
|
1131
|
-
expectTypeOf<typeof TestMap.create
|
1136
|
+
expectTypeOf<typeof TestMap.create>().toBeCallableWith(
|
1132
1137
|
// @ts-expect-error non-optional fields can't be omitted
|
1133
1138
|
{},
|
1134
1139
|
{ owner: me },
|
@@ -1136,55 +1141,35 @@ describe("CoMap Typescript validation", async () => {
|
|
1136
1141
|
});
|
1137
1142
|
|
1138
1143
|
test("Is ok to omit optional fields", () => {
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
}
|
1143
|
-
|
1144
|
-
class NestedMap extends CoMap {
|
1145
|
-
value = co.string;
|
1146
|
-
}
|
1144
|
+
const NestedMap = co.map({
|
1145
|
+
value: z.string(),
|
1146
|
+
});
|
1147
1147
|
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
{ owner: me },
|
1153
|
-
);
|
1148
|
+
const TestMap = co.map({
|
1149
|
+
required: NestedMap,
|
1150
|
+
optional: NestedMap.optional(),
|
1151
|
+
});
|
1154
1152
|
|
1155
|
-
expectTypeOf<typeof TestMap.create
|
1153
|
+
expectTypeOf<typeof TestMap.create>().toBeCallableWith(
|
1156
1154
|
{
|
1157
1155
|
required: NestedMap.create({ value: "" }, { owner: me }),
|
1158
|
-
optional: null,
|
1159
1156
|
},
|
1160
1157
|
{ owner: me },
|
1161
1158
|
);
|
1162
|
-
});
|
1163
|
-
|
1164
|
-
test("the required refs should be nullable", () => {
|
1165
|
-
class TestMap extends CoMap {
|
1166
|
-
required = co.ref(NestedMap);
|
1167
|
-
optional = co.ref(NestedMap, { optional: true });
|
1168
|
-
}
|
1169
|
-
|
1170
|
-
class NestedMap extends CoMap {
|
1171
|
-
value = co.string;
|
1172
|
-
}
|
1173
1159
|
|
1174
|
-
|
1160
|
+
expectTypeOf<typeof TestMap.create>().toBeCallableWith(
|
1175
1161
|
{
|
1176
1162
|
required: NestedMap.create({ value: "" }, { owner: me }),
|
1163
|
+
optional: undefined, // TODO: should we allow null here? zod is stricter about this than we were before
|
1177
1164
|
},
|
1178
1165
|
{ owner: me },
|
1179
1166
|
);
|
1180
|
-
|
1181
|
-
expectTypeOf(map.required).toBeNullable();
|
1182
1167
|
});
|
1183
1168
|
|
1184
1169
|
test("waitForSync should resolve when the value is uploaded", async () => {
|
1185
|
-
|
1186
|
-
name
|
1187
|
-
}
|
1170
|
+
const TestMap = co.map({
|
1171
|
+
name: z.string(),
|
1172
|
+
});
|
1188
1173
|
|
1189
1174
|
const { clientNode, serverNode, clientAccount } = await setupTwoNodes();
|
1190
1175
|
|
@@ -1210,12 +1195,12 @@ describe("Creating and finding unique CoMaps", async () => {
|
|
1210
1195
|
test("Creating and finding unique CoMaps", async () => {
|
1211
1196
|
const group = Group.create();
|
1212
1197
|
|
1213
|
-
|
1214
|
-
name
|
1215
|
-
_height
|
1216
|
-
birthday
|
1217
|
-
color
|
1218
|
-
}
|
1198
|
+
const Person = co.map({
|
1199
|
+
name: z.string(),
|
1200
|
+
_height: z.number(),
|
1201
|
+
birthday: z.date(),
|
1202
|
+
color: z.string(),
|
1203
|
+
});
|
1219
1204
|
|
1220
1205
|
const alice = Person.create(
|
1221
1206
|
{
|