jazz-tools 0.8.50 → 0.9.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 +7 -5
- package/CHANGELOG.md +16 -0
- package/dist/{chunk-6OHBW32Q.js → chunk-EK2I4C5W.js} +72 -44
- package/dist/chunk-EK2I4C5W.js.map +1 -0
- package/dist/index.native.js +1 -1
- package/dist/index.web.js +1 -1
- package/dist/testing.js +71 -0
- package/dist/testing.js.map +1 -0
- package/package.json +6 -2
- package/src/coValues/coFeed.ts +19 -13
- package/src/coValues/coList.ts +10 -6
- package/src/coValues/coMap.ts +14 -9
- package/src/coValues/group.ts +3 -2
- package/src/coValues/interfaces.ts +64 -28
- package/src/implementation/refs.ts +17 -0
- package/src/implementation/subscriptionScope.ts +4 -4
- package/src/testing.ts +103 -0
- package/src/tests/coFeed.test.ts +16 -0
- package/src/tests/coList.test.ts +14 -0
- package/src/tests/coMap.test.ts +19 -0
- package/src/tests/schemaUnion.test.ts +6 -2
- package/src/tests/subscribe.test.ts +12 -2
- package/src/tests/utils.ts +10 -6
- package/tsup.config.ts +1 -0
- package/dist/chunk-6OHBW32Q.js.map +0 -1
package/src/coValues/coFeed.ts
CHANGED
@@ -32,6 +32,7 @@ import {
|
|
32
32
|
inspect,
|
33
33
|
isRefEncoded,
|
34
34
|
loadCoValue,
|
35
|
+
parseCoValueCreateOptions,
|
35
36
|
subscribeToCoValue,
|
36
37
|
subscribeToExistingCoValue,
|
37
38
|
} from "../internal.js";
|
@@ -204,10 +205,11 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
204
205
|
static create<S extends CoFeed>(
|
205
206
|
this: CoValueClass<S>,
|
206
207
|
init: S extends CoFeed<infer Item> ? UnCo<Item>[] : never,
|
207
|
-
options: { owner: Account | Group },
|
208
|
+
options: { owner: Account | Group } | Account | Group,
|
208
209
|
) {
|
209
|
-
const
|
210
|
-
const
|
210
|
+
const { owner } = parseCoValueCreateOptions(options);
|
211
|
+
const instance = new this({ init, owner });
|
212
|
+
const raw = owner._raw.createStream();
|
211
213
|
|
212
214
|
Object.defineProperties(instance, {
|
213
215
|
id: {
|
@@ -673,9 +675,9 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
673
675
|
|
674
676
|
static create<S extends FileStream>(
|
675
677
|
this: CoValueClass<S>,
|
676
|
-
options: { owner: Account | Group },
|
678
|
+
options: { owner: Account | Group } | Account | Group,
|
677
679
|
) {
|
678
|
-
return new this(options);
|
680
|
+
return new this(parseCoValueCreateOptions(options));
|
679
681
|
}
|
680
682
|
|
681
683
|
getChunks(options?: {
|
@@ -735,7 +737,7 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
735
737
|
*/
|
736
738
|
if (!options?.allowUnfinished && !stream?.isBinaryStreamEnded()) {
|
737
739
|
stream = await new Promise<FileStream>((resolve) => {
|
738
|
-
|
740
|
+
subscribeToCoValue(this, id, as, [], (value, unsubscribe) => {
|
739
741
|
if (value.isBinaryStreamEnded()) {
|
740
742
|
unsubscribe();
|
741
743
|
resolve(value);
|
@@ -762,12 +764,16 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
762
764
|
*/
|
763
765
|
static async createFromBlob(
|
764
766
|
blob: Blob | File,
|
765
|
-
options:
|
766
|
-
|
767
|
-
|
768
|
-
|
767
|
+
options:
|
768
|
+
| {
|
769
|
+
owner: Group | Account;
|
770
|
+
onProgress?: (progress: number) => void;
|
771
|
+
}
|
772
|
+
| Account
|
773
|
+
| Group,
|
769
774
|
): Promise<FileStream> {
|
770
|
-
const stream = this.create(
|
775
|
+
const stream = this.create(options);
|
776
|
+
const onProgress = "onProgress" in options ? options.onProgress : undefined;
|
771
777
|
|
772
778
|
const start = Date.now();
|
773
779
|
|
@@ -785,7 +791,7 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
785
791
|
stream.push(data.slice(idx, idx + chunkSize));
|
786
792
|
|
787
793
|
if (Date.now() - lastProgressUpdate > 100) {
|
788
|
-
|
794
|
+
onProgress?.(idx / data.length);
|
789
795
|
lastProgressUpdate = Date.now();
|
790
796
|
}
|
791
797
|
|
@@ -800,7 +806,7 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
800
806
|
"s - Throughput in MB/s",
|
801
807
|
(1000 * (blob.size / (end - start))) / (1024 * 1024),
|
802
808
|
);
|
803
|
-
|
809
|
+
onProgress?.(1);
|
804
810
|
|
805
811
|
return stream;
|
806
812
|
}
|
package/src/coValues/coList.ts
CHANGED
@@ -23,6 +23,7 @@ import {
|
|
23
23
|
isRefEncoded,
|
24
24
|
loadCoValue,
|
25
25
|
makeRefs,
|
26
|
+
parseCoValueCreateOptions,
|
26
27
|
subscribeToCoValue,
|
27
28
|
subscribeToExistingCoValue,
|
28
29
|
subscriptionsScopes,
|
@@ -220,10 +221,11 @@ export class CoList<Item = any> extends Array<Item> implements CoValue {
|
|
220
221
|
static create<L extends CoList>(
|
221
222
|
this: CoValueClass<L>,
|
222
223
|
items: UnCo<L[number]>[],
|
223
|
-
options: { owner: Account | Group },
|
224
|
+
options: { owner: Account | Group } | Account | Group,
|
224
225
|
) {
|
225
|
-
const
|
226
|
-
const
|
226
|
+
const { owner } = parseCoValueCreateOptions(options);
|
227
|
+
const instance = new this({ init: items, owner });
|
228
|
+
const raw = owner._raw.createList(
|
227
229
|
toRawItems(items, instance._schema[ItemsSym]),
|
228
230
|
);
|
229
231
|
|
@@ -239,9 +241,11 @@ export class CoList<Item = any> extends Array<Item> implements CoValue {
|
|
239
241
|
}
|
240
242
|
|
241
243
|
push(...items: Item[]): number {
|
242
|
-
|
243
|
-
this.
|
244
|
-
|
244
|
+
this._raw.appendItems(
|
245
|
+
toRawItems(items, this._schema[ItemsSym]),
|
246
|
+
undefined,
|
247
|
+
"private",
|
248
|
+
);
|
245
249
|
|
246
250
|
return this._raw.entries().length;
|
247
251
|
}
|
package/src/coValues/coMap.ts
CHANGED
@@ -30,6 +30,7 @@ import {
|
|
30
30
|
isRefEncoded,
|
31
31
|
loadCoValue,
|
32
32
|
makeRefs,
|
33
|
+
parseCoValueCreateOptions,
|
33
34
|
subscribeToCoValue,
|
34
35
|
subscribeToExistingCoValue,
|
35
36
|
subscriptionsScopes,
|
@@ -43,6 +44,7 @@ type CoMapEdit<V> = {
|
|
43
44
|
ref?: RefIfCoValue<V>;
|
44
45
|
by?: Account;
|
45
46
|
madeAt: Date;
|
47
|
+
key?: string;
|
46
48
|
};
|
47
49
|
|
48
50
|
type LastAndAllCoMapEdits<V> = CoMapEdit<V> & { all: CoMapEdit<V>[] };
|
@@ -183,6 +185,7 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
183
185
|
optional: false,
|
184
186
|
}).accessFrom(target, "_edits." + key + ".by"),
|
185
187
|
madeAt: rawEdit.at,
|
188
|
+
key,
|
186
189
|
};
|
187
190
|
}
|
188
191
|
|
@@ -271,17 +274,19 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
271
274
|
static create<M extends CoMap>(
|
272
275
|
this: CoValueClass<M>,
|
273
276
|
init: Simplify<CoMapInit<M>>,
|
274
|
-
options:
|
275
|
-
|
276
|
-
|
277
|
-
|
277
|
+
options:
|
278
|
+
| {
|
279
|
+
owner: Account | Group;
|
280
|
+
unique?: CoValueUniqueness["uniqueness"];
|
281
|
+
}
|
282
|
+
| Account
|
283
|
+
| Group,
|
278
284
|
) {
|
279
285
|
const instance = new this();
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
);
|
286
|
+
|
287
|
+
const { owner, uniqueness } = parseCoValueCreateOptions(options);
|
288
|
+
const raw = instance.rawFromInit(init, owner, uniqueness);
|
289
|
+
|
285
290
|
Object.defineProperties(instance, {
|
286
291
|
id: {
|
287
292
|
value: raw.id,
|
package/src/coValues/group.ts
CHANGED
@@ -14,6 +14,7 @@ import {
|
|
14
14
|
Ref,
|
15
15
|
ensureCoValueLoaded,
|
16
16
|
loadCoValue,
|
17
|
+
parseCoValueCreateOptions,
|
17
18
|
subscribeToCoValue,
|
18
19
|
subscribeToExistingCoValue,
|
19
20
|
} from "../internal.js";
|
@@ -123,9 +124,9 @@ export class Group extends CoValueBase implements CoValue {
|
|
123
124
|
|
124
125
|
static create<G extends Group>(
|
125
126
|
this: CoValueClass<G>,
|
126
|
-
options: { owner: Account },
|
127
|
+
options: { owner: Account } | Account,
|
127
128
|
) {
|
128
|
-
return new this(options);
|
129
|
+
return new this(parseCoValueCreateOptions(options));
|
129
130
|
}
|
130
131
|
|
131
132
|
myRole(): Role | undefined {
|
@@ -1,4 +1,8 @@
|
|
1
|
-
import type {
|
1
|
+
import type {
|
2
|
+
CoValueUniqueness,
|
3
|
+
CojsonInternalTypes,
|
4
|
+
RawCoValue,
|
5
|
+
} from "cojson";
|
2
6
|
import { RawAccount } from "cojson";
|
3
7
|
import { AnonymousJazzAgent } from "../implementation/anonymousJazzAgent.js";
|
4
8
|
import type { DeeplyLoaded, DepthsIn } from "../internal.js";
|
@@ -157,18 +161,17 @@ export function loadCoValue<V extends CoValue, Depth>(
|
|
157
161
|
depth: Depth & DepthsIn<V>,
|
158
162
|
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
159
163
|
return new Promise((resolve) => {
|
160
|
-
|
164
|
+
subscribeToCoValue(
|
161
165
|
cls,
|
162
166
|
id,
|
163
167
|
as,
|
164
168
|
depth,
|
165
|
-
(value) => {
|
169
|
+
(value, unsubscribe) => {
|
166
170
|
resolve(value);
|
167
171
|
unsubscribe();
|
168
172
|
},
|
169
173
|
() => {
|
170
174
|
resolve(undefined);
|
171
|
-
unsubscribe();
|
172
175
|
},
|
173
176
|
);
|
174
177
|
});
|
@@ -191,37 +194,49 @@ export function subscribeToCoValue<V extends CoValue, Depth>(
|
|
191
194
|
id: ID<V>,
|
192
195
|
as: Account | AnonymousJazzAgent,
|
193
196
|
depth: Depth & DepthsIn<V>,
|
194
|
-
listener: (value: DeeplyLoaded<V, Depth
|
197
|
+
listener: (value: DeeplyLoaded<V, Depth>, unsubscribe: () => void) => void,
|
195
198
|
onUnavailable?: () => void,
|
199
|
+
syncResolution?: boolean,
|
196
200
|
): () => void {
|
197
201
|
const ref = new Ref(id, as, { ref: cls, optional: false });
|
198
202
|
|
199
203
|
let unsubscribed = false;
|
200
204
|
let unsubscribe: (() => void) | undefined;
|
201
205
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
}
|
218
|
-
|
206
|
+
function subscribe(value: V | undefined) {
|
207
|
+
if (!value) {
|
208
|
+
onUnavailable && onUnavailable();
|
209
|
+
return;
|
210
|
+
}
|
211
|
+
if (unsubscribed) return;
|
212
|
+
const subscription = new SubscriptionScope(
|
213
|
+
value,
|
214
|
+
cls as CoValueClass<V> & CoValueFromRaw<V>,
|
215
|
+
(update, subscription) => {
|
216
|
+
if (fulfillsDepth(depth, update)) {
|
217
|
+
listener(
|
218
|
+
update as DeeplyLoaded<V, Depth>,
|
219
|
+
subscription.unsubscribeAll,
|
220
|
+
);
|
221
|
+
}
|
222
|
+
},
|
223
|
+
);
|
219
224
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
+
unsubscribe = subscription.unsubscribeAll;
|
226
|
+
}
|
227
|
+
|
228
|
+
const sync = syncResolution ? ref.syncLoad() : undefined;
|
229
|
+
|
230
|
+
if (sync) {
|
231
|
+
subscribe(sync);
|
232
|
+
} else {
|
233
|
+
ref
|
234
|
+
.load()
|
235
|
+
.then((value) => subscribe(value))
|
236
|
+
.catch((e) => {
|
237
|
+
console.error("Failed to load / subscribe to CoValue", e);
|
238
|
+
});
|
239
|
+
}
|
225
240
|
|
226
241
|
return function unsubscribeAtAnyPoint() {
|
227
242
|
unsubscribed = true;
|
@@ -229,7 +244,9 @@ export function subscribeToCoValue<V extends CoValue, Depth>(
|
|
229
244
|
};
|
230
245
|
}
|
231
246
|
|
232
|
-
export function createCoValueObservable<V extends CoValue, Depth>(
|
247
|
+
export function createCoValueObservable<V extends CoValue, Depth>(options?: {
|
248
|
+
syncResolution?: boolean;
|
249
|
+
}) {
|
233
250
|
let currentValue: DeeplyLoaded<V, Depth> | undefined = undefined;
|
234
251
|
let subscriberCount = 0;
|
235
252
|
|
@@ -253,6 +270,7 @@ export function createCoValueObservable<V extends CoValue, Depth>() {
|
|
253
270
|
listener();
|
254
271
|
},
|
255
272
|
onUnavailable,
|
273
|
+
options?.syncResolution,
|
256
274
|
);
|
257
275
|
|
258
276
|
return () => {
|
@@ -285,3 +303,21 @@ export function subscribeToExistingCoValue<V extends CoValue, Depth>(
|
|
285
303
|
listener,
|
286
304
|
);
|
287
305
|
}
|
306
|
+
|
307
|
+
export function parseCoValueCreateOptions(
|
308
|
+
options:
|
309
|
+
| {
|
310
|
+
owner: Account | Group;
|
311
|
+
unique?: CoValueUniqueness["uniqueness"];
|
312
|
+
}
|
313
|
+
| Account
|
314
|
+
| Group,
|
315
|
+
) {
|
316
|
+
return "_type" in options &&
|
317
|
+
(options._type === "Account" || options._type === "Group")
|
318
|
+
? { owner: options, uniqueness: undefined }
|
319
|
+
: {
|
320
|
+
owner: options.owner,
|
321
|
+
uniqueness: options.unique ? { uniqueness: options.unique } : undefined,
|
322
|
+
};
|
323
|
+
}
|
@@ -55,6 +55,23 @@ export class Ref<out V extends CoValue> {
|
|
55
55
|
}
|
56
56
|
}
|
57
57
|
|
58
|
+
syncLoad(): V | undefined {
|
59
|
+
const node =
|
60
|
+
"node" in this.controlledAccount
|
61
|
+
? this.controlledAccount.node
|
62
|
+
: this.controlledAccount._raw.core.node;
|
63
|
+
|
64
|
+
const entry = node.coValuesStore.get(
|
65
|
+
this.id as unknown as CoID<RawCoValue>,
|
66
|
+
);
|
67
|
+
|
68
|
+
if (entry.state.type === "available") {
|
69
|
+
return new Ref(this.id, this.controlledAccount, this.schema).value!;
|
70
|
+
}
|
71
|
+
|
72
|
+
return undefined;
|
73
|
+
}
|
74
|
+
|
58
75
|
async load(): Promise<V | undefined> {
|
59
76
|
const result = await this.loadHelper();
|
60
77
|
if (result === "unavailable") {
|
@@ -37,7 +37,7 @@ export class SubscriptionScope<Root extends CoValue> {
|
|
37
37
|
constructor(
|
38
38
|
root: Root,
|
39
39
|
rootSchema: CoValueClass<Root> & CoValueFromRaw<Root>,
|
40
|
-
onUpdate: (newRoot: Root) => void,
|
40
|
+
onUpdate: (newRoot: Root, scope: SubscriptionScope<Root>) => void,
|
41
41
|
) {
|
42
42
|
this.rootEntry = {
|
43
43
|
state: "loaded" as const,
|
@@ -52,7 +52,7 @@ export class SubscriptionScope<Root extends CoValue> {
|
|
52
52
|
this.scheduleUpdate = () => {
|
53
53
|
const value = rootSchema.fromRaw(this.rootEntry.value) as Root;
|
54
54
|
subscriptionsScopes.set(value, this);
|
55
|
-
onUpdate(value);
|
55
|
+
onUpdate(value, this);
|
56
56
|
};
|
57
57
|
|
58
58
|
this.rootEntry.rawUnsub = root._raw.core.subscribe(
|
@@ -125,7 +125,7 @@ export class SubscriptionScope<Root extends CoValue> {
|
|
125
125
|
}
|
126
126
|
}
|
127
127
|
|
128
|
-
unsubscribeAll() {
|
128
|
+
unsubscribeAll = () => {
|
129
129
|
for (const entry of this.entries.values()) {
|
130
130
|
if (entry.state === "loaded") {
|
131
131
|
entry.rawUnsub();
|
@@ -134,5 +134,5 @@ export class SubscriptionScope<Root extends CoValue> {
|
|
134
134
|
}
|
135
135
|
}
|
136
136
|
this.entries.clear();
|
137
|
-
}
|
137
|
+
};
|
138
138
|
}
|
package/src/testing.ts
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
import { AgentSecret, CryptoProvider, Peer } from "cojson";
|
2
|
+
import { cojsonInternals } from "cojson";
|
3
|
+
import { PureJSCrypto } from "cojson/crypto";
|
4
|
+
import { Account, type AccountClass } from "./exports.js";
|
5
|
+
import {
|
6
|
+
type AnonymousJazzAgent,
|
7
|
+
type CoValueClass,
|
8
|
+
createAnonymousJazzContext,
|
9
|
+
} from "./internal.js";
|
10
|
+
|
11
|
+
type TestAccountSchema<Acc extends Account> = CoValueClass<Acc> & {
|
12
|
+
fromNode: (typeof Account)["fromNode"];
|
13
|
+
create: (options: {
|
14
|
+
creationProps: { name: string };
|
15
|
+
initialAgentSecret?: AgentSecret;
|
16
|
+
peersToLoadFrom?: Peer[];
|
17
|
+
crypto: CryptoProvider;
|
18
|
+
}) => Promise<Acc>;
|
19
|
+
};
|
20
|
+
|
21
|
+
class TestJSCrypto extends PureJSCrypto {
|
22
|
+
static async create() {
|
23
|
+
if ("navigator" in globalThis && navigator.userAgent.includes("jsdom")) {
|
24
|
+
// Mocking crypto seal & encrypt to make it work with JSDom. Getting "Error: Uint8Array expected" there
|
25
|
+
const crypto = new PureJSCrypto();
|
26
|
+
|
27
|
+
crypto.seal = (options) =>
|
28
|
+
`sealed_U${cojsonInternals.stableStringify(options.message)}` as any;
|
29
|
+
crypto.unseal = (sealed) =>
|
30
|
+
JSON.parse(sealed.substring("sealed_U".length));
|
31
|
+
crypto.encrypt = (message) =>
|
32
|
+
`encrypted_U${cojsonInternals.stableStringify(message)}` as any;
|
33
|
+
crypto.decryptRaw = (encrypted) =>
|
34
|
+
encrypted.substring("encrypted_U".length) as any;
|
35
|
+
|
36
|
+
return crypto;
|
37
|
+
}
|
38
|
+
|
39
|
+
// For non-jsdom environments, we use the real crypto
|
40
|
+
return new PureJSCrypto();
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
export async function createJazzTestAccount<Acc extends Account>(options?: {
|
45
|
+
AccountSchema?: CoValueClass<Acc>;
|
46
|
+
}): Promise<Acc> {
|
47
|
+
const AccountSchema = (options?.AccountSchema ??
|
48
|
+
Account) as unknown as TestAccountSchema<Acc>;
|
49
|
+
const account = await AccountSchema.create({
|
50
|
+
creationProps: {
|
51
|
+
name: "Test Account",
|
52
|
+
},
|
53
|
+
crypto: await TestJSCrypto.create(),
|
54
|
+
});
|
55
|
+
|
56
|
+
return account;
|
57
|
+
}
|
58
|
+
|
59
|
+
export async function createJazzTestGuest() {
|
60
|
+
const ctx = await createAnonymousJazzContext({
|
61
|
+
crypto: await PureJSCrypto.create(),
|
62
|
+
peersToLoadFrom: [],
|
63
|
+
});
|
64
|
+
|
65
|
+
return {
|
66
|
+
guest: ctx.agent,
|
67
|
+
};
|
68
|
+
}
|
69
|
+
|
70
|
+
export function getJazzContextShape<Acc extends Account>(
|
71
|
+
account: Acc | { guest: AnonymousJazzAgent },
|
72
|
+
) {
|
73
|
+
if ("guest" in account) {
|
74
|
+
return {
|
75
|
+
guest: account.guest,
|
76
|
+
AccountSchema: Account,
|
77
|
+
logOut: () => account.guest.node.gracefulShutdown(),
|
78
|
+
done: () => account.guest.node.gracefulShutdown(),
|
79
|
+
};
|
80
|
+
}
|
81
|
+
|
82
|
+
return {
|
83
|
+
me: account,
|
84
|
+
AccountSchema: account.constructor as AccountClass<Acc>,
|
85
|
+
logOut: () => account._raw.core.node.gracefulShutdown(),
|
86
|
+
done: () => account._raw.core.node.gracefulShutdown(),
|
87
|
+
};
|
88
|
+
}
|
89
|
+
|
90
|
+
export function linkAccounts(
|
91
|
+
a: Account,
|
92
|
+
b: Account,
|
93
|
+
aRole: "server" | "client" = "server",
|
94
|
+
bRole: "server" | "client" = "server",
|
95
|
+
) {
|
96
|
+
const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {
|
97
|
+
peer1role: aRole,
|
98
|
+
peer2role: bRole,
|
99
|
+
});
|
100
|
+
|
101
|
+
a._raw.core.node.syncManager.addPeer(aPeer);
|
102
|
+
b._raw.core.node.syncManager.addPeer(bPeer);
|
103
|
+
}
|
package/src/tests/coFeed.test.ts
CHANGED
@@ -4,6 +4,7 @@ import {
|
|
4
4
|
Account,
|
5
5
|
CoFeed,
|
6
6
|
FileStream,
|
7
|
+
Group,
|
7
8
|
ID,
|
8
9
|
WasmCrypto,
|
9
10
|
co,
|
@@ -34,6 +35,21 @@ describe("Simple CoFeed operations", async () => {
|
|
34
35
|
expect(stream.perSession[me.sessionID]?.value).toEqual("milk");
|
35
36
|
});
|
36
37
|
|
38
|
+
test("Construction with an Account", () => {
|
39
|
+
const stream = TestStream.create(["milk"], me);
|
40
|
+
|
41
|
+
expect(stream[me.id]?.value).toEqual("milk");
|
42
|
+
expect(stream.perSession[me.sessionID]?.value).toEqual("milk");
|
43
|
+
});
|
44
|
+
|
45
|
+
test("Construction with a Group", () => {
|
46
|
+
const group = Group.create(me);
|
47
|
+
const stream = TestStream.create(["milk"], group);
|
48
|
+
|
49
|
+
expect(stream[me.id]?.value).toEqual("milk");
|
50
|
+
expect(stream.perSession[me.sessionID]?.value).toEqual("milk");
|
51
|
+
});
|
52
|
+
|
37
53
|
describe("Mutation", () => {
|
38
54
|
test("pushing", () => {
|
39
55
|
stream.push("bread");
|
package/src/tests/coList.test.ts
CHANGED
@@ -3,6 +3,7 @@ import { describe, expect, test } from "vitest";
|
|
3
3
|
import {
|
4
4
|
Account,
|
5
5
|
CoList,
|
6
|
+
Group,
|
6
7
|
WasmCrypto,
|
7
8
|
co,
|
8
9
|
cojsonInternals,
|
@@ -37,6 +38,19 @@ describe("Simple CoList operations", async () => {
|
|
37
38
|
]);
|
38
39
|
});
|
39
40
|
|
41
|
+
test("Construction with an Account", () => {
|
42
|
+
const list = TestList.create(["milk"], me);
|
43
|
+
|
44
|
+
expect(list[0]).toEqual("milk");
|
45
|
+
});
|
46
|
+
|
47
|
+
test("Construction with a Group", () => {
|
48
|
+
const group = Group.create(me);
|
49
|
+
const list = TestList.create(["milk"], group);
|
50
|
+
|
51
|
+
expect(list[0]).toEqual("milk");
|
52
|
+
});
|
53
|
+
|
40
54
|
describe("Mutation", () => {
|
41
55
|
test("assignment", () => {
|
42
56
|
const list = TestList.create(["bread", "butter", "onion"], {
|
package/src/tests/coMap.test.ts
CHANGED
@@ -64,6 +64,25 @@ describe("Simple CoMap operations", async () => {
|
|
64
64
|
]);
|
65
65
|
});
|
66
66
|
|
67
|
+
test("Construction with an Account", () => {
|
68
|
+
const map = TestMap.create(
|
69
|
+
{ color: "red", _height: 10, birthday: birthday },
|
70
|
+
me,
|
71
|
+
);
|
72
|
+
|
73
|
+
expect(map.color).toEqual("red");
|
74
|
+
});
|
75
|
+
|
76
|
+
test("Construction with a Group", () => {
|
77
|
+
const group = Group.create(me);
|
78
|
+
const map = TestMap.create(
|
79
|
+
{ color: "red", _height: 10, birthday: birthday },
|
80
|
+
group,
|
81
|
+
);
|
82
|
+
|
83
|
+
expect(map.color).toEqual("red");
|
84
|
+
});
|
85
|
+
|
67
86
|
test("Construction with too many things provided", () => {
|
68
87
|
const mapWithExtra = TestMap.create(
|
69
88
|
{
|
@@ -99,6 +99,7 @@ describe("SchemaUnion", () => {
|
|
99
99
|
{ type: "button", label: "Submit" },
|
100
100
|
{ owner: me },
|
101
101
|
);
|
102
|
+
let currentValue = "Submit";
|
102
103
|
const unsubscribe = subscribeToCoValue(
|
103
104
|
WidgetUnion,
|
104
105
|
buttonWidget.id,
|
@@ -106,13 +107,16 @@ describe("SchemaUnion", () => {
|
|
106
107
|
{},
|
107
108
|
(value: BaseWidget) => {
|
108
109
|
if (value instanceof ButtonWidget) {
|
109
|
-
expect(value.label).toBe(
|
110
|
-
unsubscribe();
|
110
|
+
expect(value.label).toBe(currentValue);
|
111
111
|
} else {
|
112
112
|
throw new Error("Unexpected widget type");
|
113
113
|
}
|
114
114
|
},
|
115
|
+
() => {},
|
116
|
+
true,
|
115
117
|
);
|
118
|
+
currentValue = "Changed";
|
116
119
|
buttonWidget.label = "Changed";
|
120
|
+
unsubscribe();
|
117
121
|
});
|
118
122
|
});
|
@@ -1,9 +1,15 @@
|
|
1
1
|
import { describe, expect, it, onTestFinished, vi } from "vitest";
|
2
|
-
import { Account, CoFeed, CoList, CoMap, co } from "../index.web.js";
|
3
2
|
import {
|
4
|
-
|
3
|
+
Account,
|
4
|
+
CoFeed,
|
5
|
+
CoList,
|
6
|
+
CoMap,
|
5
7
|
FileStream,
|
6
8
|
Group,
|
9
|
+
co,
|
10
|
+
} from "../index.web.js";
|
11
|
+
import {
|
12
|
+
type DepthsIn,
|
7
13
|
createCoValueObservable,
|
8
14
|
subscribeToCoValue,
|
9
15
|
} from "../internal.js";
|
@@ -64,6 +70,7 @@ describe("subscribeToCoValue", () => {
|
|
64
70
|
messages: null,
|
65
71
|
name: "General",
|
66
72
|
}),
|
73
|
+
expect.any(Function),
|
67
74
|
);
|
68
75
|
|
69
76
|
updateFn.mockClear();
|
@@ -78,6 +85,7 @@ describe("subscribeToCoValue", () => {
|
|
78
85
|
name: "General",
|
79
86
|
messages: expect.any(Array),
|
80
87
|
}),
|
88
|
+
expect.any(Function),
|
81
89
|
);
|
82
90
|
|
83
91
|
updateFn.mockClear();
|
@@ -93,6 +101,7 @@ describe("subscribeToCoValue", () => {
|
|
93
101
|
name: "Lounge",
|
94
102
|
messages: expect.any(Array),
|
95
103
|
}),
|
104
|
+
expect.any(Function),
|
96
105
|
);
|
97
106
|
});
|
98
107
|
|
@@ -125,6 +134,7 @@ describe("subscribeToCoValue", () => {
|
|
125
134
|
name: "General",
|
126
135
|
messages: expect.any(Array),
|
127
136
|
}),
|
137
|
+
expect.any(Function),
|
128
138
|
);
|
129
139
|
});
|
130
140
|
|