jazz-tools 0.7.25 → 0.7.26
Sign up to get free protection for your applications and to get access to all the features.
- package/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-test.log +39 -37
- package/CHANGELOG.md +8 -0
- package/dist/coValues/account.js +1 -5
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +11 -7
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +6 -6
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +3 -4
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/interfaces.js +6 -1
- package/dist/coValues/interfaces.js.map +1 -1
- package/dist/implementation/schema.js +4 -2
- package/dist/implementation/schema.js.map +1 -1
- package/dist/tests/coList.test.js +37 -40
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/coMap.test.js +47 -48
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coStream.test.js +97 -107
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/deepLoading.test.js +6 -7
- package/dist/tests/deepLoading.test.js.map +1 -1
- package/package.json +2 -4
- package/src/coValues/account.ts +4 -10
- package/src/coValues/coList.ts +13 -8
- package/src/coValues/coMap.ts +13 -11
- package/src/coValues/coStream.ts +3 -4
- package/src/coValues/interfaces.ts +6 -1
- package/src/implementation/schema.ts +14 -23
- package/src/tests/coList.test.ts +58 -65
- package/src/tests/coMap.test.ts +25 -28
- package/src/tests/coStream.test.ts +151 -169
- package/src/tests/deepLoading.test.ts +13 -15
package/src/coValues/coStream.ts
CHANGED
@@ -35,7 +35,6 @@ import {
|
|
35
35
|
ensureCoValueLoaded,
|
36
36
|
subscribeToExistingCoValue,
|
37
37
|
} from "../internal.js";
|
38
|
-
import { encodeSync, decodeSync } from "@effect/schema/Schema";
|
39
38
|
|
40
39
|
export type CoStreamEntry<Item> = SingleCoStreamEntry<Item> & {
|
41
40
|
all: IterableIterator<SingleCoStreamEntry<Item>>;
|
@@ -141,7 +140,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
141
140
|
if (itemDescriptor === "json") {
|
142
141
|
this._raw.push(item as JsonValue);
|
143
142
|
} else if ("encoded" in itemDescriptor) {
|
144
|
-
this._raw.push(
|
143
|
+
this._raw.push(itemDescriptor.encoded.encode(item));
|
145
144
|
} else if (isRefEncoded(itemDescriptor)) {
|
146
145
|
this._raw.push((item as unknown as CoValue).id);
|
147
146
|
}
|
@@ -153,7 +152,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
153
152
|
itemDescriptor === "json"
|
154
153
|
? (v: unknown) => v
|
155
154
|
: "encoded" in itemDescriptor
|
156
|
-
?
|
155
|
+
? itemDescriptor.encoded.encode
|
157
156
|
: (v: unknown) => v && (v as CoValue).id;
|
158
157
|
|
159
158
|
return {
|
@@ -247,7 +246,7 @@ function entryFromRawEntry<Item>(
|
|
247
246
|
? (CoValue & Item) | null
|
248
247
|
: Item;
|
249
248
|
} else if ("encoded" in itemField) {
|
250
|
-
return
|
249
|
+
return itemField.encoded.decode(rawEntry.value);
|
251
250
|
} else if (isRefEncoded(itemField)) {
|
252
251
|
return this.ref?.accessFrom(
|
253
252
|
accessFrom,
|
@@ -122,7 +122,12 @@ export class CoValueBase implements CoValue {
|
|
122
122
|
castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
|
123
123
|
cl: Cl,
|
124
124
|
): InstanceType<Cl> {
|
125
|
-
|
125
|
+
const casted = cl.fromRaw(this._raw) as InstanceType<Cl>;
|
126
|
+
const subscriptionScope = subscriptionsScopes.get(this);
|
127
|
+
if (subscriptionScope) {
|
128
|
+
subscriptionsScopes.set(casted, subscriptionScope);
|
129
|
+
}
|
130
|
+
return casted;
|
126
131
|
}
|
127
132
|
}
|
128
133
|
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
isCoValueClass,
|
6
6
|
CoValueFromRaw,
|
7
7
|
} from "../internal.js";
|
8
|
-
import type { Schema as EffectSchema, TypeId } from "@effect/schema/Schema";
|
9
8
|
|
10
9
|
export type CoMarker = { readonly __co: unique symbol };
|
11
10
|
/** @category Schema definition */
|
@@ -113,7 +112,7 @@ function ref<
|
|
113
112
|
}
|
114
113
|
|
115
114
|
export type JsonEncoded = "json";
|
116
|
-
export type EncodedAs<V> = { encoded: Encoder<V> };
|
115
|
+
export type EncodedAs<V> = { encoded: Encoder<V> | OptionalEncoder<V> };
|
117
116
|
export type RefEncoded<V extends CoValue> = {
|
118
117
|
ref: CoValueClass<V> | ((raw: RawCoValue) => CoValueClass<V>);
|
119
118
|
optional: boolean;
|
@@ -152,31 +151,23 @@ export type SchemaFor<Field> = NonNullable<Field> extends CoValue
|
|
152
151
|
? JsonEncoded
|
153
152
|
: EncodedAs<NonNullable<Field>>;
|
154
153
|
|
155
|
-
export type
|
156
|
-
|
157
|
-
|
158
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
159
|
-
any,
|
160
|
-
never
|
161
|
-
> & {
|
162
|
-
[TypeId]: {
|
163
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
164
|
-
_A: (_: any) => A;
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
166
|
-
_I: (_: any) => I;
|
167
|
-
};
|
154
|
+
export type Encoder<V> = {
|
155
|
+
encode: (value: V) => JsonValue;
|
156
|
+
decode: (value: JsonValue) => V;
|
168
157
|
};
|
158
|
+
export type OptionalEncoder<V> =
|
159
|
+
| Encoder<V>
|
160
|
+
| {
|
161
|
+
encode: (value: V | undefined) => JsonValue;
|
162
|
+
decode: (value: JsonValue) => V | undefined;
|
163
|
+
};
|
169
164
|
|
170
|
-
export type Encoder<V> = EffectSchemaWithInputAndOutput<V, JsonValue>;
|
171
|
-
export type OptionalEncoder<V> = EffectSchemaWithInputAndOutput<
|
172
|
-
V,
|
173
|
-
JsonValue | undefined
|
174
|
-
>;
|
175
|
-
|
176
|
-
import { Date } from "@effect/schema/Schema";
|
177
165
|
import { SchemaInit, ItemsSym, MembersSym } from "./symbols.js";
|
178
166
|
|
179
167
|
/** @category Schema definition */
|
180
168
|
export const Encoders = {
|
181
|
-
Date
|
169
|
+
Date: {
|
170
|
+
encode: (value: Date) => value.toISOString(),
|
171
|
+
decode: (value: JsonValue) => new Date(value as string),
|
172
|
+
},
|
182
173
|
};
|
package/src/tests/coList.test.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
import { expect, describe, test } from "vitest";
|
2
2
|
import { connectedPeers } from "cojson/src/streamUtils.js";
|
3
3
|
import { newRandomSessionID } from "cojson/src/coValueCore.js";
|
4
|
-
import { Effect, Queue } from "effect";
|
5
4
|
import {
|
6
5
|
Account,
|
7
6
|
CoList,
|
8
7
|
WasmCrypto,
|
9
8
|
co,
|
9
|
+
cojsonInternals,
|
10
10
|
isControlledAccount,
|
11
11
|
} from "../index.js";
|
12
12
|
|
@@ -157,11 +157,13 @@ describe("CoList resolution", async () => {
|
|
157
157
|
test("Loading and availability", async () => {
|
158
158
|
const { me, list } = await initNodeAndList();
|
159
159
|
|
160
|
-
const [initialAsPeer, secondPeer] =
|
161
|
-
|
160
|
+
const [initialAsPeer, secondPeer] = connectedPeers(
|
161
|
+
"initial",
|
162
|
+
"second",
|
163
|
+
{
|
162
164
|
peer1role: "server",
|
163
165
|
peer2role: "client",
|
164
|
-
}
|
166
|
+
},
|
165
167
|
);
|
166
168
|
if (!isControlledAccount(me)) {
|
167
169
|
throw "me is not a controlled account";
|
@@ -217,11 +219,13 @@ describe("CoList resolution", async () => {
|
|
217
219
|
test("Subscription & auto-resolution", async () => {
|
218
220
|
const { me, list } = await initNodeAndList();
|
219
221
|
|
220
|
-
const [initialAsPeer, secondPeer] =
|
221
|
-
|
222
|
+
const [initialAsPeer, secondPeer] = connectedPeers(
|
223
|
+
"initial",
|
224
|
+
"second",
|
225
|
+
{
|
222
226
|
peer1role: "server",
|
223
227
|
peer2role: "client",
|
224
|
-
}
|
228
|
+
},
|
225
229
|
);
|
226
230
|
if (!isControlledAccount(me)) {
|
227
231
|
throw "me is not a controlled account";
|
@@ -236,63 +240,52 @@ describe("CoList resolution", async () => {
|
|
236
240
|
crypto: Crypto,
|
237
241
|
});
|
238
242
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
const update5 = yield* $(Queue.take(queue));
|
288
|
-
expect(update5?.[0]?.[0]?.[0]).toBe("y");
|
289
|
-
expect(update5?.[0]?.[0]?.joined()).toBe("y,z");
|
290
|
-
|
291
|
-
// we get updates when the new nested value changes
|
292
|
-
newTwiceNestedList[0] = "w";
|
293
|
-
const update6 = yield* $(Queue.take(queue));
|
294
|
-
expect(update6?.[0]?.[0]?.[0]).toBe("w");
|
295
|
-
}),
|
296
|
-
);
|
243
|
+
const queue = new cojsonInternals.Channel();
|
244
|
+
|
245
|
+
TestList.subscribe(list.id, meOnSecondPeer, [], (subscribedList) => {
|
246
|
+
console.log(
|
247
|
+
"subscribedList?.[0]?.[0]?.[0]",
|
248
|
+
subscribedList?.[0]?.[0]?.[0],
|
249
|
+
);
|
250
|
+
void queue.push(subscribedList);
|
251
|
+
});
|
252
|
+
|
253
|
+
const update1 = (await queue.next()).value;
|
254
|
+
expect(update1?.[0]).toBe(null);
|
255
|
+
|
256
|
+
const update2 = (await queue.next()).value;
|
257
|
+
expect(update2?.[0]).toBeDefined();
|
258
|
+
expect(update2?.[0]?.[0]).toBe(null);
|
259
|
+
|
260
|
+
const update3 = (await queue.next()).value;
|
261
|
+
expect(update3?.[0]?.[0]).toBeDefined();
|
262
|
+
expect(update3?.[0]?.[0]?.[0]).toBe("a");
|
263
|
+
expect(update3?.[0]?.[0]?.joined()).toBe("a,b");
|
264
|
+
|
265
|
+
update3[0]![0]![0] = "x";
|
266
|
+
|
267
|
+
const update4 = (await queue.next()).value;
|
268
|
+
expect(update4?.[0]?.[0]?.[0]).toBe("x");
|
269
|
+
|
270
|
+
// When assigning a new nested value, we get an update
|
271
|
+
|
272
|
+
const newTwiceNestedList = TwiceNestedList.create(["y", "z"], {
|
273
|
+
owner: meOnSecondPeer,
|
274
|
+
});
|
275
|
+
|
276
|
+
const newNestedList = NestedList.create([newTwiceNestedList], {
|
277
|
+
owner: meOnSecondPeer,
|
278
|
+
});
|
279
|
+
|
280
|
+
update4[0] = newNestedList;
|
281
|
+
|
282
|
+
const update5 = (await queue.next()).value;
|
283
|
+
expect(update5?.[0]?.[0]?.[0]).toBe("y");
|
284
|
+
expect(update5?.[0]?.[0]?.joined()).toBe("y,z");
|
285
|
+
|
286
|
+
// we get updates when the new nested value changes
|
287
|
+
newTwiceNestedList[0] = "w";
|
288
|
+
const update6 = (await queue.next()).value;
|
289
|
+
expect(update6?.[0]?.[0]?.[0]).toBe("w");
|
297
290
|
});
|
298
291
|
});
|
package/src/tests/coMap.test.ts
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import { expect, describe, test } from "vitest";
|
2
2
|
import { connectedPeers } from "cojson/src/streamUtils.js";
|
3
3
|
import { newRandomSessionID } from "cojson/src/coValueCore.js";
|
4
|
-
import { Effect, Queue } from "effect";
|
5
4
|
import {
|
6
5
|
Account,
|
7
6
|
Encoders,
|
@@ -9,8 +8,8 @@ import {
|
|
9
8
|
co,
|
10
9
|
WasmCrypto,
|
11
10
|
isControlledAccount,
|
11
|
+
cojsonInternals,
|
12
12
|
} from "../index.js";
|
13
|
-
import { Schema } from "@effect/schema";
|
14
13
|
|
15
14
|
const Crypto = await WasmCrypto.create();
|
16
15
|
|
@@ -25,7 +24,10 @@ describe("Simple CoMap operations", async () => {
|
|
25
24
|
_height = co.number;
|
26
25
|
birthday = co.encoded(Encoders.Date);
|
27
26
|
name? = co.string;
|
28
|
-
nullable = co.optional.encoded(
|
27
|
+
nullable = co.optional.encoded<string | undefined>({
|
28
|
+
encode: (value: string | undefined) => value || null,
|
29
|
+
decode: (value: unknown) => (value as string) || undefined,
|
30
|
+
});
|
29
31
|
optionalDate = co.optional.encoded(Encoders.Date);
|
30
32
|
|
31
33
|
get roughColor() {
|
@@ -42,7 +44,7 @@ describe("Simple CoMap operations", async () => {
|
|
42
44
|
color: "red",
|
43
45
|
_height: 10,
|
44
46
|
birthday: birthday,
|
45
|
-
nullable:
|
47
|
+
nullable: undefined,
|
46
48
|
},
|
47
49
|
{ owner: me },
|
48
50
|
);
|
@@ -94,7 +96,7 @@ describe("Simple CoMap operations", async () => {
|
|
94
96
|
expect(map._raw.get("_height")).toEqual(20);
|
95
97
|
|
96
98
|
map.nullable = "not null";
|
97
|
-
map.nullable =
|
99
|
+
map.nullable = undefined;
|
98
100
|
delete map.nullable;
|
99
101
|
map.nullable = undefined;
|
100
102
|
|
@@ -282,12 +284,12 @@ describe("CoMap resolution", async () => {
|
|
282
284
|
|
283
285
|
test("Loading and availability", async () => {
|
284
286
|
const { me, map } = await initNodeAndMap();
|
285
|
-
const [initialAsPeer, secondPeer] =
|
287
|
+
const [initialAsPeer, secondPeer] =
|
286
288
|
connectedPeers("initial", "second", {
|
287
289
|
peer1role: "server",
|
288
290
|
peer2role: "client",
|
289
|
-
})
|
290
|
-
|
291
|
+
});
|
292
|
+
|
291
293
|
if (!isControlledAccount(me)) {
|
292
294
|
throw "me is not a controlled account";
|
293
295
|
}
|
@@ -353,12 +355,12 @@ describe("CoMap resolution", async () => {
|
|
353
355
|
test("Subscription & auto-resolution", async () => {
|
354
356
|
const { me, map } = await initNodeAndMap();
|
355
357
|
|
356
|
-
const [initialAsPeer, secondAsPeer] =
|
358
|
+
const [initialAsPeer, secondAsPeer] =
|
357
359
|
connectedPeers("initial", "second", {
|
358
360
|
peer1role: "server",
|
359
361
|
peer2role: "client",
|
360
|
-
})
|
361
|
-
|
362
|
+
});
|
363
|
+
|
362
364
|
if (!isControlledAccount(me)) {
|
363
365
|
throw "me is not a controlled account";
|
364
366
|
}
|
@@ -372,9 +374,8 @@ describe("CoMap resolution", async () => {
|
|
372
374
|
crypto: Crypto,
|
373
375
|
});
|
374
376
|
|
375
|
-
|
376
|
-
|
377
|
-
const queue = yield* $(Queue.unbounded<TestMap>());
|
377
|
+
|
378
|
+
const queue = new cojsonInternals.Channel<TestMap>();
|
378
379
|
|
379
380
|
TestMap.subscribe(
|
380
381
|
map.id,
|
@@ -385,22 +386,20 @@ describe("CoMap resolution", async () => {
|
|
385
386
|
"subscribedMap.nested?.twiceNested?.taste",
|
386
387
|
subscribedMap.nested?.twiceNested?.taste,
|
387
388
|
);
|
388
|
-
void
|
389
|
-
Queue.offer(queue, subscribedMap),
|
390
|
-
);
|
389
|
+
void queue.push(subscribedMap);
|
391
390
|
},
|
392
391
|
);
|
393
392
|
|
394
|
-
const update1 =
|
393
|
+
const update1 = (await queue.next()).value;
|
395
394
|
expect(update1.nested).toEqual(null);
|
396
395
|
|
397
|
-
const update2 =
|
396
|
+
const update2 = (await queue.next()).value;
|
398
397
|
expect(update2.nested?.name).toEqual("nested");
|
399
398
|
|
400
399
|
map.nested!.name = "nestedUpdated";
|
401
400
|
|
402
|
-
const _ =
|
403
|
-
const update3 =
|
401
|
+
const _ = (await queue.next()).value;
|
402
|
+
const update3 = (await queue.next()).value;
|
404
403
|
expect(update3.nested?.name).toEqual("nestedUpdated");
|
405
404
|
|
406
405
|
const oldTwiceNested = update3.nested!.twiceNested;
|
@@ -424,23 +423,21 @@ describe("CoMap resolution", async () => {
|
|
424
423
|
|
425
424
|
update3.nested = newNested;
|
426
425
|
|
427
|
-
|
428
|
-
// const update4 =
|
429
|
-
const update4b =
|
426
|
+
(await queue.next()).value;
|
427
|
+
// const update4 = (await queue.next()).value;
|
428
|
+
const update4b = (await queue.next()).value;
|
430
429
|
|
431
430
|
expect(update4b.nested?.name).toEqual("newNested");
|
432
431
|
expect(update4b.nested?.twiceNested?.taste).toEqual("sweet");
|
433
432
|
|
434
433
|
// we get updates when the new nested value changes
|
435
434
|
newTwiceNested.taste = "salty";
|
436
|
-
const update5 =
|
435
|
+
const update5 = (await queue.next()).value;
|
437
436
|
expect(update5.nested?.twiceNested?.taste).toEqual("salty");
|
438
437
|
|
439
438
|
newTwiceNested.taste = "umami";
|
440
|
-
const update6 =
|
439
|
+
const update6 = (await queue.next()).value;
|
441
440
|
expect(update6.nested?.twiceNested?.taste).toEqual("umami");
|
442
|
-
}),
|
443
|
-
);
|
444
441
|
});
|
445
442
|
|
446
443
|
class TestMapWithOptionalRef extends CoMap {
|