jazz-tools 0.7.1 → 0.7.3
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 +15 -0
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +33 -33
- package/CHANGELOG.md +171 -165
- package/LICENSE.txt +1 -1
- package/dist/coValues/account.js +30 -3
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +29 -5
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +25 -1
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +49 -1
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/group.js +25 -1
- package/dist/coValues/group.js.map +1 -1
- package/dist/coValues/interfaces.js +32 -48
- package/dist/coValues/interfaces.js.map +1 -1
- package/dist/implementation/schema.js.map +1 -1
- package/dist/implementation/subscriptionScope.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tests/deepLoading.test.js +2 -2
- package/dist/tests/deepLoading.test.js.map +1 -1
- package/dist/tests/groupsAndAccounts.test.js +3 -3
- package/dist/tests/groupsAndAccounts.test.js.map +1 -1
- package/package.json +1 -1
- package/src/coValues/account.ts +82 -12
- package/src/coValues/coList.ts +78 -13
- package/src/coValues/coMap.ts +78 -7
- package/src/coValues/coStream.ts +128 -11
- package/src/coValues/group.ts +77 -4
- package/src/coValues/interfaces.ts +140 -211
- package/src/implementation/schema.ts +7 -4
- package/src/implementation/subscriptionScope.ts +3 -3
- package/src/index.ts +7 -0
- package/src/tests/deepLoading.test.ts +6 -3
- package/src/tests/groupsAndAccounts.test.ts +4 -4
package/src/coValues/group.ts
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
import type { AccountID, Everyone, RawGroup, Role } from "cojson";
|
2
|
-
import type {
|
2
|
+
import type {
|
3
|
+
CoValue,
|
4
|
+
ID,
|
5
|
+
RefEncoded,
|
6
|
+
Schema,
|
7
|
+
AccountCtx,
|
8
|
+
CoValueClass,
|
9
|
+
DeeplyLoaded,
|
10
|
+
DepthsIn,
|
11
|
+
UnavailableError,
|
12
|
+
} from "../internal.js";
|
3
13
|
import {
|
4
14
|
Account,
|
5
15
|
CoMap,
|
@@ -9,7 +19,14 @@ import {
|
|
9
19
|
isControlledAccount,
|
10
20
|
AccountAndGroupProxyHandler,
|
11
21
|
MembersSym,
|
22
|
+
loadCoValue,
|
23
|
+
loadCoValueEf,
|
24
|
+
subscribeToCoValue,
|
25
|
+
subscribeToCoValueEf,
|
26
|
+
ensureCoValueLoaded,
|
27
|
+
subscribeToExistingCoValue,
|
12
28
|
} from "../internal.js";
|
29
|
+
import { Effect, Stream } from "effect";
|
13
30
|
|
14
31
|
/** @category Identity & Permissions */
|
15
32
|
export class Profile extends CoMap {
|
@@ -17,7 +34,7 @@ export class Profile extends CoMap {
|
|
17
34
|
}
|
18
35
|
|
19
36
|
/** @category Identity & Permissions */
|
20
|
-
export class Group extends CoValueBase implements CoValue
|
37
|
+
export class Group extends CoValueBase implements CoValue {
|
21
38
|
declare id: ID<this>;
|
22
39
|
declare _type: "Group";
|
23
40
|
static {
|
@@ -41,7 +58,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
41
58
|
[MembersSym]: {
|
42
59
|
ref: () => Account,
|
43
60
|
optional: false,
|
44
|
-
} satisfies
|
61
|
+
} satisfies RefEncoded<Account>,
|
45
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
46
63
|
} as any;
|
47
64
|
Object.defineProperty(this.prototype, "_schema", {
|
@@ -124,7 +141,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
124
141
|
}
|
125
142
|
|
126
143
|
static create<G extends Group>(
|
127
|
-
this:
|
144
|
+
this: CoValueClass<G>,
|
128
145
|
options: { owner: Account },
|
129
146
|
) {
|
130
147
|
return new this(options);
|
@@ -170,4 +187,60 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
170
187
|
};
|
171
188
|
});
|
172
189
|
}
|
190
|
+
|
191
|
+
/** @category Subscription & Loading */
|
192
|
+
static load<G extends Group, Depth>(
|
193
|
+
this: CoValueClass<G>,
|
194
|
+
id: ID<G>,
|
195
|
+
as: Account,
|
196
|
+
depth: Depth & DepthsIn<G>,
|
197
|
+
): Promise<DeeplyLoaded<G, Depth> | undefined> {
|
198
|
+
return loadCoValue(this, id, as, depth);
|
199
|
+
}
|
200
|
+
|
201
|
+
/** @category Subscription & Loading */
|
202
|
+
static loadEf<G extends Group, Depth>(
|
203
|
+
this: CoValueClass<G>,
|
204
|
+
id: ID<G>,
|
205
|
+
depth: Depth & DepthsIn<G>,
|
206
|
+
): Effect.Effect<DeeplyLoaded<G, Depth>, UnavailableError, AccountCtx> {
|
207
|
+
return loadCoValueEf<G, Depth>(this, id, depth);
|
208
|
+
}
|
209
|
+
|
210
|
+
/** @category Subscription & Loading */
|
211
|
+
static subscribe<G extends Group, Depth>(
|
212
|
+
this: CoValueClass<G>,
|
213
|
+
id: ID<G>,
|
214
|
+
as: Account,
|
215
|
+
depth: Depth & DepthsIn<G>,
|
216
|
+
listener: (value: DeeplyLoaded<G, Depth>) => void,
|
217
|
+
): () => void {
|
218
|
+
return subscribeToCoValue<G, Depth>(this, id, as, depth, listener);
|
219
|
+
}
|
220
|
+
|
221
|
+
/** @category Subscription & Loading */
|
222
|
+
static subscribeEf<G extends Group, Depth>(
|
223
|
+
this: CoValueClass<G>,
|
224
|
+
id: ID<G>,
|
225
|
+
depth: Depth & DepthsIn<G>,
|
226
|
+
): Stream.Stream<DeeplyLoaded<G, Depth>, UnavailableError, AccountCtx> {
|
227
|
+
return subscribeToCoValueEf<G, Depth>(this, id, depth);
|
228
|
+
}
|
229
|
+
|
230
|
+
/** @category Subscription & Loading */
|
231
|
+
ensureLoaded<G extends Group, Depth>(
|
232
|
+
this: G,
|
233
|
+
depth: Depth & DepthsIn<G>,
|
234
|
+
): Promise<DeeplyLoaded<G, Depth> | undefined> {
|
235
|
+
return ensureCoValueLoaded(this, depth);
|
236
|
+
}
|
237
|
+
|
238
|
+
/** @category Subscription & Loading */
|
239
|
+
subscribe<G extends Group, Depth>(
|
240
|
+
this: G,
|
241
|
+
depth: Depth & DepthsIn<G>,
|
242
|
+
listener: (value: DeeplyLoaded<G, Depth>) => void,
|
243
|
+
): () => void {
|
244
|
+
return subscribeToExistingCoValue(this, depth, listener);
|
245
|
+
}
|
173
246
|
}
|
@@ -13,74 +13,29 @@ import {
|
|
13
13
|
} from "../internal.js";
|
14
14
|
import { fulfillsDepth } from "./deepLoading.js";
|
15
15
|
|
16
|
-
export type ClassOf<T> = {
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
18
|
-
new (...args: any[]): T;
|
19
|
-
};
|
20
|
-
|
21
16
|
/** @category Abstract interfaces */
|
22
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
23
|
-
export interface CoValueClass<Value extends CoValue = CoValue
|
24
|
-
new (init: Init, options: { owner: Account | Group }): Value;
|
25
|
-
|
18
|
+
export interface CoValueClass<Value extends CoValue = CoValue> {
|
26
19
|
/** @ignore */
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
load<V extends Value, Depth>(
|
31
|
-
this: ClassOf<V>,
|
32
|
-
id: ID<V>,
|
33
|
-
as: Account,
|
34
|
-
depth: Depth & DepthsIn<V>,
|
35
|
-
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
36
|
-
/** @category Subscription & Loading */
|
37
|
-
load<V extends Value, Depth>(
|
38
|
-
this: ClassOf<V>,
|
39
|
-
existing: V,
|
40
|
-
depth: Depth & DepthsIn<V>,
|
41
|
-
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
42
|
-
|
43
|
-
/** @category Subscription & Loading */
|
44
|
-
loadEf<V extends Value, Depth>(
|
45
|
-
this: ClassOf<V>,
|
46
|
-
id: ID<V>,
|
47
|
-
depth: Depth & DepthsIn<V>,
|
48
|
-
): Effect.Effect<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx>;
|
49
|
-
|
50
|
-
/** @category Subscription & Loading */
|
51
|
-
subscribe<V extends Value, Depth>(
|
52
|
-
this: ClassOf<V>,
|
53
|
-
id: ID<V>,
|
54
|
-
as: Account,
|
55
|
-
depth: Depth & DepthsIn<V>,
|
56
|
-
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
57
|
-
): () => void;
|
58
|
-
subscribe<V extends Value, Depth>(
|
59
|
-
this: ClassOf<V>,
|
60
|
-
existing: V,
|
61
|
-
depth: Depth & DepthsIn<V>,
|
62
|
-
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
63
|
-
): () => void;
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
21
|
+
new (...args: any[]): Value;
|
22
|
+
}
|
64
23
|
|
65
|
-
|
66
|
-
|
67
|
-
this: ClassOf<V>,
|
68
|
-
id: ID<V>,
|
69
|
-
depth: Depth & DepthsIn<V>,
|
70
|
-
): Stream.Stream<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx>;
|
24
|
+
export interface CoValueFromRaw<V extends CoValue> {
|
25
|
+
fromRaw(raw: V["_raw"]): V;
|
71
26
|
}
|
72
27
|
|
73
28
|
/** @category Abstract interfaces */
|
74
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
75
|
-
export interface CoValue
|
30
|
+
export interface CoValue {
|
76
31
|
/** @category Content */
|
77
32
|
readonly id: ID<this>;
|
78
33
|
/** @category Type Helpers */
|
79
|
-
_type:
|
34
|
+
_type: string;
|
80
35
|
/** @category Collaboration */
|
81
36
|
_owner: Account | Group;
|
82
37
|
/** @category Internals */
|
83
|
-
_raw:
|
38
|
+
_raw: RawCoValue;
|
84
39
|
/** @internal */
|
85
40
|
readonly _loadedAs: Account;
|
86
41
|
/** @category Stringifying & Inspection */
|
@@ -96,8 +51,10 @@ export function isCoValue(value: any): value is CoValue {
|
|
96
51
|
return value && value._type !== undefined;
|
97
52
|
}
|
98
53
|
|
99
|
-
|
100
|
-
|
54
|
+
export function isCoValueClass<V extends CoValue>(
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
56
|
+
value: any,
|
57
|
+
): value is CoValueClass<V> & CoValueFromRaw<V> {
|
101
58
|
return typeof value === "function" && value.fromRaw !== undefined;
|
102
59
|
}
|
103
60
|
|
@@ -142,156 +99,13 @@ export class CoValueBase implements CoValue {
|
|
142
99
|
}
|
143
100
|
|
144
101
|
/** @category Internals */
|
145
|
-
static fromRaw<V extends CoValue>(
|
102
|
+
static fromRaw<V extends CoValue>(
|
103
|
+
this: CoValueClass<V>,
|
104
|
+
raw: RawCoValue,
|
105
|
+
): V {
|
146
106
|
return new this({ fromRaw: raw });
|
147
107
|
}
|
148
108
|
|
149
|
-
/** @category Subscription & Loading */
|
150
|
-
static load<V extends CoValue, Depth>(
|
151
|
-
this: ClassOf<V> & typeof CoValueBase,
|
152
|
-
id: ID<V>,
|
153
|
-
as: Account,
|
154
|
-
depth: Depth & DepthsIn<V>,
|
155
|
-
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
156
|
-
/** @category Subscription & Loading */
|
157
|
-
static load<V extends CoValue, Depth>(
|
158
|
-
this: ClassOf<V> & typeof CoValueBase,
|
159
|
-
existing: V,
|
160
|
-
depth: Depth & DepthsIn<V>,
|
161
|
-
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
162
|
-
static load<V extends CoValue, Depth>(
|
163
|
-
this: ClassOf<V> & typeof CoValueBase,
|
164
|
-
|
165
|
-
...args:
|
166
|
-
| [ID<V>, Account, Depth & DepthsIn<V>]
|
167
|
-
| [V, Depth & DepthsIn<V>]
|
168
|
-
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
169
|
-
const { id, as, depth } =
|
170
|
-
args.length === 3
|
171
|
-
? { id: args[0], as: args[1], depth: args[2] }
|
172
|
-
: { id: args[0].id, as: args[0]._loadedAs, depth: args[1] };
|
173
|
-
return Effect.runPromise(
|
174
|
-
this.loadEf(id, depth).pipe(
|
175
|
-
Effect.mapError(() => undefined),
|
176
|
-
Effect.merge,
|
177
|
-
Effect.provideService(AccountCtx, as),
|
178
|
-
),
|
179
|
-
);
|
180
|
-
}
|
181
|
-
|
182
|
-
/** @category Subscription & Loading */
|
183
|
-
static loadEf<V extends CoValue, Depth>(
|
184
|
-
this: ClassOf<V> & typeof CoValueBase,
|
185
|
-
id: ID<V>,
|
186
|
-
depth: Depth & DepthsIn<V>,
|
187
|
-
): Effect.Effect<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
188
|
-
return this.subscribeEf(id, depth).pipe(
|
189
|
-
Stream.runHead,
|
190
|
-
Effect.andThen(
|
191
|
-
Effect.mapError((_noSuchElem) => "unavailable" as const),
|
192
|
-
),
|
193
|
-
);
|
194
|
-
}
|
195
|
-
|
196
|
-
/** @category Subscription & Loading */
|
197
|
-
static subscribe<V extends CoValue, Depth>(
|
198
|
-
this: ClassOf<V> & typeof CoValueBase,
|
199
|
-
id: ID<V>,
|
200
|
-
as: Account,
|
201
|
-
depth: Depth & DepthsIn<V>,
|
202
|
-
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
203
|
-
): () => void;
|
204
|
-
static subscribe<V extends CoValue, Depth>(
|
205
|
-
this: ClassOf<V> & typeof CoValueBase,
|
206
|
-
existing: V,
|
207
|
-
depth: Depth & DepthsIn<V>,
|
208
|
-
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
209
|
-
): () => void;
|
210
|
-
static subscribe<V extends CoValue, Depth>(
|
211
|
-
this: ClassOf<V> & typeof CoValueBase,
|
212
|
-
...args:
|
213
|
-
| [
|
214
|
-
ID<V>,
|
215
|
-
Account,
|
216
|
-
Depth & DepthsIn<V>,
|
217
|
-
(value: DeeplyLoaded<V, Depth>) => void,
|
218
|
-
]
|
219
|
-
| [V, Depth & DepthsIn<V>, (value: DeeplyLoaded<V, Depth>) => void]
|
220
|
-
): () => void {
|
221
|
-
const { id, as, depth, listener } =
|
222
|
-
args.length === 4
|
223
|
-
? {
|
224
|
-
id: args[0],
|
225
|
-
as: args[1],
|
226
|
-
depth: args[2],
|
227
|
-
listener: args[3],
|
228
|
-
}
|
229
|
-
: {
|
230
|
-
id: args[0].id,
|
231
|
-
as: args[0]._loadedAs,
|
232
|
-
depth: args[1],
|
233
|
-
listener: args[2],
|
234
|
-
};
|
235
|
-
void Effect.runPromise(
|
236
|
-
Effect.provideService(
|
237
|
-
this.subscribeEf(id, depth).pipe(
|
238
|
-
Stream.run(
|
239
|
-
Sink.forEach((update) =>
|
240
|
-
Effect.sync(() => listener(update)),
|
241
|
-
),
|
242
|
-
),
|
243
|
-
),
|
244
|
-
AccountCtx,
|
245
|
-
as,
|
246
|
-
),
|
247
|
-
);
|
248
|
-
|
249
|
-
return function unsubscribe() {};
|
250
|
-
}
|
251
|
-
|
252
|
-
/** @category Subscription & Loading */
|
253
|
-
static subscribeEf<V extends CoValue, Depth>(
|
254
|
-
this: ClassOf<V> & typeof CoValueBase,
|
255
|
-
id: ID<V>,
|
256
|
-
depth: Depth & DepthsIn<V>,
|
257
|
-
): Stream.Stream<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
258
|
-
return AccountCtx.pipe(
|
259
|
-
Effect.andThen((account) =>
|
260
|
-
new Ref(id, account, {
|
261
|
-
ref: this as CoValueClass<V>,
|
262
|
-
optional: false,
|
263
|
-
}).loadEf(),
|
264
|
-
),
|
265
|
-
Stream.fromEffect,
|
266
|
-
Stream.flatMap((value: V) =>
|
267
|
-
Stream.asyncScoped<V, UnavailableError>((emit) =>
|
268
|
-
Effect.gen(this, function* (_) {
|
269
|
-
const subscription = new SubscriptionScope(
|
270
|
-
value,
|
271
|
-
this,
|
272
|
-
(update) => void emit.single(update as V),
|
273
|
-
);
|
274
|
-
|
275
|
-
yield* _(
|
276
|
-
Effect.addFinalizer(() =>
|
277
|
-
Effect.sync(() =>
|
278
|
-
subscription.unsubscribeAll(),
|
279
|
-
),
|
280
|
-
),
|
281
|
-
);
|
282
|
-
}),
|
283
|
-
),
|
284
|
-
),
|
285
|
-
Stream.filterMap((update: V) =>
|
286
|
-
Option.fromNullable(
|
287
|
-
fulfillsDepth(depth, update)
|
288
|
-
? (update as DeeplyLoaded<V, Depth>)
|
289
|
-
: undefined,
|
290
|
-
),
|
291
|
-
),
|
292
|
-
);
|
293
|
-
}
|
294
|
-
|
295
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
296
110
|
toJSON(): object | any[] {
|
297
111
|
return {
|
@@ -305,13 +119,128 @@ export class CoValueBase implements CoValue {
|
|
305
119
|
return this.toJSON();
|
306
120
|
}
|
307
121
|
|
308
|
-
/** @category Type Helpers*/
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
subscriptionsScopes.set(cast, subScope);
|
314
|
-
}
|
315
|
-
return cast;
|
122
|
+
/** @category Type Helpers */
|
123
|
+
castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
|
124
|
+
cl: Cl,
|
125
|
+
): InstanceType<Cl> {
|
126
|
+
return cl.fromRaw(this._raw) as InstanceType<Cl>;
|
316
127
|
}
|
317
128
|
}
|
129
|
+
|
130
|
+
export function loadCoValue<V extends CoValue, Depth>(
|
131
|
+
cls: CoValueClass<V>,
|
132
|
+
id: ID<V>,
|
133
|
+
as: Account,
|
134
|
+
depth: Depth & DepthsIn<V>,
|
135
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
136
|
+
return Effect.runPromise(
|
137
|
+
loadCoValueEf(cls, id, depth).pipe(
|
138
|
+
Effect.mapError(() => undefined),
|
139
|
+
Effect.merge,
|
140
|
+
Effect.provideService(AccountCtx, as),
|
141
|
+
),
|
142
|
+
);
|
143
|
+
}
|
144
|
+
|
145
|
+
export function ensureCoValueLoaded<V extends CoValue, Depth>(
|
146
|
+
existing: V,
|
147
|
+
depth: Depth & DepthsIn<V>,
|
148
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
149
|
+
return loadCoValue(
|
150
|
+
existing.constructor as CoValueClass<V>,
|
151
|
+
existing.id,
|
152
|
+
existing._loadedAs,
|
153
|
+
depth,
|
154
|
+
);
|
155
|
+
}
|
156
|
+
|
157
|
+
export function loadCoValueEf<V extends CoValue, Depth>(
|
158
|
+
cls: CoValueClass<V>,
|
159
|
+
id: ID<V>,
|
160
|
+
depth: Depth & DepthsIn<V>,
|
161
|
+
): Effect.Effect<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
162
|
+
return subscribeToCoValueEf(cls, id, depth).pipe(
|
163
|
+
Stream.runHead,
|
164
|
+
Effect.andThen(
|
165
|
+
Effect.mapError((_noSuchElem) => "unavailable" as const),
|
166
|
+
),
|
167
|
+
);
|
168
|
+
}
|
169
|
+
|
170
|
+
export function subscribeToCoValue<V extends CoValue, Depth>(
|
171
|
+
cls: CoValueClass<V>,
|
172
|
+
id: ID<V>,
|
173
|
+
as: Account,
|
174
|
+
depth: Depth & DepthsIn<V>,
|
175
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
176
|
+
): () => void {
|
177
|
+
void Effect.runPromise(
|
178
|
+
Effect.provideService(
|
179
|
+
subscribeToCoValueEf(cls, id, depth).pipe(
|
180
|
+
Stream.run(
|
181
|
+
Sink.forEach((update) =>
|
182
|
+
Effect.sync(() => listener(update)),
|
183
|
+
),
|
184
|
+
),
|
185
|
+
),
|
186
|
+
AccountCtx,
|
187
|
+
as,
|
188
|
+
),
|
189
|
+
);
|
190
|
+
|
191
|
+
return function unsubscribe() {};
|
192
|
+
}
|
193
|
+
|
194
|
+
export function subscribeToExistingCoValue<V extends CoValue, Depth>(
|
195
|
+
existing: V,
|
196
|
+
depth: Depth & DepthsIn<V>,
|
197
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
198
|
+
): () => void {
|
199
|
+
return subscribeToCoValue(
|
200
|
+
existing.constructor as CoValueClass<V>,
|
201
|
+
existing.id,
|
202
|
+
existing._loadedAs,
|
203
|
+
depth,
|
204
|
+
listener,
|
205
|
+
);
|
206
|
+
}
|
207
|
+
|
208
|
+
export function subscribeToCoValueEf<V extends CoValue, Depth>(
|
209
|
+
cls: CoValueClass<V>,
|
210
|
+
id: ID<V>,
|
211
|
+
depth: Depth & DepthsIn<V>,
|
212
|
+
): Stream.Stream<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
213
|
+
return AccountCtx.pipe(
|
214
|
+
Effect.andThen((account) =>
|
215
|
+
new Ref(id, account, {
|
216
|
+
ref: cls,
|
217
|
+
optional: false,
|
218
|
+
}).loadEf(),
|
219
|
+
),
|
220
|
+
Stream.fromEffect,
|
221
|
+
Stream.flatMap((value: V) =>
|
222
|
+
Stream.asyncScoped<V, UnavailableError>((emit) =>
|
223
|
+
Effect.gen(function* (_) {
|
224
|
+
const subscription = new SubscriptionScope(
|
225
|
+
value,
|
226
|
+
cls as CoValueClass<V> & CoValueFromRaw<V>,
|
227
|
+
(update) => void emit.single(update as V),
|
228
|
+
);
|
229
|
+
|
230
|
+
yield* _(
|
231
|
+
Effect.addFinalizer(() =>
|
232
|
+
Effect.sync(() => subscription.unsubscribeAll()),
|
233
|
+
),
|
234
|
+
);
|
235
|
+
}),
|
236
|
+
),
|
237
|
+
),
|
238
|
+
Stream.filterMap((update: V) =>
|
239
|
+
Option.fromNullable(
|
240
|
+
fulfillsDepth(depth, update)
|
241
|
+
? (update as DeeplyLoaded<V, Depth>)
|
242
|
+
: undefined,
|
243
|
+
),
|
244
|
+
),
|
245
|
+
);
|
246
|
+
}
|
@@ -3,6 +3,7 @@ import {
|
|
3
3
|
type CoValue,
|
4
4
|
type CoValueClass,
|
5
5
|
isCoValueClass,
|
6
|
+
CoValueFromRaw,
|
6
7
|
} from "../internal.js";
|
7
8
|
import type { Schema as EffectSchema, TypeId } from "@effect/schema/Schema";
|
8
9
|
|
@@ -96,11 +97,13 @@ export function instantiateRefEncoded<V extends CoValue>(
|
|
96
97
|
schema: RefEncoded<V>,
|
97
98
|
raw: RawCoValue,
|
98
99
|
): V {
|
99
|
-
return isCoValueClass(schema.ref)
|
100
|
+
return isCoValueClass<V>(schema.ref)
|
100
101
|
? schema.ref.fromRaw(raw)
|
101
|
-
: (
|
102
|
-
|
103
|
-
|
102
|
+
: (
|
103
|
+
schema.ref as (
|
104
|
+
raw: RawCoValue,
|
105
|
+
) => CoValueClass<V> & CoValueFromRaw<V>
|
106
|
+
)(raw).fromRaw(raw);
|
104
107
|
}
|
105
108
|
|
106
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -2,9 +2,9 @@ import type { RawCoValue } from "cojson";
|
|
2
2
|
import type {
|
3
3
|
Account,
|
4
4
|
CoValue,
|
5
|
-
CoValueBase,
|
6
5
|
ID,
|
7
|
-
|
6
|
+
CoValueClass,
|
7
|
+
CoValueFromRaw,
|
8
8
|
} from "../internal.js";
|
9
9
|
|
10
10
|
export const subscriptionsScopes = new WeakMap<
|
@@ -35,7 +35,7 @@ export class SubscriptionScope<Root extends CoValue> {
|
|
35
35
|
|
36
36
|
constructor(
|
37
37
|
root: Root,
|
38
|
-
rootSchema:
|
38
|
+
rootSchema: CoValueClass<Root> & CoValueFromRaw<Root>,
|
39
39
|
onUpdate: (newRoot: Root) => void,
|
40
40
|
) {
|
41
41
|
this.rootEntry = {
|
package/src/index.ts
CHANGED
@@ -25,3 +25,10 @@ export { Account, isControlledAccount } from "./internal.js";
|
|
25
25
|
export { ImageDefinition } from "./internal.js";
|
26
26
|
export { CoValueBase, type CoValueClass } from "./internal.js";
|
27
27
|
export type { DepthsIn, DeeplyLoaded } from "./internal.js";
|
28
|
+
|
29
|
+
export {
|
30
|
+
loadCoValue,
|
31
|
+
loadCoValueEf,
|
32
|
+
subscribeToCoValue,
|
33
|
+
subscribeToCoValueEf,
|
34
|
+
} from "./internal.js";
|
@@ -180,7 +180,10 @@ class CustomAccount extends Account {
|
|
180
180
|
profile = co.ref(CustomProfile);
|
181
181
|
root = co.ref(TestMap);
|
182
182
|
|
183
|
-
async migrate(
|
183
|
+
async migrate(
|
184
|
+
this: CustomAccount,
|
185
|
+
creationProps?: { name: string } | undefined,
|
186
|
+
) {
|
184
187
|
if (creationProps) {
|
185
188
|
this.profile = CustomProfile.create(
|
186
189
|
{
|
@@ -195,7 +198,7 @@ class CustomAccount extends Account {
|
|
195
198
|
);
|
196
199
|
}
|
197
200
|
|
198
|
-
const thisLoaded = await
|
201
|
+
const thisLoaded = await this.ensureLoaded({
|
199
202
|
profile: { stream: [] },
|
200
203
|
root: { list: [] },
|
201
204
|
});
|
@@ -219,7 +222,7 @@ test("Deep loading within account", async () => {
|
|
219
222
|
crypto: Crypto,
|
220
223
|
});
|
221
224
|
|
222
|
-
const meLoaded = await
|
225
|
+
const meLoaded = await me.ensureLoaded({
|
223
226
|
profile: { stream: [] },
|
224
227
|
root: { list: [] },
|
225
228
|
});
|
@@ -13,7 +13,7 @@ describe("Custom accounts and groups", async () => {
|
|
13
13
|
profile = co.ref(CustomProfile);
|
14
14
|
root = co.ref(CoMap);
|
15
15
|
|
16
|
-
migrate(creationProps?: { name: string }) {
|
16
|
+
migrate(this: CustomAccount, creationProps?: { name: string }) {
|
17
17
|
if (creationProps) {
|
18
18
|
const profileGroup = Group.create({ owner: this });
|
19
19
|
profileGroup.addMember("everyone", "reader");
|
@@ -56,7 +56,7 @@ describe("Custom accounts and groups", async () => {
|
|
56
56
|
expect(group.nMembers).toBe(2);
|
57
57
|
|
58
58
|
await new Promise<void>((resolve) => {
|
59
|
-
|
59
|
+
group.subscribe({}, (update) => {
|
60
60
|
const meAsMember = update.members.find((member) => {
|
61
61
|
return member.id === me.id && member.account?.profile;
|
62
62
|
});
|
@@ -77,7 +77,7 @@ describe("Custom accounts and groups", async () => {
|
|
77
77
|
const map = MyMap.create({ name: "test" }, { owner: group });
|
78
78
|
|
79
79
|
const meAsCastMember = map._owner
|
80
|
-
.
|
80
|
+
.castAs(CustomGroup)
|
81
81
|
.members.find((member) => member.id === me.id);
|
82
82
|
expect(meAsCastMember?.account?.profile?.name).toBe(
|
83
83
|
"Hermes Puggington",
|
@@ -86,6 +86,6 @@ describe("Custom accounts and groups", async () => {
|
|
86
86
|
|
87
87
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
88
88
|
expect((map._owner as any).nMembers).toBeUndefined();
|
89
|
-
expect(map._owner.
|
89
|
+
expect(map._owner.castAs(CustomGroup).nMembers).toBe(2);
|
90
90
|
});
|
91
91
|
});
|