jazz-tools 0.7.0-alpha.2 → 0.7.0-alpha.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +84 -9
  2. package/CHANGELOG.md +116 -0
  3. package/dist/coValues/account.js +66 -33
  4. package/dist/coValues/account.js.map +1 -1
  5. package/dist/coValues/coList.js +147 -97
  6. package/dist/coValues/coList.js.map +1 -1
  7. package/dist/coValues/coMap.js +151 -164
  8. package/dist/coValues/coMap.js.map +1 -1
  9. package/dist/coValues/coStream.js +176 -70
  10. package/dist/coValues/coStream.js.map +1 -1
  11. package/dist/coValues/extensions/imageDef.js +13 -8
  12. package/dist/coValues/extensions/imageDef.js.map +1 -1
  13. package/dist/coValues/group.js +13 -35
  14. package/dist/coValues/group.js.map +1 -1
  15. package/dist/coValues/interfaces.js +6 -3
  16. package/dist/coValues/interfaces.js.map +1 -1
  17. package/dist/implementation/refs.js +13 -10
  18. package/dist/implementation/refs.js.map +1 -1
  19. package/dist/implementation/schema.js +36 -1
  20. package/dist/implementation/schema.js.map +1 -1
  21. package/dist/index.js +4 -3
  22. package/dist/index.js.map +1 -1
  23. package/dist/tests/coList.test.js +5 -9
  24. package/dist/tests/coList.test.js.map +1 -1
  25. package/dist/tests/coMap.test.js +108 -38
  26. package/dist/tests/coMap.test.js.map +1 -1
  27. package/dist/tests/coStream.test.js +46 -51
  28. package/dist/tests/coStream.test.js.map +1 -1
  29. package/package.json +5 -4
  30. package/src/coValues/account.ts +98 -68
  31. package/src/coValues/coList.ts +188 -120
  32. package/src/coValues/coMap.ts +232 -276
  33. package/src/coValues/coStream.ts +265 -124
  34. package/src/coValues/extensions/imageDef.ts +13 -15
  35. package/src/coValues/group.ts +33 -80
  36. package/src/coValues/interfaces.ts +12 -10
  37. package/src/implementation/refs.ts +45 -18
  38. package/src/implementation/schema.ts +86 -31
  39. package/src/index.ts +10 -8
  40. package/src/tests/coList.test.ts +5 -9
  41. package/src/tests/coMap.test.ts +89 -53
  42. package/src/tests/coStream.test.ts +61 -66
@@ -1,23 +1,18 @@
1
- import type { CoID, Everyone, RawCoMap, RawGroup, Role } from "cojson";
2
- import type {
3
- CoValue,
4
- CoValueClass,
5
- ID,
6
- PrimitiveField,
7
- RefField,
8
- } from "../internal.js";
1
+ import type { Everyone, RawGroup, Role } from "cojson";
2
+ import type { CoValue, ID, JsonEncoded, RefEncoded } from "../internal.js";
9
3
  import {
10
4
  Account,
11
5
  CoMap,
12
6
  CoValueBase,
13
- ValueRef,
7
+ Ref,
8
+ co,
14
9
  isControlledAccount,
10
+ AccountAndGroupProxyHandler,
15
11
  } from "../internal.js";
16
12
 
17
- export class Profile extends CoMap<{ name: string }> {
18
- declare name: string;
13
+ export class Profile extends CoMap<{ name: co<string> }> {
14
+ name = co.string;
19
15
  }
20
- Profile.encoding({ name: "json" });
21
16
 
22
17
  export class Group<
23
18
  Def extends { profile: Profile | null; root: CoMap | null } = {
@@ -28,31 +23,31 @@ export class Group<
28
23
  extends CoValueBase
29
24
  implements CoValue<"Group", RawGroup>
30
25
  {
31
- id!: ID<this>;
32
- _type!: "Group";
26
+ declare id: ID<this>;
27
+ declare _type: "Group";
33
28
  static {
34
29
  this.prototype._type = "Group";
35
30
  }
36
- _raw!: RawGroup;
31
+ declare _raw: RawGroup;
37
32
 
38
- static _encoding: any;
39
- get _encoding(): {
33
+ static _schema: any;
34
+ get _schema(): {
40
35
  profile: Def["profile"] extends CoValue
41
- ? RefField<Def["profile"]>
42
- : PrimitiveField;
36
+ ? RefEncoded<Def["profile"]>
37
+ : JsonEncoded;
43
38
  root: Def["root"] extends CoValue
44
- ? RefField<Def["root"]>
45
- : PrimitiveField;
39
+ ? RefEncoded<Def["root"]>
40
+ : JsonEncoded;
46
41
  } {
47
- return (this.constructor as typeof Group)._encoding;
42
+ return (this.constructor as typeof Group)._schema;
48
43
  }
49
44
  static {
50
- this._encoding = {
45
+ this._schema = {
51
46
  profile: { json: true },
52
47
  root: { json: true },
53
48
  } as any;
54
- Object.defineProperty(this.prototype, "_encoding", {
55
- get: () => this._encoding,
49
+ Object.defineProperty(this.prototype, "_schema", {
50
+ get: () => this._schema,
56
51
  });
57
52
  }
58
53
 
@@ -63,10 +58,8 @@ export class Group<
63
58
  root!: Def["root"] extends CoMap ? Def["root"] | null : undefined;
64
59
 
65
60
  get _refs(): {
66
- profile: Def["profile"] extends Profile
67
- ? ValueRef<Def["profile"]>
68
- : never;
69
- root: Def["root"] extends CoMap ? ValueRef<Def["root"]> : never;
61
+ profile: Def["profile"] extends Profile ? Ref<Def["profile"]> : never;
62
+ root: Def["root"] extends CoMap ? Ref<Def["root"]> : never;
70
63
  } {
71
64
  const profileID = this._raw.get("profile") as unknown as
72
65
  | ID<NonNullable<Def["profile"]>>
@@ -77,25 +70,19 @@ export class Group<
77
70
  return {
78
71
  profile:
79
72
  profileID &&
80
- (new ValueRef(
73
+ (new Ref(
81
74
  profileID,
82
75
  this._loadedAs,
83
- (
84
- this._encoding.profile as RefField<
85
- NonNullable<Def["profile"]>
86
- >
87
- ).ref()
76
+ this._schema.profile as RefEncoded<
77
+ NonNullable<Def["profile"]>
78
+ >
88
79
  ) as any),
89
80
  root:
90
81
  rootID &&
91
- (new ValueRef(
82
+ (new Ref(
92
83
  rootID,
93
84
  this._loadedAs,
94
- (
95
- this._encoding.root as RefField<
96
- NonNullable<Def["root"]>
97
- >
98
- ).ref()
85
+ this._schema.root as RefEncoded<NonNullable<Def["root"]>>
99
86
  ) as any),
100
87
  };
101
88
  }
@@ -134,35 +121,12 @@ export class Group<
134
121
  enumerable: false,
135
122
  },
136
123
  _raw: { value: raw, enumerable: false },
137
- profile: {
138
- get: () => {
139
- const ref = this._refs.profile;
140
- return ref ? ref.accessFrom(this) : (undefined as any);
141
- },
142
- set: (value: Def["profile"] | null) => {
143
- if (value) {
144
- this._raw.set(
145
- "profile",
146
- value.id as unknown as CoID<RawCoMap>
147
- );
148
- }
149
- },
150
- },
151
- root: {
152
- get: () => {
153
- const ref = this._refs.root;
154
- return ref ? ref.accessFrom(this) : (undefined as any);
155
- },
156
- set: (value: Def["root"] | null) => {
157
- if (value) {
158
- this._raw.set(
159
- "root",
160
- value.id as unknown as CoID<RawCoMap>
161
- );
162
- }
163
- },
164
- },
165
124
  });
125
+
126
+ return new Proxy(
127
+ this,
128
+ AccountAndGroupProxyHandler as ProxyHandler<this>
129
+ );
166
130
  }
167
131
 
168
132
  myRole(): Role | undefined {
@@ -172,15 +136,4 @@ export class Group<
172
136
  addMember(member: Everyone | Account, role: Role) {
173
137
  this._raw.addMember(member === "everyone" ? member : member._raw, role);
174
138
  }
175
-
176
- static define<V extends Account>(
177
- this: CoValueClass<V> & typeof Account,
178
- fields: {
179
- profile: V["_encoding"]["profile"];
180
- root: V["_encoding"]["root"];
181
- }
182
- ) {
183
- this._encoding ||= {};
184
- Object.assign(this._encoding, fields);
185
- }
186
139
  }
@@ -7,7 +7,7 @@ import {
7
7
  AccountCtx,
8
8
  Group,
9
9
  SubscriptionScope,
10
- ValueRef,
10
+ Ref,
11
11
  inspect,
12
12
  } from "../internal.js";
13
13
 
@@ -15,10 +15,7 @@ export type SubclassedConstructor<T> = {
15
15
  new (...args: any[]): T;
16
16
  };
17
17
 
18
- export interface CoValueClass<
19
- Value extends CoValue = CoValue,
20
- Init = any,
21
- > {
18
+ export interface CoValueClass<Value extends CoValue = CoValue, Init = any> {
22
19
  /** @category Construction and loading */
23
20
  new (init: Init, options: { owner: Account | Group }): Value;
24
21
 
@@ -81,11 +78,14 @@ export interface CoValue<Type extends string = string, Raw = any> {
81
78
  export function isCoValue(value: any): value is CoValue {
82
79
  return value && value._type !== undefined;
83
80
  }
81
+ export function isCoValueClass(value: any): value is CoValueClass {
82
+ return typeof value === "function" && value.fromRaw !== undefined;
83
+ }
84
84
 
85
85
  /** @category Schemas & CoValues - Abstract interfaces */
86
- export type ID<T> = CojsonInternalTypes.RawCoID & {
87
- readonly __type: T;
88
- };
86
+ export type ID<T> = CojsonInternalTypes.RawCoID & IDMarker<T>;
87
+
88
+ type IDMarker<out T> = { __type(_: never): T };
89
89
 
90
90
  export class CoValueBase implements CoValue {
91
91
  id!: ID<this>;
@@ -117,7 +117,9 @@ export class CoValueBase implements CoValue {
117
117
  ): Effect.Effect<V, UnavailableError, AccountCtx> {
118
118
  return Effect.gen(this, function* (_) {
119
119
  const account = yield* _(AccountCtx);
120
- return yield* _(new ValueRef(id as ID<V>, account, this).loadEf());
120
+ return yield* _(
121
+ new Ref(id as ID<V>, account, this as CoValueClass<V>).loadEf()
122
+ );
121
123
  });
122
124
  }
123
125
 
@@ -129,7 +131,7 @@ export class CoValueBase implements CoValue {
129
131
  onProgress?: (progress: number) => void;
130
132
  }
131
133
  ): Promise<V | undefined> {
132
- return new ValueRef(id as ID<V>, options.as, this).load(
134
+ return new Ref(id as ID<V>, options.as, this as CoValueClass<V>).load(
133
135
  options?.onProgress && { onProgress: options.onProgress }
134
136
  );
135
137
  }
@@ -1,16 +1,31 @@
1
1
  import { Effect } from "effect";
2
2
  import type { CoID, RawCoValue } from "cojson";
3
- import type { Account, CoValue, ID, Me, SubclassedConstructor, UnavailableError, indexSignature} from '../internal.js';
4
- import { subscriptionsScopes } from '../internal.js';
3
+ import type {
4
+ Account,
5
+ CoValue,
6
+ ID,
7
+ Me,
8
+ RefEncoded,
9
+ UnavailableError,
10
+ } from "../internal.js";
11
+ import {
12
+ instantiateRefEncoded,
13
+ isRefEncoded,
14
+ subscriptionsScopes,
15
+ } from "../internal.js";
5
16
 
6
- export class ValueRef<V extends CoValue> {
17
+ export class Ref<out V extends CoValue> {
7
18
  private cachedValue: V | undefined;
8
19
 
9
20
  constructor(
10
21
  readonly id: ID<V>,
11
22
  readonly controlledAccount: Account & Me,
12
- readonly valueConstructor: SubclassedConstructor<V>
13
- ) {}
23
+ readonly schema: RefEncoded<V>
24
+ ) {
25
+ if (!isRefEncoded(schema)) {
26
+ throw new Error("Ref must be constructed with a ref schema");
27
+ }
28
+ }
14
29
 
15
30
  get value() {
16
31
  if (this.cachedValue) return this.cachedValue;
@@ -19,7 +34,7 @@ export class ValueRef<V extends CoValue> {
19
34
  this.id as unknown as CoID<RawCoValue>
20
35
  );
21
36
  if (raw) {
22
- const value = new this.valueConstructor(undefined, { fromRaw: raw }) as V;
37
+ const value = instantiateRefEncoded(this.schema, raw);
23
38
  this.cachedValue = value;
24
39
  return value;
25
40
  } else {
@@ -43,7 +58,9 @@ export class ValueRef<V extends CoValue> {
43
58
  });
44
59
  }
45
60
 
46
- private async loadHelper(options?: {onProgress: (p: number) => void}): Promise<V | "unavailable"> {
61
+ private async loadHelper(options?: {
62
+ onProgress: (p: number) => void;
63
+ }): Promise<V | "unavailable"> {
47
64
  const raw = await this.controlledAccount._raw.core.node.load(
48
65
  this.id as unknown as CoID<RawCoValue>,
49
66
  options?.onProgress
@@ -51,12 +68,14 @@ export class ValueRef<V extends CoValue> {
51
68
  if (raw === "unavailable") {
52
69
  return "unavailable";
53
70
  } else {
54
- return new ValueRef(this.id, this.controlledAccount, this.valueConstructor)
71
+ return new Ref(this.id, this.controlledAccount, this.schema)
55
72
  .value!;
56
73
  }
57
74
  }
58
75
 
59
- async load(options?: {onProgress: (p: number) => void}): Promise<V | undefined> {
76
+ async load(options?: {
77
+ onProgress: (p: number) => void;
78
+ }): Promise<V | undefined> {
60
79
  const result = await this.loadHelper(options);
61
80
  if (result === "unavailable") {
62
81
  return undefined;
@@ -78,22 +97,28 @@ export class ValueRef<V extends CoValue> {
78
97
  }
79
98
  }
80
99
 
81
- export function makeRefs<Keys extends string | number | indexSignature>(
100
+ export function makeRefs<Keys extends string | number>(
82
101
  getIdForKey: (key: Keys) => ID<CoValue> | undefined,
83
102
  getKeysWithIds: () => Keys[],
84
103
  controlledAccount: Account & Me,
85
- valueConstructorForKey: (key: Keys) => SubclassedConstructor<CoValue>,
86
- ): { [K in Keys]: ValueRef<CoValue> } {
87
- const refs = {} as { [K in Keys]: ValueRef<CoValue> };
104
+ refSchemaForKey: (key: Keys) => RefEncoded<CoValue>
105
+ ): { [K in Keys]: Ref<CoValue> } & {
106
+ [Symbol.iterator]: () => IterableIterator<Ref<CoValue>>;
107
+ length: number;
108
+ } {
109
+ const refs = {} as { [K in Keys]: Ref<CoValue> } & {
110
+ [Symbol.iterator]: () => IterableIterator<Ref<CoValue>>;
111
+ length: number;
112
+ };
88
113
  return new Proxy(refs, {
89
- get(target, key) {
114
+ get(_target, key) {
90
115
  if (key === Symbol.iterator) {
91
116
  return function* () {
92
117
  for (const key of getKeysWithIds()) {
93
- yield new ValueRef(
118
+ yield new Ref(
94
119
  getIdForKey(key)!,
95
120
  controlledAccount,
96
- valueConstructorForKey(key)
121
+ refSchemaForKey(key)
97
122
  );
98
123
  }
99
124
  };
@@ -104,10 +129,10 @@ export function makeRefs<Keys extends string | number | indexSignature>(
104
129
  }
105
130
  const id = getIdForKey(key as Keys);
106
131
  if (!id) return undefined;
107
- return new ValueRef(
132
+ return new Ref(
108
133
  id as ID<CoValue>,
109
134
  controlledAccount,
110
- valueConstructorForKey(key as Keys)
135
+ refSchemaForKey(key as Keys)
111
136
  );
112
137
  },
113
138
  ownKeys() {
@@ -115,3 +140,5 @@ export function makeRefs<Keys extends string | number | indexSignature>(
115
140
  },
116
141
  });
117
142
  }
143
+
144
+ export type RefIfCoValue<V> = NonNullable<V> extends CoValue ? Ref<NonNullable<V>> : never;
@@ -1,25 +1,81 @@
1
- import type { JsonValue } from "cojson";
2
- import type { CoValue, CoValueClass } from "../internal.js";
3
- import type { Schema, TypeId } from "@effect/schema/Schema";
4
-
5
- export type PrimitiveField = "json";
6
- export type EncodedField<V> = { encoded: Encoder<V> };
7
- export type RefField<V extends CoValue> = {
8
- ref: () => CoValueClass<V>;
1
+ import type { JsonValue, RawCoValue } from "cojson";
2
+ import { type CoValue, type CoValueClass, isCoValueClass } from "../internal.js";
3
+ import type { Schema as EffectSchema, TypeId } from "@effect/schema/Schema";
4
+
5
+ export type CoMarker = { readonly __co: unique symbol };
6
+ export type co<T> = T | (T & CoMarker);
7
+ export type IfCo<C, R> = C extends infer _A | infer B
8
+ ? B extends CoMarker
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 co = {
23
+ string: {
24
+ [SchemaInit]: "json" satisfies Schema,
25
+ } as unknown as co<string>,
26
+ number: {
27
+ [SchemaInit]: "json" satisfies Schema,
28
+ } as unknown as co<number>,
29
+ boolean: {
30
+ [SchemaInit]: "json" satisfies Schema,
31
+ } as unknown as co<boolean>,
32
+ literal: <T extends string | number | boolean>(_lit: T): co<T> => {
33
+ return { [SchemaInit]: "json" satisfies Schema } as any;
34
+ },
35
+ json: <T extends JsonValue>(): co<T> => {
36
+ return { [SchemaInit]: "json" satisfies Schema } as any;
37
+ },
38
+ encoded: <T>(arg: Encoder<T>): co<T> => {
39
+ return { [SchemaInit]: { encoded: arg } satisfies Schema } as any;
40
+ },
41
+ ref: <C extends CoValueClass>(
42
+ arg: C | ((_raw: InstanceType<C>["_raw"]) => C)
43
+ ): co<InstanceType<C> | null> => {
44
+ return { [SchemaInit]: arg satisfies Schema } as any;
45
+ },
46
+ items: ItemsSym as ItemsSym,
9
47
  };
10
48
 
11
- export type FieldDescriptor =
12
- | PrimitiveField
13
- | RefField<CoValue>
14
- | EncodedField<any>;
49
+ export type JsonEncoded = "json";
50
+ export type EncodedAs<V> = { encoded: Encoder<V> };
51
+ export type RefEncoded<V extends CoValue> =
52
+ | CoValueClass<V>
53
+ | ((raw: RawCoValue) => CoValueClass<V>);
15
54
 
16
- export type FieldDescriptorFor<Field> = NonNullable<Field> extends CoValue
17
- ? RefField<NonNullable<Field>>
55
+ export function isRefEncoded<V extends CoValue>(
56
+ schema: Schema
57
+ ): schema is RefEncoded<V> {
58
+ return typeof schema === "function";
59
+ }
60
+
61
+ export function instantiateRefEncoded<V extends CoValue>(
62
+ schema: RefEncoded<V>,
63
+ raw: RawCoValue
64
+ ): V {
65
+ return isCoValueClass(schema)
66
+ ? schema.fromRaw(raw)
67
+ : (schema as (raw: RawCoValue) => CoValueClass<V>)(raw).fromRaw(raw);
68
+ }
69
+
70
+ export type Schema = JsonEncoded | RefEncoded<CoValue> | EncodedAs<any>;
71
+
72
+ export type SchemaFor<Field> = NonNullable<Field> extends CoValue
73
+ ? RefEncoded<NonNullable<Field>>
18
74
  : NonNullable<Field> extends JsonValue
19
- ? PrimitiveField
20
- : EncodedField<NonNullable<Field>>;
75
+ ? JsonEncoded
76
+ : EncodedAs<NonNullable<Field>>;
21
77
 
22
- export type EffectSchemaWithInputAndOutput<A, I = A> = Schema<
78
+ export type EffectSchemaWithInputAndOutput<A, I = A> = EffectSchema<
23
79
  any,
24
80
  any,
25
81
  never
@@ -38,12 +94,9 @@ export const Encoders = {
38
94
  Date,
39
95
  };
40
96
 
41
- export const indexSignature = Symbol.for("indexSignature");
42
- export type indexSignature = typeof indexSignature;
43
-
44
97
  export type EnsureCoValueNullable<
45
98
  V,
46
- Key extends string | indexSignature,
99
+ Key extends string | ItemsSym,
47
100
  > = NonNullable<V> extends CoValue
48
101
  ? null extends V
49
102
  ? V
@@ -53,17 +106,19 @@ export type EnsureCoValueNullable<
53
106
  V | null,
54
107
  ]
55
108
  : [
56
- `👋 CoMap fields that are CoValue references should be nullable, declare [indexSignature] as:`,
109
+ `👋 CoMap fields that are CoValue references should be nullable, declare _item as:`,
57
110
  V | null,
58
111
  ]
59
112
  : V;
60
113
 
61
- export type EnsureItemNullable<Item, ContainerType extends string> =
62
- NonNullable<Item> extends CoValue
63
- ? null extends Item
64
- ? any
65
- : [
66
- `👋 CoList items that are CoValue references should be nullable, make sure the Item generic parameter of ${ContainerType} is:`,
67
- Item | null
68
- ]
69
- : any;
114
+ export type ValidItem<
115
+ Item,
116
+ ContainerType extends string,
117
+ > = NonNullable<Item> extends CoValue
118
+ ? null extends Item
119
+ ? any
120
+ : [
121
+ `👋 CoList items that are CoValue references should be nullable, make sure the Item generic parameter of ${ContainerType} is:`,
122
+ Item | null,
123
+ ]
124
+ : any;
package/src/index.ts CHANGED
@@ -1,23 +1,25 @@
1
- /** @category Internal types */
2
1
  export {
2
+ /** @category Internal types */
3
3
  cojsonReady as jazzReady,
4
+ cojsonInternals,
5
+ MAX_RECOMMENDED_TX_SIZE,
6
+ } from "cojson";
7
+ export type {
4
8
  InviteSecret,
5
9
  Peer,
6
10
  SessionID,
7
11
  AgentID,
8
12
  SyncMessage,
9
- cojsonInternals,
10
- MAX_RECOMMENDED_TX_SIZE,
11
13
  } from "cojson";
12
14
 
13
- export { ID, CoValue } from "./internal.js";
15
+ export type { ID, CoValue } from "./internal.js";
14
16
 
15
- export { Encoders } from "./internal.js";
17
+ export { Encoders, co } from "./internal.js";
16
18
 
17
- export { CoMap, indexSignature } from "./internal.js";
19
+ export { CoMap } from "./internal.js";
18
20
  export { CoList } from "./internal.js";
19
21
  export { CoStream, BinaryCoStream } from "./internal.js";
20
22
  export { Group, Profile } from "./internal.js";
21
- export { Account, Me } from "./internal.js";
23
+ export { Account, type Me } from "./internal.js";
22
24
  export { ImageDefinition } from "./internal.js";
23
- export { CoValueBase, CoValueClass } from "./internal.js";
25
+ export { CoValueBase, type CoValueClass } from "./internal.js";
@@ -4,7 +4,7 @@ import { webcrypto } from "node:crypto";
4
4
  import { connectedPeers } from "cojson/src/streamUtils.js";
5
5
  import { newRandomSessionID } from "cojson/src/coValueCore.js";
6
6
  import { Effect, Queue } from "effect";
7
- import { Account, CoList, jazzReady } from "..";
7
+ import { Account, CoList, co, jazzReady } from "..";
8
8
 
9
9
  if (!("crypto" in globalThis)) {
10
10
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -20,8 +20,7 @@ describe("Simple CoList operations", async () => {
20
20
  name: "Hermes Puggington",
21
21
  });
22
22
 
23
- class TestList extends CoList<string> {}
24
- TestList.encoding({ _item: "json" });
23
+ class TestList extends CoList.Of(co.string) {}
25
24
 
26
25
  const list = new TestList(["bread", "butter", "onion"], { owner: me });
27
26
 
@@ -115,18 +114,15 @@ describe("Simple CoList operations", async () => {
115
114
  });
116
115
 
117
116
  describe("CoList resolution", async () => {
118
- class TwiceNestedList extends CoList<string> {
117
+ class TwiceNestedList extends CoList.Of(co.string) {
119
118
  joined() {
120
119
  return this.join(",");
121
120
  }
122
121
  }
123
- TwiceNestedList.encoding({ _item: "json" });
124
122
 
125
- class NestedList extends CoList<TwiceNestedList | null> {}
126
- NestedList.encoding({ _item: { ref: () => TwiceNestedList } });
123
+ class NestedList extends CoList.Of(co.ref(TwiceNestedList)) {}
127
124
 
128
- class TestList extends CoList<NestedList | null> {}
129
- TestList.encoding({ _item: { ref: () => NestedList } });
125
+ class TestList extends CoList.Of(co.ref(NestedList)) {}
130
126
 
131
127
  const initNodeAndList = async () => {
132
128
  const me = await Account.create({