jazz-tools 0.7.0-alpha.30 → 0.7.0-alpha.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/.turbo/turbo-build.log +55 -57
  2. package/CHANGELOG.md +13 -0
  3. package/dist/cli/index.js +46 -0
  4. package/dist/cli/index.js.map +1 -0
  5. package/dist/coValues/account.js +9 -6
  6. package/dist/coValues/account.js.map +1 -1
  7. package/dist/coValues/coList.js +10 -7
  8. package/dist/coValues/coList.js.map +1 -1
  9. package/dist/coValues/coMap.js +57 -3
  10. package/dist/coValues/coMap.js.map +1 -1
  11. package/dist/coValues/coStream.js +55 -4
  12. package/dist/coValues/coStream.js.map +1 -1
  13. package/dist/coValues/extensions/imageDef.js +1 -0
  14. package/dist/coValues/extensions/imageDef.js.map +1 -1
  15. package/dist/coValues/group.js +8 -2
  16. package/dist/coValues/group.js.map +1 -1
  17. package/dist/coValues/interfaces.js +10 -1
  18. package/dist/coValues/interfaces.js.map +1 -1
  19. package/dist/implementation/schema.js +3 -1
  20. package/dist/implementation/schema.js.map +1 -1
  21. package/dist/implementation/subscriptionScope.js.map +1 -1
  22. package/dist/tests/coList.test.js +13 -13
  23. package/dist/tests/coList.test.js.map +1 -1
  24. package/dist/tests/coMap.test.js +22 -22
  25. package/dist/tests/coMap.test.js.map +1 -1
  26. package/dist/tests/coStream.test.js +9 -9
  27. package/dist/tests/coStream.test.js.map +1 -1
  28. package/dist/tests/groupsAndAccounts.test.js +6 -4
  29. package/dist/tests/groupsAndAccounts.test.js.map +1 -1
  30. package/package.json +14 -8
  31. package/src/cli/index.ts +69 -0
  32. package/src/coValues/account.ts +29 -42
  33. package/src/coValues/coList.ts +24 -17
  34. package/src/coValues/coMap.ts +73 -20
  35. package/src/coValues/coStream.ts +110 -18
  36. package/src/coValues/extensions/imageDef.ts +2 -1
  37. package/src/coValues/group.ts +34 -48
  38. package/src/coValues/interfaces.ts +30 -20
  39. package/src/implementation/schema.ts +5 -1
  40. package/src/implementation/subscriptionScope.ts +2 -2
  41. package/src/tests/coList.test.ts +16 -16
  42. package/src/tests/coMap.test.ts +35 -35
  43. package/src/tests/coStream.test.ts +11 -11
  44. package/src/tests/groupsAndAccounts.test.ts +13 -9
@@ -8,9 +8,10 @@ import type {
8
8
  SchemaFor,
9
9
  ID,
10
10
  RefEncoded,
11
- SubclassedConstructor,
11
+ ClassOf,
12
12
  UnavailableError,
13
13
  IfCo,
14
+ UnCo,
14
15
  } from "../internal.js";
15
16
  import {
16
17
  Account,
@@ -27,11 +28,13 @@ import {
27
28
  } from "../internal.js";
28
29
  import { encodeSync, decodeSync } from "@effect/schema/Schema";
29
30
 
31
+ /** @category CoValues */
30
32
  export class CoList<Item = any>
31
33
  extends Array<Item>
32
34
  implements CoValue<"CoList", RawCoList>
33
35
  {
34
36
  static Of<Item>(item: IfCo<Item, Item>): typeof CoList<Item> {
37
+ // TODO: cache superclass for item class
35
38
  return class CoListOf extends CoList<Item> {
36
39
  [co.items] = item;
37
40
  };
@@ -64,6 +67,7 @@ export class CoList<Item = any>
64
67
  : Group.fromRaw(this._raw.group);
65
68
  }
66
69
 
70
+ /** @category Content */
67
71
  get _refs(): {
68
72
  [idx: number]: NonNullable<Item> extends CoValue
69
73
  ? Ref<NonNullable<Item>>
@@ -107,21 +111,16 @@ export class CoList<Item = any>
107
111
  return Array;
108
112
  }
109
113
 
110
- constructor(_init: undefined, options: { fromRaw: RawCoList });
111
- constructor(init: Item[], options: { owner: Account | Group });
112
114
  constructor(
113
- init: Item[] | undefined,
114
- options?: { owner: Account | Group } | { fromRaw: RawCoList }
115
+ options:
116
+ | { init: Item[]; owner: Account | Group }
117
+ | { fromRaw: RawCoList }
115
118
  ) {
116
119
  super();
117
120
 
118
- if (!options) {
119
- throw new Error("Must provide options");
120
- }
121
-
122
- if (init && "owner" in options) {
121
+ if ("owner" in options) {
123
122
  this[InitValues] = {
124
- init,
123
+ init: options.init,
125
124
  owner: options.owner,
126
125
  };
127
126
  } else if ("fromRaw" in options) {
@@ -137,6 +136,14 @@ export class CoList<Item = any>
137
136
  return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
138
137
  }
139
138
 
139
+ static create<L extends CoList>(
140
+ this: ClassOf<L>,
141
+ items: UnCo<L[number]>[],
142
+ options: {owner: Account | Group}
143
+ ) {
144
+ return new this({ init: items, owner: options.owner });
145
+ }
146
+
140
147
  push(...items: Item[]): number;
141
148
  /** @private For exact type compatibility with Array superclass */
142
149
  push(...items: Item[]): number;
@@ -235,29 +242,29 @@ export class CoList<Item = any>
235
242
  }
236
243
 
237
244
  static fromRaw<V extends CoList>(
238
- this: SubclassedConstructor<V> & typeof CoList,
245
+ this: ClassOf<V> & typeof CoList,
239
246
  raw: RawCoList
240
247
  ) {
241
- return new this(undefined, { fromRaw: raw });
248
+ return new this({ fromRaw: raw });
242
249
  }
243
250
 
244
251
  static loadEf = CoValueBase.loadEf as unknown as <V extends CoValue>(
245
- this: SubclassedConstructor<V>,
252
+ this: ClassOf<V>,
246
253
  id: ID<V>
247
254
  ) => Effect.Effect<V, UnavailableError, AccountCtx>;
248
255
  static load = CoValueBase.load as unknown as <V extends CoValue>(
249
- this: SubclassedConstructor<V>,
256
+ this: ClassOf<V>,
250
257
  id: ID<V>,
251
258
  options: { as: Account | Group }
252
259
  ) => Promise<V | undefined>;
253
260
  static subscribeEf = CoValueBase.subscribeEf as unknown as <
254
261
  V extends CoValue,
255
262
  >(
256
- this: SubclassedConstructor<V>,
263
+ this: ClassOf<V>,
257
264
  id: ID<V>
258
265
  ) => Stream.Stream<V, UnavailableError, AccountCtx>;
259
266
  static subscribe = CoValueBase.subscribe as unknown as <V extends CoValue>(
260
- this: SubclassedConstructor<V>,
267
+ this: ClassOf<V>,
261
268
  id: ID<V>,
262
269
  options: { as: Account | Group },
263
270
  onUpdate: (value: V) => void
@@ -9,6 +9,7 @@ import type {
9
9
  RefEncoded,
10
10
  IfCo,
11
11
  RefIfCoValue,
12
+ ClassOf,
12
13
  } from "../internal.js";
13
14
  import {
14
15
  Account,
@@ -23,11 +24,6 @@ import {
23
24
  isRefEncoded,
24
25
  } from "../internal.js";
25
26
 
26
- type DefaultFields = {
27
- [key: string]: any;
28
- [ItemsSym]?: any;
29
- };
30
-
31
27
  type CoMapEdit<V> = {
32
28
  value?: V;
33
29
  ref?: RefIfCoValue<V>;
@@ -40,24 +36,72 @@ type InitValuesFor<C extends CoMap> = {
40
36
  owner: Account | Group;
41
37
  };
42
38
 
43
- export class CoMap<Fields extends object = DefaultFields>
44
- extends CoValueBase
45
- implements CoValue<"CoMap", RawCoMap>
46
- {
39
+ /**
40
+ * CoMaps are collaborative versions of plain objects, mapping string-like keys to values.
41
+ *
42
+ * @categoryDescription Declaration
43
+ * Declare your own CoMap schemas by subclassing `CoMap` and assigning field schemas with `co`.
44
+ *
45
+ * ```ts
46
+ * import { co, CoMap } from "jazz-tools";
47
+ *
48
+ * class Person extends CoMap {
49
+ * name = co.string;
50
+ * age = co.number;
51
+ * pet = co.ref(Animal);
52
+ * }
53
+ * ```
54
+ *
55
+ * @categoryDescription Content
56
+ * You can access properties you declare on a `CoMap` (using `co`) as if they were normal properties on a plain object, using dot notation, `Object.keys()`, etc.
57
+ *
58
+ * ```ts
59
+ * person.name;
60
+ * person["age"];
61
+ * person.age = 42;
62
+ * person.pet?.name;
63
+ * Object.keys(person);
64
+ * // => ["name", "age", "pet"]
65
+ * ```
66
+ *
67
+ * @category CoValues
68
+ * */
69
+ export class CoMap extends CoValueBase implements CoValue<"CoMap", RawCoMap> {
70
+ /**
71
+ * The ID of this `CoMap`
72
+ * @category Content */
47
73
  declare id: ID<this>;
74
+ /** @category Type Helpers */
48
75
  declare _type: "CoMap";
49
76
  static {
50
77
  this.prototype._type = "CoMap";
51
78
  }
79
+ /** @category Internals */
52
80
  declare _raw: RawCoMap;
53
81
 
82
+ /** @internal */
54
83
  static _schema: any;
84
+ /** @internal */
55
85
  get _schema() {
56
86
  return (this.constructor as typeof CoMap)._schema as {
57
87
  [key: string]: Schema;
58
88
  } & { [ItemsSym]?: Schema };
59
89
  }
60
90
 
91
+ /**
92
+ * If property `prop` is a `co.ref(...)`, you can use `coMaps._refs.prop` to access
93
+ * the `Ref` instead of the potentially loaded/null value.
94
+ * This allows you to always get the ID or load the value manually.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * person._refs.pet.id; // => ID<Animal>
99
+ * person._refs.pet.value;
100
+ * // => Animal | undefined
101
+ * const pet = await person._refs.pet.load();
102
+ * ```
103
+ *
104
+ * @category Content */
61
105
  get _refs(): {
62
106
  [Key in CoKeys<this>]: IfCo<this[Key], RefIfCoValue<this[Key]>>;
63
107
  } {
@@ -80,6 +124,7 @@ export class CoMap<Fields extends object = DefaultFields>
80
124
  ) as any;
81
125
  }
82
126
 
127
+ /** @category Collaboration */
83
128
  get _edits() {
84
129
  return new Proxy(this, {
85
130
  get(target, key) {
@@ -124,26 +169,23 @@ export class CoMap<Fields extends object = DefaultFields>
124
169
  };
125
170
  }
126
171
 
172
+ /** @internal */
127
173
  get _loadedAs() {
128
174
  return Account.fromNode(this._raw.core.node);
129
175
  }
130
176
 
177
+ /** @internal */
131
178
  [InitValues]?: any;
132
179
 
133
- constructor(_init: undefined, options: { fromRaw: RawCoMap });
180
+ /** @internal */
134
181
  constructor(
135
- init: Simplify<CoMapInit<Fields>>,
136
- options: { owner: Account | Group }
137
- );
138
- constructor(
139
- init: Simplify<CoMapInit<Fields>> | undefined,
140
- options: { owner: Account | Group } | { fromRaw: RawCoMap }
182
+ options: { fromRaw: RawCoMap } | { init: any; owner: Account | Group }
141
183
  ) {
142
184
  super();
143
185
 
144
- if (init && "owner" in options) {
186
+ if ("owner" in options) {
145
187
  this[InitValues] = {
146
- init,
188
+ init: options.init,
147
189
  owner: options.owner,
148
190
  } as InitValuesFor<this>;
149
191
  } else if ("fromRaw" in options) {
@@ -161,6 +203,15 @@ export class CoMap<Fields extends object = DefaultFields>
161
203
  return new Proxy(this, CoMapProxyHandler as ProxyHandler<this>);
162
204
  }
163
205
 
206
+ /** @category Creation */
207
+ static create<M extends CoMap>(
208
+ this: ClassOf<M>,
209
+ init: Simplify<CoMapInit<M>>,
210
+ options: { owner: Account | Group }
211
+ ) {
212
+ return new this({ init, owner: options.owner });
213
+ }
214
+
164
215
  toJSON() {
165
216
  const jsonedFields = this._raw.keys().map((key) => {
166
217
  const tKey = key as CoKeys<this>;
@@ -188,6 +239,7 @@ export class CoMap<Fields extends object = DefaultFields>
188
239
  return this.toJSON();
189
240
  }
190
241
 
242
+ /** @internal */
191
243
  rawFromInit<Fields extends object = Record<string, any>>(
192
244
  init: Simplify<CoMapInit<Fields>> | undefined,
193
245
  owner: Account | Group
@@ -222,9 +274,10 @@ export class CoMap<Fields extends object = DefaultFields>
222
274
  return rawOwner.createMap(rawInit);
223
275
  }
224
276
 
277
+ /** @category Declaration */
225
278
  static Record<Value>(value: IfCo<Value, Value>) {
226
279
  // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
227
- class RecordLikeCoMap extends CoMap<RecordLikeCoMap> {
280
+ class RecordLikeCoMap extends CoMap {
228
281
  [ItemsSym] = value;
229
282
  }
230
283
  // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
@@ -236,7 +289,7 @@ export class CoMap<Fields extends object = DefaultFields>
236
289
 
237
290
  export type CoKeys<Fields extends object> = Exclude<
238
291
  keyof Fields & string,
239
- keyof CoMap<Record<string, never>>
292
+ keyof CoMap
240
293
  >;
241
294
 
242
295
  export type CoMapInit<Fields extends object> = {
@@ -8,7 +8,7 @@ import type {
8
8
  RawCoStream,
9
9
  SessionID,
10
10
  } from "cojson";
11
- import { cojsonInternals } from "cojson";
11
+ import { MAX_RECOMMENDED_TX_SIZE, cojsonInternals } from "cojson";
12
12
  import type {
13
13
  CoValue,
14
14
  Schema,
@@ -17,6 +17,8 @@ import type {
17
17
  ID,
18
18
  Me,
19
19
  IfCo,
20
+ ClassOf,
21
+ UnCo,
20
22
  } from "../internal.js";
21
23
  import {
22
24
  ItemsSym,
@@ -43,13 +45,12 @@ export type SingleCoStreamEntry<Item> = {
43
45
  tx: CojsonInternalTypes.TransactionID;
44
46
  };
45
47
 
48
+ /** @category CoValues */
46
49
  export class CoStream<Item = any>
47
50
  extends CoValueBase
48
51
  implements CoValue<"CoStream", RawCoStream>
49
52
  {
50
- static Of<Item>(
51
- item: IfCo<Item, Item>
52
- ): typeof CoStream<Item> {
53
+ static Of<Item>(item: IfCo<Item, Item>): typeof CoStream<Item> {
53
54
  return class CoStreamOf extends CoStream<Item> {
54
55
  [co.items] = item;
55
56
  };
@@ -85,11 +86,10 @@ export class CoStream<Item = any>
85
86
 
86
87
  [InitValues]?: any;
87
88
 
88
- constructor(_init: undefined, options: { fromRaw: RawCoStream });
89
- constructor(init: Item[], options: { owner: Account | Group });
90
89
  constructor(
91
- init: Item[] | undefined,
92
- options: { owner: Account | Group } | { fromRaw: RawCoStream }
90
+ options:
91
+ | { init: Item[]; owner: Account | Group }
92
+ | { fromRaw: RawCoStream }
93
93
  ) {
94
94
  super();
95
95
 
@@ -103,7 +103,7 @@ export class CoStream<Item = any>
103
103
  });
104
104
  } else {
105
105
  this[InitValues] = {
106
- init,
106
+ init: options.init,
107
107
  owner: options.owner,
108
108
  };
109
109
  }
@@ -111,6 +111,14 @@ export class CoStream<Item = any>
111
111
  return new Proxy(this, CoStreamProxyHandler as ProxyHandler<this>);
112
112
  }
113
113
 
114
+ static create<S extends CoStream>(
115
+ this: ClassOf<S>,
116
+ init: S extends CoStream<infer Item> ? UnCo<Item>[] : never,
117
+ options: { owner: Account | Group }
118
+ ) {
119
+ return new this({ init, owner: options.owner });
120
+ }
121
+
114
122
  push(...items: Item[]) {
115
123
  for (const item of items) {
116
124
  this.pushItem(item);
@@ -123,9 +131,7 @@ export class CoStream<Item = any>
123
131
  if (itemDescriptor === "json") {
124
132
  this._raw.push(item as JsonValue);
125
133
  } else if ("encoded" in itemDescriptor) {
126
- this._raw.push(
127
- encodeSync(itemDescriptor.encoded)(item)
128
- );
134
+ this._raw.push(encodeSync(itemDescriptor.encoded)(item));
129
135
  } else if (isRefEncoded(itemDescriptor)) {
130
136
  this._raw.push((item as unknown as CoValue).id);
131
137
  }
@@ -192,9 +198,7 @@ function entryFromRawEntry<Item>(
192
198
  ? (CoValue & Item) | null
193
199
  : Item;
194
200
  } else if ("encoded" in itemField) {
195
- return decodeSync(itemField.encoded)(
196
- rawEntry.value
197
- );
201
+ return decodeSync(itemField.encoded)(rawEntry.value);
198
202
  } else if (isRefEncoded(itemField)) {
199
203
  return this.ref?.accessFrom(
200
204
  accessFrom
@@ -292,7 +296,10 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
292
296
 
293
297
  return entry;
294
298
  } else if (key === "perSession") {
295
- return new Proxy({}, CoStreamPerSessionProxyHandler(target, receiver));
299
+ return new Proxy(
300
+ {},
301
+ CoStreamPerSessionProxyHandler(target, receiver)
302
+ );
296
303
  } else {
297
304
  return Reflect.get(target, key, receiver);
298
305
  }
@@ -350,7 +357,10 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
350
357
  },
351
358
  };
352
359
 
353
- const CoStreamPerSessionProxyHandler = (innerTarget: CoStream, accessFrom: CoStream): ProxyHandler<Record<string, never>> => ({
360
+ const CoStreamPerSessionProxyHandler = (
361
+ innerTarget: CoStream,
362
+ accessFrom: CoStream
363
+ ): ProxyHandler<Record<string, never>> => ({
354
364
  get(_target, key, receiver) {
355
365
  if (typeof key === "string" && key.includes("session")) {
356
366
  const sessionID = key as SessionID;
@@ -411,6 +421,7 @@ const CoStreamPerSessionProxyHandler = (innerTarget: CoStream, accessFrom: CoStr
411
421
  },
412
422
  });
413
423
 
424
+ /** @category CoValues */
414
425
  export class BinaryCoStream
415
426
  extends CoValueBase
416
427
  implements CoValue<"BinaryCoStream", RawBinaryCoStream>
@@ -420,7 +431,6 @@ export class BinaryCoStream
420
431
  declare _raw: RawBinaryCoStream;
421
432
 
422
433
  constructor(
423
- _init: [] | undefined,
424
434
  options:
425
435
  | {
426
436
  owner: Account | Group;
@@ -449,6 +459,13 @@ export class BinaryCoStream
449
459
  });
450
460
  }
451
461
 
462
+ static create<S extends BinaryCoStream>(
463
+ this: ClassOf<S>,
464
+ options: { owner: Account | Group }
465
+ ) {
466
+ return new this(options);
467
+ }
468
+
452
469
  getChunks(options?: {
453
470
  allowUnfinished?: boolean;
454
471
  }):
@@ -469,6 +486,81 @@ export class BinaryCoStream
469
486
  this._raw.endBinaryStream();
470
487
  }
471
488
 
489
+ toBlob(options?: { allowUnfinished?: boolean }): Blob | undefined {
490
+ const chunks = this.getChunks({
491
+ allowUnfinished: options?.allowUnfinished,
492
+ });
493
+
494
+ if (!chunks) {
495
+ return undefined;
496
+ }
497
+
498
+ return new Blob(chunks.chunks, { type: chunks.mimeType });
499
+ }
500
+
501
+ static async loadAsBlob(
502
+ id: ID<BinaryCoStream>,
503
+ options: {
504
+ as: Account & Me;
505
+ allowUnfinished?: boolean;
506
+ onProgress?: (progress: number) => void;
507
+ }
508
+ ): Promise<Blob | undefined> {
509
+ const stream = await this.load(id, {
510
+ as: options.as,
511
+ onProgress: options.onProgress,
512
+ });
513
+
514
+ return stream?.toBlob({
515
+ allowUnfinished: options.allowUnfinished,
516
+ });
517
+ }
518
+
519
+ static async createFromBlob(
520
+ blob: Blob | File,
521
+ options: {
522
+ owner: Group | Account;
523
+ onProgress?: (progress: number) => void;
524
+ }
525
+ ): Promise<BinaryCoStream> {
526
+ const stream = this.create({ owner: options.owner });
527
+
528
+ const start = Date.now();
529
+
530
+ const data = new Uint8Array(await blob.arrayBuffer());
531
+ stream.start({
532
+ mimeType: blob.type,
533
+ totalSizeBytes: blob.size,
534
+ fileName: blob instanceof File ? blob.name : undefined,
535
+ });
536
+ const chunkSize = MAX_RECOMMENDED_TX_SIZE;
537
+
538
+ let lastProgressUpdate = Date.now();
539
+
540
+ for (let idx = 0; idx < data.length; idx += chunkSize) {
541
+ stream.push(data.slice(idx, idx + chunkSize));
542
+
543
+ if (Date.now() - lastProgressUpdate > 100) {
544
+ options.onProgress?.(idx / data.length);
545
+ lastProgressUpdate = Date.now();
546
+ }
547
+
548
+ await new Promise((resolve) => setTimeout(resolve, 0));
549
+ }
550
+ stream.end();
551
+ const end = Date.now();
552
+
553
+ console.debug(
554
+ "Finished creating binary stream in",
555
+ (end - start) / 1000,
556
+ "s - Throughput in MB/s",
557
+ (1000 * (blob.size / (end - start))) / (1024 * 1024)
558
+ );
559
+ options.onProgress?.(1);
560
+
561
+ return stream;
562
+ }
563
+
472
564
  toJSON() {
473
565
  return {
474
566
  id: this.id,
@@ -5,7 +5,8 @@ import {
5
5
  subscriptionsScopes,
6
6
  } from "../../internal.js";
7
7
 
8
- export class ImageDefinition extends CoMap<ImageDefinition> {
8
+ /** @category Media */
9
+ export class ImageDefinition extends CoMap {
9
10
  originalSize = co.json<[number, number]>();
10
11
  placeholderDataURL? = co.string;
11
12
 
@@ -2,9 +2,9 @@ import type { AccountID, Everyone, RawGroup, Role } from "cojson";
2
2
  import type {
3
3
  CoValue,
4
4
  ID,
5
- JsonEncoded,
6
5
  RefEncoded,
7
6
  Schema,
7
+ ClassOf,
8
8
  } from "../internal.js";
9
9
  import {
10
10
  Account,
@@ -17,34 +17,13 @@ import {
17
17
  MembersSym,
18
18
  } from "../internal.js";
19
19
 
20
- export class Profile extends CoMap<{ name: co<string> }> {
20
+ /** @category Identity & Permissions */
21
+ export class Profile extends CoMap {
21
22
  name = co.string;
22
23
  }
23
24
 
24
- type GroupSchema<Def extends Group> = {
25
- profile: NonNullable<Def["profile"]> extends CoValue
26
- ? RefEncoded<NonNullable<Def["profile"]>>
27
- : JsonEncoded;
28
- root: NonNullable<Def["root"]> extends CoValue
29
- ? RefEncoded<NonNullable<Def["root"]>>
30
- : JsonEncoded;
31
- [MembersSym]: RefEncoded<NonNullable<Def[MembersSym]>>;
32
- };
33
-
34
- export class Group<
35
- Def extends {
36
- profile: Profile | null;
37
- root: CoMap | null;
38
- [MembersSym]: Account | null;
39
- } = {
40
- profile: Profile | null;
41
- root: CoMap | null;
42
- [MembersSym]: Account | null;
43
- },
44
- >
45
- extends CoValueBase
46
- implements CoValue<"Group", RawGroup>
47
- {
25
+ /** @category Identity & Permissions */
26
+ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
48
27
  declare id: ID<this>;
49
28
  declare _type: "Group";
50
29
  static {
@@ -53,7 +32,11 @@ export class Group<
53
32
  declare _raw: RawGroup;
54
33
 
55
34
  static _schema: any;
56
- get _schema(): GroupSchema<this> {
35
+ get _schema(): {
36
+ profile: Schema;
37
+ root: Schema;
38
+ [MembersSym]: RefEncoded<Account>;
39
+ } {
57
40
  return (this.constructor as typeof Group)._schema;
58
41
  }
59
42
  static {
@@ -67,19 +50,16 @@ export class Group<
67
50
  });
68
51
  }
69
52
 
70
- declare profile: Def["profile"] | null;
71
- declare root: Def["root"] | null;
72
- declare [MembersSym]: Def[MembersSym] | null;
53
+ declare profile: Profile | null;
54
+ declare root: CoMap | null;
55
+ declare [MembersSym]: Account | null;
73
56
 
74
- get _refs(): {
75
- profile: Def["profile"] extends Profile ? Ref<Def["profile"]> : never;
76
- root: Def["root"] extends CoMap ? Ref<Def["root"]> : never;
77
- } {
57
+ get _refs() {
78
58
  const profileID = this._raw.get("profile") as unknown as
79
- | ID<NonNullable<Def["profile"]>>
59
+ | ID<NonNullable<this["profile"]>>
80
60
  | undefined;
81
61
  const rootID = this._raw.get("root") as unknown as
82
- | ID<NonNullable<Def["root"]>>
62
+ | ID<NonNullable<this["root"]>>
83
63
  | undefined;
84
64
  return {
85
65
  profile:
@@ -88,33 +68,32 @@ export class Group<
88
68
  profileID,
89
69
  this._loadedAs,
90
70
  this._schema.profile as RefEncoded<
91
- NonNullable<Def["profile"]>
71
+ NonNullable<this["profile"]>
92
72
  >
93
- ) as any),
73
+ ) as any as this["profile"] extends Profile
74
+ ? Ref<this["profile"]>
75
+ : never),
94
76
  root:
95
77
  rootID &&
96
78
  (new Ref(
97
79
  rootID,
98
80
  this._loadedAs,
99
- this._schema.root as RefEncoded<NonNullable<Def["root"]>>
100
- ) as any),
81
+ this._schema.root as RefEncoded<NonNullable<this["root"]>>
82
+ ) as any as this["root"] extends CoMap
83
+ ? Ref<this["root"]>
84
+ : never),
101
85
  };
102
86
  }
103
87
 
104
- constructor(options: { owner: Account | Group });
105
- constructor(init: any, options: { fromRaw: RawGroup });
106
- constructor(init: undefined, options: { owner: Account | Group });
107
- constructor(
108
- init: undefined | { owner: Account | Group },
109
- options?: { fromRaw: RawGroup } | { owner: Account | Group }
110
- ) {
88
+ /** @deprecated Don't use constructor directly, use .create */
89
+ constructor(options: { fromRaw: RawGroup } | { owner: Account | Group }) {
111
90
  super();
112
91
  let raw: RawGroup;
113
92
 
114
93
  if (options && "fromRaw" in options) {
115
94
  raw = options.fromRaw;
116
95
  } else {
117
- const initOwner = options?.owner || init?.owner;
96
+ const initOwner = options.owner;
118
97
  if (!initOwner) throw new Error("No owner provided");
119
98
  if (
120
99
  initOwner instanceof Account &&
@@ -143,6 +122,13 @@ export class Group<
143
122
  );
144
123
  }
145
124
 
125
+ static create<G extends Group>(
126
+ this: ClassOf<G>,
127
+ options: { owner: Account }
128
+ ) {
129
+ return new this(options);
130
+ }
131
+
146
132
  myRole(): Role | undefined {
147
133
  return this._raw.myRole();
148
134
  }