jazz-tools 0.7.0-alpha.4 → 0.7.0-alpha.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. package/.eslintrc.cjs +3 -10
  2. package/.prettierrc.js +9 -0
  3. package/.turbo/turbo-build.log +3 -19
  4. package/.turbo/turbo-lint.log +4 -0
  5. package/.turbo/turbo-test.log +140 -0
  6. package/CHANGELOG.md +243 -0
  7. package/README.md +10 -2
  8. package/dist/coValues/account.js +104 -50
  9. package/dist/coValues/account.js.map +1 -1
  10. package/dist/coValues/coList.js +165 -112
  11. package/dist/coValues/coList.js.map +1 -1
  12. package/dist/coValues/coMap.js +243 -163
  13. package/dist/coValues/coMap.js.map +1 -1
  14. package/dist/coValues/coStream.js +256 -73
  15. package/dist/coValues/coStream.js.map +1 -1
  16. package/dist/coValues/deepLoading.js +57 -0
  17. package/dist/coValues/deepLoading.js.map +1 -0
  18. package/dist/coValues/extensions/imageDef.js +14 -8
  19. package/dist/coValues/extensions/imageDef.js.map +1 -1
  20. package/dist/coValues/group.js +49 -38
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/coValues/interfaces.js +66 -26
  23. package/dist/coValues/interfaces.js.map +1 -1
  24. package/dist/implementation/devtoolsFormatters.js +114 -0
  25. package/dist/implementation/devtoolsFormatters.js.map +1 -0
  26. package/dist/implementation/refs.js +60 -19
  27. package/dist/implementation/refs.js.map +1 -1
  28. package/dist/implementation/schema.js +44 -1
  29. package/dist/implementation/schema.js.map +1 -1
  30. package/dist/implementation/subscriptionScope.js +19 -1
  31. package/dist/implementation/subscriptionScope.js.map +1 -1
  32. package/dist/implementation/symbols.js +5 -0
  33. package/dist/implementation/symbols.js.map +1 -0
  34. package/dist/index.js +4 -5
  35. package/dist/index.js.map +1 -1
  36. package/dist/internal.js +4 -1
  37. package/dist/internal.js.map +1 -1
  38. package/dist/tests/coList.test.js +51 -52
  39. package/dist/tests/coList.test.js.map +1 -1
  40. package/dist/tests/coMap.test.js +196 -75
  41. package/dist/tests/coMap.test.js.map +1 -1
  42. package/dist/tests/coStream.test.js +95 -85
  43. package/dist/tests/coStream.test.js.map +1 -1
  44. package/dist/tests/deepLoading.test.js +188 -0
  45. package/dist/tests/deepLoading.test.js.map +1 -0
  46. package/dist/tests/groupsAndAccounts.test.js +83 -0
  47. package/dist/tests/groupsAndAccounts.test.js.map +1 -0
  48. package/package.json +17 -9
  49. package/src/coValues/account.ts +183 -152
  50. package/src/coValues/coList.ts +220 -173
  51. package/src/coValues/coMap.ts +322 -312
  52. package/src/coValues/coStream.ts +397 -135
  53. package/src/coValues/deepLoading.ts +215 -0
  54. package/src/coValues/extensions/imageDef.ts +16 -17
  55. package/src/coValues/group.ts +95 -111
  56. package/src/coValues/interfaces.ts +217 -115
  57. package/src/implementation/devtoolsFormatters.ts +110 -0
  58. package/src/implementation/inspect.ts +1 -1
  59. package/src/implementation/refs.ts +91 -38
  60. package/src/implementation/schema.ts +87 -46
  61. package/src/implementation/subscriptionScope.ts +44 -12
  62. package/src/implementation/symbols.ts +11 -0
  63. package/src/index.ts +13 -9
  64. package/src/internal.ts +6 -2
  65. package/src/tests/coList.test.ts +67 -66
  66. package/src/tests/coMap.test.ts +226 -123
  67. package/src/tests/coStream.test.ts +141 -131
  68. package/src/tests/deepLoading.test.ts +301 -0
  69. package/src/tests/groupsAndAccounts.test.ts +91 -0
@@ -0,0 +1,83 @@
1
+ import { expect, describe, test } from "vitest";
2
+ import { Account, CoMap, co, Group, WasmCrypto } from "../index.js";
3
+ const Crypto = await WasmCrypto.create();
4
+ describe("Custom accounts and groups", async () => {
5
+ var _a;
6
+ class CustomProfile extends CoMap {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.name = co.string;
10
+ this.color = co.string;
11
+ }
12
+ }
13
+ class CustomAccount extends Account {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.profile = co.ref(CustomProfile);
17
+ this.root = co.ref(CoMap);
18
+ }
19
+ migrate(creationProps) {
20
+ if (creationProps) {
21
+ const profileGroup = Group.create({ owner: this });
22
+ profileGroup.addMember("everyone", "reader");
23
+ this.profile = CustomProfile.create({ name: creationProps.name, color: "blue" }, { owner: this });
24
+ }
25
+ }
26
+ }
27
+ class CustomGroup extends Group {
28
+ constructor() {
29
+ super(...arguments);
30
+ this.profile = co.null;
31
+ this.root = co.null;
32
+ this[_a] = co.ref(CustomAccount);
33
+ }
34
+ get nMembers() {
35
+ return this.members.length;
36
+ }
37
+ }
38
+ _a = co.members;
39
+ test("Custom account and group", async () => {
40
+ const me = await CustomAccount.create({
41
+ creationProps: { name: "Hermes Puggington" },
42
+ crypto: Crypto,
43
+ });
44
+ expect(me.profile).toBeDefined();
45
+ expect(me.profile?.name).toBe("Hermes Puggington");
46
+ expect(me.profile?.color).toBe("blue");
47
+ const group = new CustomGroup({ owner: me });
48
+ group.addMember("everyone", "reader");
49
+ expect(group.members).toMatchObject([
50
+ { id: me.id, role: "admin" },
51
+ { id: "everyone", role: "reader" },
52
+ ]);
53
+ expect(group.nMembers).toBe(2);
54
+ await new Promise((resolve) => {
55
+ CustomGroup.subscribe(group, {}, (update) => {
56
+ const meAsMember = update.members.find((member) => {
57
+ return member.id === me.id && member.account?.profile;
58
+ });
59
+ if (meAsMember) {
60
+ expect(meAsMember.account?.profile?.name).toBe("Hermes Puggington");
61
+ expect(meAsMember.account?.profile?.color).toBe("blue");
62
+ resolve();
63
+ }
64
+ });
65
+ });
66
+ class MyMap extends CoMap {
67
+ constructor() {
68
+ super(...arguments);
69
+ this.name = co.string;
70
+ }
71
+ }
72
+ const map = MyMap.create({ name: "test" }, { owner: group });
73
+ const meAsCastMember = map._owner
74
+ .as(CustomGroup)
75
+ .members.find((member) => member.id === me.id);
76
+ expect(meAsCastMember?.account?.profile?.name).toBe("Hermes Puggington");
77
+ expect(meAsCastMember?.account?.profile?.color).toBe("blue");
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ expect(map._owner.nMembers).toBeUndefined();
80
+ expect(map._owner.as(CustomGroup).nMembers).toBe(2);
81
+ });
82
+ });
83
+ //# sourceMappingURL=groupsAndAccounts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groupsAndAccounts.test.js","sourceRoot":"","sources":["../../src/tests/groupsAndAccounts.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "jazz-tools",
3
- "module": "dist/index.js",
4
- "main": "dist/index.js",
5
- "types": "src/index.ts",
3
+ "module": "./dist/index.js",
4
+ "main": "./dist/index.js",
5
+ "types": "./src/index.ts",
6
6
  "type": "module",
7
7
  "license": "MIT",
8
- "version": "0.7.0-alpha.4",
8
+ "version": "0.7.0-alpha.41",
9
9
  "dependencies": {
10
- "@effect/schema": "^0.64.20",
11
- "effect": "^2.4.18",
12
- "cojson": "0.7.0-alpha.1"
10
+ "@effect/schema": "^0.66.16",
11
+ "effect": "^3.1.5",
12
+ "fast-check": "^3.17.2",
13
+ "cojson": "0.7.0-alpha.39",
14
+ "cojson-transport-nodejs-ws": "0.7.0-alpha.41"
13
15
  },
14
16
  "devDependencies": {
15
17
  "typescript": "^5.3.3",
@@ -22,9 +24,15 @@
22
24
  }
23
25
  }
24
26
  },
27
+ "lint-staged": {
28
+ "*.{ts,tsx}": "eslint --fix",
29
+ "*.{js,jsx,mdx,json}": "prettier --write"
30
+ },
25
31
  "scripts": {
26
- "test": "vitest",
27
- "lint": "eslint src/**/*.ts",
32
+ "test": "vitest --run",
33
+ "test-watch": "vitest",
34
+ "lint": "eslint . --ext ts,tsx",
35
+ "format": "prettier --write './src/**/*.{ts,tsx}'",
28
36
  "build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist"
29
37
  }
30
38
  }
@@ -2,6 +2,7 @@ import { LocalNode } from "cojson";
2
2
  import type {
3
3
  AgentSecret,
4
4
  CoID,
5
+ CryptoProvider,
5
6
  InviteSecret,
6
7
  Peer,
7
8
  RawAccount,
@@ -15,109 +16,100 @@ import type {
15
16
  CoMap,
16
17
  CoValue,
17
18
  CoValueClass,
18
- FieldDescriptor,
19
- Group,
19
+ Schema,
20
20
  ID,
21
- RefField,
22
- SubclassedConstructor,
23
- UnavailableError,
21
+ RefEncoded,
22
+ ClassOf,
23
+ RefIfCoValue,
24
+ } from "../internal.js";
25
+ import {
26
+ Group,
27
+ CoValueBase,
28
+ MembersSym,
29
+ Profile,
30
+ Ref,
31
+ SchemaInit,
32
+ inspect,
33
+ subscriptionsScopes,
24
34
  } from "../internal.js";
25
- import { CoValueBase, Profile, ValueRef, inspect } from "../internal.js";
26
- import type { Stream } from "effect/Stream";
27
35
 
28
- export class Account<
29
- Def extends { profile: Profile | null; root: CoMap | null } = {
30
- profile: Profile | null;
31
- root: CoMap | null;
32
- },
33
- >
36
+ /** @category Identity & Permissions */
37
+ export class Account
34
38
  extends CoValueBase
35
39
  implements CoValue<"Account", RawAccount | RawControlledAccount>
36
40
  {
37
- id!: ID<this>;
38
- _type!: "Account";
39
- _raw!: RawAccount | RawControlledAccount;
41
+ declare id: ID<this>;
42
+ declare _type: "Account";
43
+ declare _raw: RawAccount | RawControlledAccount;
40
44
 
41
- static _encoding: any;
42
- get _encoding(): {
43
- profile: FieldDescriptor;
44
- root: FieldDescriptor;
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ static _schema: any;
47
+ get _schema(): {
48
+ profile: Schema;
49
+ root: Schema;
45
50
  } {
46
- return (this.constructor as typeof Account)._encoding;
51
+ return (this.constructor as typeof Account)._schema;
47
52
  }
48
53
  static {
49
- this._encoding = {
50
- profile: { ref: () => Profile },
51
- root: { json: true },
54
+ this._schema = {
55
+ profile: () => Profile satisfies Schema,
56
+ root: "json" satisfies Schema,
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
58
  } as any;
53
59
  }
54
60
 
55
61
  get _owner(): Account {
56
62
  return this as Account;
57
63
  }
58
- get _loadedAs(): Account & Me {
64
+ get _loadedAs(): Account {
59
65
  return this.isMe
60
- ? (this as Account & Me)
66
+ ? this
61
67
  : Account.fromNode(this._raw.core.node);
62
68
  }
63
69
 
64
- profile!: NonNullable<Def["profile"]> | null;
65
- root!: NonNullable<Def["root"]> | null;
70
+ declare profile: Profile | null;
71
+ declare root: CoMap | null;
66
72
 
67
- get _refs(): {
68
- profile: NonNullable<Def["profile"]> extends Profile
69
- ? ValueRef<NonNullable<Def["profile"]>> | null
70
- : null;
71
- root: NonNullable<Def["root"]> extends CoMap
72
- ? ValueRef<NonNullable<Def["root"]>> | null
73
- : null;
74
- } {
75
- const profileID = this._raw.get("profile") as unknown as ID<
76
- NonNullable<Def["profile"]>
77
- > | undefined;
73
+ get _refs() {
74
+ const profileID = this._raw.get("profile") as unknown as
75
+ | ID<NonNullable<this["profile"]>>
76
+ | undefined;
78
77
  const rootID = this._raw.get("root") as unknown as
79
- | ID<NonNullable<Def["root"]>>
78
+ | ID<NonNullable<this["root"]>>
80
79
  | undefined;
80
+
81
81
  return {
82
- profile: profileID && (new ValueRef(
83
- profileID,
84
- this._loadedAs,
85
- (
86
- this._encoding.profile as RefField<
87
- NonNullable<Def["profile"]> & CoValue
88
- >
89
- ).ref()
90
- )) as any,
82
+ profile:
83
+ profileID &&
84
+ (new Ref(
85
+ profileID,
86
+ this._loadedAs,
87
+ this._schema.profile as RefEncoded<
88
+ NonNullable<this["profile"]> & CoValue
89
+ >,
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ ) as any as RefIfCoValue<this["profile"]>),
91
92
  root:
92
93
  rootID &&
93
- (new ValueRef(
94
+ (new Ref(
94
95
  rootID,
95
96
  this._loadedAs,
96
- (
97
- this._encoding.root as RefField<NonNullable<Def["root"]> & CoValue>
98
- ).ref()
99
- ) as any),
97
+ this._schema.root as RefEncoded<
98
+ NonNullable<this["root"]> & CoValue
99
+ >,
100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
+ ) as any as RefIfCoValue<this["root"]>),
100
102
  };
101
103
  }
102
104
 
103
105
  isMe: boolean;
104
106
  sessionID: SessionID | undefined;
105
107
 
106
- constructor(init: undefined, options: { owner: Group | Account });
107
- constructor(
108
- init: undefined,
109
- options: { fromRaw: RawAccount | RawControlledAccount }
110
- );
111
- constructor(
112
- init: undefined,
113
- options:
114
- | { fromRaw: RawAccount | RawControlledAccount }
115
- | { owner: Group | Account }
116
- ) {
108
+ constructor(options: { fromRaw: RawAccount | RawControlledAccount }) {
117
109
  super();
118
110
  if (!("fromRaw" in options)) {
119
111
  throw new Error(
120
- "Can only construct account from raw or with .create()"
112
+ "Can only construct account from raw or with .create()",
121
113
  );
122
114
  }
123
115
  this.isMe = options.fromRaw.id == options.fromRaw.core.node.account.id;
@@ -128,40 +120,18 @@ export class Account<
128
120
  enumerable: false,
129
121
  },
130
122
  _raw: { value: options.fromRaw, enumerable: false },
131
- profile: {
132
- get: () => {
133
- const ref = this._refs.profile;
134
- return ref ? ref.accessFrom(this) : (undefined as any);
135
- },
136
- set: (value: Def["profile"] | null) => {
137
- if (value) {
138
- this._raw.set(
139
- "profile",
140
- value.id as unknown as CoID<RawCoMap>
141
- );
142
- }
143
- },
144
- },
145
- root: {
146
- get: () => {
147
- const ref = this._refs.root;
148
- return ref ? ref.accessFrom(this) : (undefined as any);
149
- },
150
- set: (value: Def["root"] | null) => {
151
- if (value) {
152
- this._raw.set(
153
- "root",
154
- value.id as unknown as CoID<RawCoMap>
155
- );
156
- }
157
- },
158
- },
123
+ _type: { value: "Account", enumerable: false },
159
124
  });
160
125
 
161
126
  if (this.isMe) {
162
- (this as Account & Me).sessionID =
127
+ this.sessionID =
163
128
  options.fromRaw.core.node.currentSessionID;
164
129
  }
130
+
131
+ return new Proxy(
132
+ this,
133
+ AccountAndGroupProxyHandler as ProxyHandler<this>,
134
+ );
165
135
  }
166
136
 
167
137
  myRole(): "admin" | undefined {
@@ -170,88 +140,89 @@ export class Account<
170
140
  }
171
141
  }
172
142
 
173
- acceptInvite:
174
- | (<V extends CoValue>(
175
- valueID: ID<V>,
176
- inviteSecret: InviteSecret,
177
- coValueClass: CoValueClass<V>
178
- ) => Promise<V | undefined>)
179
- | undefined = (async <V extends CoValue>(
143
+ async acceptInvite <V extends CoValue>(
180
144
  valueID: ID<V>,
181
145
  inviteSecret: InviteSecret,
182
- coValueClass: CoValueClass<V>
183
- ) => {
146
+ coValueClass: CoValueClass<V>,
147
+ ) {
184
148
  if (!this.isMe) {
185
149
  throw new Error("Only a controlled account can accept invites");
186
150
  }
187
151
 
188
152
  await (this._raw as RawControlledAccount).acceptInvite(
189
153
  valueID as unknown as CoID<RawCoValue>,
190
- inviteSecret
154
+ inviteSecret,
191
155
  );
192
156
 
193
- return coValueClass.load(valueID, {
194
- as: this as Account & Me,
195
- });
196
- }) as any;
157
+ return coValueClass.load(
158
+ valueID,
159
+ this as Account,
160
+ [],
161
+ );
162
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
163
+ }
197
164
 
198
165
  static async create<A extends Account>(
199
- this: SubclassedConstructor<A> & typeof Account,
166
+ this: ClassOf<A> & typeof Account,
200
167
  options: {
201
- name: string;
168
+ creationProps: { name: string };
202
169
  initialAgentSecret?: AgentSecret;
203
170
  peersToLoadFrom?: Peer[];
204
- }
205
- ): Promise<A & Me> {
171
+ crypto: CryptoProvider;
172
+ },
173
+ ): Promise<A> {
206
174
  const { node } = await LocalNode.withNewlyCreatedAccount({
207
175
  ...options,
208
- migration: async (rawAccount) => {
209
- const account = new this(undefined, {
176
+ migration: async (rawAccount, _node, creationProps) => {
177
+ const account = new this({
210
178
  fromRaw: rawAccount,
211
- }) as A & Me;
179
+ }) as A;
212
180
 
213
- await account.migrate?.();
181
+ await account.migrate?.(creationProps);
214
182
  },
215
183
  });
216
184
 
217
- return this.fromNode(node) as A & Me;
185
+ return this.fromNode(node) as A;
218
186
  }
219
187
 
220
188
  static async become<A extends Account>(
221
- this: SubclassedConstructor<A> & typeof Account,
189
+ this: ClassOf<A> & typeof Account,
222
190
  options: {
223
191
  accountID: ID<Account>;
224
192
  accountSecret: AgentSecret;
225
193
  sessionID: SessionID;
226
194
  peersToLoadFrom: Peer[];
227
- }
228
- ): Promise<A & Me> {
195
+ crypto: CryptoProvider;
196
+ },
197
+ ): Promise<A> {
229
198
  const node = await LocalNode.withLoadedAccount({
230
199
  accountID: options.accountID as unknown as CoID<RawAccount>,
231
200
  accountSecret: options.accountSecret,
232
201
  sessionID: options.sessionID,
233
202
  peersToLoadFrom: options.peersToLoadFrom,
234
- migration: async (rawAccount) => {
235
- const account = new this(undefined, {
203
+ crypto: options.crypto,
204
+ migration: async (rawAccount, _node, creationProps) => {
205
+ const account = new this({
236
206
  fromRaw: rawAccount,
237
- }) as A & Me;
207
+ }) as A;
238
208
 
239
- await account.migrate?.();
209
+ await account.migrate?.(creationProps);
240
210
  },
241
211
  });
242
212
 
243
- return this.fromNode(node) as A & Me;
213
+ return this.fromNode(node) as A;
244
214
  }
245
215
 
246
216
  static fromNode<A extends Account>(
247
- this: SubclassedConstructor<A>,
248
- node: LocalNode
249
- ): A & Me {
250
- return new this(undefined, {
217
+ this: ClassOf<A>,
218
+ node: LocalNode,
219
+ ): A {
220
+ return new this({
251
221
  fromRaw: node.account as RawControlledAccount,
252
- }) as A & Me;
222
+ }) as A;
253
223
  }
254
224
 
225
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
255
226
  toJSON(): object | any[] {
256
227
  return {
257
228
  id: this.id,
@@ -263,35 +234,95 @@ export class Account<
263
234
  return this.toJSON();
264
235
  }
265
236
 
266
- static encoding<V extends Account>(
267
- this: { new (...args: any[]): V } & CoValueClass<V> & { _encoding: any },
268
- fields: {
269
- profile: V["_encoding"]["profile"];
270
- root: V["_encoding"]["root"];
237
+ migrate(creationProps?: { name: string }): void | Promise<void> {
238
+ if (creationProps) {
239
+ const profileGroup = Group.create({ owner: this });
240
+ profileGroup.addMember("everyone", "reader");
241
+ this.profile = Profile.create(
242
+ { name: creationProps.name },
243
+ { owner: profileGroup },
244
+ );
271
245
  }
272
- ) {
273
- this._encoding ||= {};
274
- Object.assign(this._encoding, fields);
275
246
  }
276
-
277
- migrate: (() => void | Promise<void>) | undefined;
278
247
  }
279
248
 
280
- export interface Me {
281
- id: ID<any>;
282
- isMe: true;
283
- _raw: RawControlledAccount;
284
- sessionID: SessionID;
285
- subscribe(listener: (update: this & Me) => void): () => void;
286
- subscribeEf(): Stream<this & Me, UnavailableError, never>;
287
- acceptInvite: (...args: any[]) => any;
288
- }
249
+ export const AccountAndGroupProxyHandler: ProxyHandler<Account | Group> = {
250
+ get(target, key, receiver) {
251
+ if (key === "profile") {
252
+ const ref = target._refs.profile;
253
+ return ref
254
+ ? ref.accessFrom(receiver, "profile")
255
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
+ (undefined as any);
257
+ } else if (key === "root") {
258
+ const ref = target._refs.root;
259
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
260
+ return ref ? ref.accessFrom(receiver, "root") : (undefined as any);
261
+ } else {
262
+ return Reflect.get(target, key, receiver);
263
+ }
264
+ },
265
+ set(target, key, value, receiver) {
266
+ if (
267
+ (key === "profile" || key === "root" || key === MembersSym) &&
268
+ typeof value === "object" &&
269
+ SchemaInit in value
270
+ ) {
271
+ (target.constructor as typeof CoMap)._schema ||= {};
272
+ (target.constructor as typeof CoMap)._schema[key] =
273
+ value[SchemaInit];
274
+ return true;
275
+ } else if (key === "profile") {
276
+ if (value) {
277
+ target._raw.set(
278
+ "profile",
279
+ value.id as unknown as CoID<RawCoMap>,
280
+ "trusting",
281
+ );
282
+ }
283
+ subscriptionsScopes
284
+ .get(receiver)
285
+ ?.onRefAccessedOrSet(target.id, value.id);
286
+ return true;
287
+ } else if (key === "root") {
288
+ if (value) {
289
+ target._raw.set("root", value.id as unknown as CoID<RawCoMap>);
290
+ }
291
+ subscriptionsScopes
292
+ .get(receiver)
293
+ ?.onRefAccessedOrSet(target.id, value.id);
294
+ return true;
295
+ } else {
296
+ return Reflect.set(target, key, value, receiver);
297
+ }
298
+ },
299
+ defineProperty(target, key, descriptor) {
300
+ if (
301
+ (key === "profile" || key === "root" || key === MembersSym) &&
302
+ typeof descriptor.value === "object" &&
303
+ SchemaInit in descriptor.value
304
+ ) {
305
+ (target.constructor as typeof CoMap)._schema ||= {};
306
+ (target.constructor as typeof CoMap)._schema[key] =
307
+ descriptor.value[SchemaInit];
308
+ return true;
309
+ } else {
310
+ return Reflect.defineProperty(target, key, descriptor);
311
+ }
312
+ },
313
+ };
289
314
 
315
+ /** @category Identity & Permissions */
290
316
  export class AccountCtx extends Context.Tag("Account")<
291
317
  AccountCtx,
292
- Account & Me
318
+ Account
293
319
  >() {}
294
320
 
295
- export function isControlledAccount(account: Account): account is Account & Me {
321
+ /** @category Identity & Permissions */
322
+ export function isControlledAccount(account: Account): account is Account & {
323
+ isMe: true;
324
+ sessionID: SessionID;
325
+ _raw: RawControlledAccount;
326
+ } {
296
327
  return account.isMe;
297
328
  }