jazz-tools 0.7.0-alpha.37 → 0.7.0-alpha.38
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.cjs +3 -10
- package/.prettierrc.js +9 -0
- package/.turbo/turbo-build.log +1 -95
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +140 -0
- package/CHANGELOG.md +11 -0
- package/README.md +10 -2
- package/dist/coValues/account.js +22 -12
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +7 -9
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +11 -3
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +15 -8
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/deepLoading.js +57 -0
- package/dist/coValues/deepLoading.js.map +1 -0
- package/dist/coValues/extensions/imageDef.js +1 -1
- package/dist/coValues/extensions/imageDef.js.map +1 -1
- package/dist/coValues/group.js +1 -0
- package/dist/coValues/group.js.map +1 -1
- package/dist/coValues/interfaces.js +34 -28
- package/dist/coValues/interfaces.js.map +1 -1
- package/dist/implementation/devtoolsFormatters.js +1 -0
- package/dist/implementation/devtoolsFormatters.js.map +1 -1
- package/dist/implementation/refs.js +4 -2
- package/dist/implementation/refs.js.map +1 -1
- package/dist/implementation/schema.js +5 -1
- package/dist/implementation/schema.js.map +1 -1
- package/dist/implementation/subscriptionScope.js +9 -4
- package/dist/implementation/subscriptionScope.js.map +1 -1
- package/dist/implementation/symbols.js.map +1 -1
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/tests/coList.test.js +20 -17
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/coMap.test.js +27 -17
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coStream.test.js +39 -24
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/deepLoading.test.js +188 -0
- package/dist/tests/deepLoading.test.js.map +1 -0
- package/dist/tests/groupsAndAccounts.test.js +6 -11
- package/dist/tests/groupsAndAccounts.test.js.map +1 -1
- package/package.json +12 -6
- package/src/coValues/account.ts +60 -58
- package/src/coValues/coList.ts +31 -51
- package/src/coValues/coMap.ts +27 -21
- package/src/coValues/coStream.ts +44 -32
- package/src/coValues/deepLoading.ts +215 -0
- package/src/coValues/extensions/imageDef.ts +3 -3
- package/src/coValues/group.ts +11 -13
- package/src/coValues/interfaces.ts +151 -93
- package/src/implementation/devtoolsFormatters.ts +1 -0
- package/src/implementation/inspect.ts +1 -1
- package/src/implementation/refs.ts +29 -15
- package/src/implementation/schema.ts +21 -6
- package/src/implementation/subscriptionScope.ts +33 -17
- package/src/implementation/symbols.ts +0 -1
- package/src/index.ts +5 -3
- package/src/internal.ts +3 -2
- package/src/tests/coList.test.ts +33 -28
- package/src/tests/coMap.test.ts +63 -55
- package/src/tests/coStream.test.ts +82 -67
- package/src/tests/deepLoading.test.ts +301 -0
- package/src/tests/groupsAndAccounts.test.ts +9 -18
@@ -0,0 +1,215 @@
|
|
1
|
+
import { SessionID } from "cojson";
|
2
|
+
import {
|
3
|
+
Account,
|
4
|
+
CoList,
|
5
|
+
CoStream,
|
6
|
+
CoStreamEntry,
|
7
|
+
ItemsSym,
|
8
|
+
Ref,
|
9
|
+
UnCo,
|
10
|
+
} from "../internal.js";
|
11
|
+
import { CoKeys } from "./coMap.js";
|
12
|
+
import { CoValue, ID } from "./interfaces.js";
|
13
|
+
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
15
|
+
export function fulfillsDepth(depth: any, value: CoValue): boolean {
|
16
|
+
if (
|
17
|
+
value._type === "CoMap" ||
|
18
|
+
value._type === "Group" ||
|
19
|
+
value._type === "Account"
|
20
|
+
) {
|
21
|
+
if (Array.isArray(depth) && depth.length === 1) {
|
22
|
+
return Object.entries(value).every(([key, item]) => {
|
23
|
+
return (
|
24
|
+
value as unknown as {
|
25
|
+
_refs: { [key: string]: Ref<CoValue> | undefined };
|
26
|
+
}
|
27
|
+
)._refs[key]
|
28
|
+
? item && fulfillsDepth(depth[0], item)
|
29
|
+
: true;
|
30
|
+
});
|
31
|
+
} else {
|
32
|
+
for (const key of Object.keys(depth)) {
|
33
|
+
const map = value as unknown as {
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
35
|
+
[key: string]: any;
|
36
|
+
_refs: { [key: string]: Ref<CoValue> | undefined };
|
37
|
+
};
|
38
|
+
if (!map._refs[key]) {
|
39
|
+
continue;
|
40
|
+
}
|
41
|
+
if (!map[key]) {
|
42
|
+
return false;
|
43
|
+
}
|
44
|
+
if (!fulfillsDepth(depth[key], map[key])) {
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
return true;
|
49
|
+
}
|
50
|
+
} else if (value._type === "CoList") {
|
51
|
+
if (depth.length === 0) {
|
52
|
+
return true;
|
53
|
+
} else {
|
54
|
+
const itemDepth = depth[0];
|
55
|
+
return (value as CoList).every((item, i) =>
|
56
|
+
(value as CoList)._refs[i]
|
57
|
+
? item && fulfillsDepth(itemDepth, item)
|
58
|
+
: true,
|
59
|
+
);
|
60
|
+
}
|
61
|
+
} else if (value._type === "CoStream") {
|
62
|
+
if (depth.length === 0) {
|
63
|
+
return true;
|
64
|
+
} else {
|
65
|
+
const itemDepth = depth[0];
|
66
|
+
return Object.values((value as CoStream).perSession).every(
|
67
|
+
(entry) => entry.value && fulfillsDepth(itemDepth, entry.value),
|
68
|
+
);
|
69
|
+
}
|
70
|
+
} else if (value._type === "BinaryCoStream") {
|
71
|
+
return true;
|
72
|
+
} else {
|
73
|
+
console.error(value);
|
74
|
+
throw new Error("Unexpected value type: " + value._type);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
type UnCoNotNull<T> = UnCo<Exclude<T, null>>;
|
79
|
+
type Clean<T> = UnCo<NonNullable<T>>;
|
80
|
+
|
81
|
+
export type DepthsIn<
|
82
|
+
V,
|
83
|
+
DepthLimit extends number = 5,
|
84
|
+
CurrentDepth extends number[] = [],
|
85
|
+
> =
|
86
|
+
| (DepthLimit extends CurrentDepth["length"]
|
87
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
88
|
+
any
|
89
|
+
: // Basically V extends CoList - but if we used that we'd introduce circularity into the definition of CoList itself
|
90
|
+
V extends Array<infer Item>
|
91
|
+
?
|
92
|
+
| [
|
93
|
+
DepthsIn<
|
94
|
+
UnCoNotNull<Item>,
|
95
|
+
DepthLimit,
|
96
|
+
[0, ...CurrentDepth]
|
97
|
+
>,
|
98
|
+
]
|
99
|
+
| never[]
|
100
|
+
: // Basically V extends CoMap | Group | Account - but if we used that we'd introduce circularity into the definition of CoMap itself
|
101
|
+
V extends { _type: "CoMap" | "Group" | "Account" }
|
102
|
+
?
|
103
|
+
| {
|
104
|
+
[Key in CoKeys<V> as Clean<V[Key]> extends CoValue
|
105
|
+
? Key
|
106
|
+
: never]?: DepthsIn<
|
107
|
+
Clean<V[Key]>,
|
108
|
+
DepthLimit,
|
109
|
+
[0, ...CurrentDepth]
|
110
|
+
>;
|
111
|
+
}
|
112
|
+
| (ItemsSym extends keyof V
|
113
|
+
? [
|
114
|
+
DepthsIn<
|
115
|
+
Clean<V[ItemsSym]>,
|
116
|
+
DepthLimit,
|
117
|
+
[0, ...CurrentDepth]
|
118
|
+
>,
|
119
|
+
]
|
120
|
+
: never)
|
121
|
+
| never[]
|
122
|
+
: V extends {
|
123
|
+
_type: "CoStream";
|
124
|
+
byMe: CoStreamEntry<infer Item> | undefined;
|
125
|
+
}
|
126
|
+
?
|
127
|
+
| [
|
128
|
+
DepthsIn<
|
129
|
+
UnCoNotNull<Item>,
|
130
|
+
DepthLimit,
|
131
|
+
[0, ...CurrentDepth]
|
132
|
+
>,
|
133
|
+
]
|
134
|
+
| never[]
|
135
|
+
: never[])
|
136
|
+
| never[];
|
137
|
+
|
138
|
+
export type DeeplyLoaded<
|
139
|
+
V,
|
140
|
+
Depth,
|
141
|
+
DepthLimit extends number = 5,
|
142
|
+
CurrentDepth extends number[] = [],
|
143
|
+
> = DepthLimit extends CurrentDepth["length"]
|
144
|
+
? V
|
145
|
+
: // Basically V extends CoList - but if we used that we'd introduce circularity into the definition of CoList itself
|
146
|
+
[V] extends [Array<infer Item>]
|
147
|
+
? Depth extends never[] // []
|
148
|
+
? V
|
149
|
+
: UnCoNotNull<Item> extends CoValue
|
150
|
+
? Depth extends Array<infer ItemDepth> // [item-depth]
|
151
|
+
? (UnCoNotNull<Item> &
|
152
|
+
DeeplyLoaded<
|
153
|
+
UnCoNotNull<Item>,
|
154
|
+
ItemDepth,
|
155
|
+
DepthLimit,
|
156
|
+
[0, ...CurrentDepth]
|
157
|
+
>)[] &
|
158
|
+
V
|
159
|
+
: never
|
160
|
+
: V
|
161
|
+
: // Basically V extends CoMap | Group | Account - but if we used that we'd introduce circularity into the definition of CoMap itself
|
162
|
+
[V] extends [{ _type: "CoMap" | "Group" | "Account" }]
|
163
|
+
? Depth extends never[]
|
164
|
+
? V
|
165
|
+
: Depth extends Array<infer ItemDepth>
|
166
|
+
? ItemsSym extends keyof V
|
167
|
+
? V & {
|
168
|
+
[key: string]: DeeplyLoaded<
|
169
|
+
Clean<V[ItemsSym]>,
|
170
|
+
ItemDepth,
|
171
|
+
DepthLimit,
|
172
|
+
[0, ...CurrentDepth]
|
173
|
+
>;
|
174
|
+
}
|
175
|
+
: never
|
176
|
+
: keyof Depth extends never
|
177
|
+
? V
|
178
|
+
: {
|
179
|
+
[Key in keyof Depth]-?: Key extends CoKeys<V>
|
180
|
+
? Clean<V[Key]> extends CoValue
|
181
|
+
?
|
182
|
+
| DeeplyLoaded<
|
183
|
+
Clean<V[Key]>,
|
184
|
+
Depth[Key],
|
185
|
+
DepthLimit,
|
186
|
+
[0, ...CurrentDepth]
|
187
|
+
>
|
188
|
+
| (undefined extends V[Key]
|
189
|
+
? undefined
|
190
|
+
: never)
|
191
|
+
: never
|
192
|
+
: never;
|
193
|
+
} & V
|
194
|
+
: [V] extends [
|
195
|
+
{
|
196
|
+
_type: "CoStream";
|
197
|
+
byMe: CoStreamEntry<infer Item> | undefined;
|
198
|
+
},
|
199
|
+
]
|
200
|
+
? Depth extends never[]
|
201
|
+
? V
|
202
|
+
: V & {
|
203
|
+
byMe?: { value: UnCoNotNull<Item> };
|
204
|
+
inCurrentSession?: { value: UnCoNotNull<Item> };
|
205
|
+
perSession: {
|
206
|
+
[key: SessionID]: { value: UnCoNotNull<Item> };
|
207
|
+
};
|
208
|
+
} & { [key: ID<Account>]: { value: UnCoNotNull<Item> } }
|
209
|
+
: [V] extends [
|
210
|
+
{
|
211
|
+
_type: "BinaryCoStream";
|
212
|
+
},
|
213
|
+
]
|
214
|
+
? V
|
215
|
+
: never;
|
@@ -18,15 +18,15 @@ export class ImageDefinition extends CoMap {
|
|
18
18
|
}): { res: `${number}x${number}`; stream: BinaryCoStream } | undefined {
|
19
19
|
if (!subscriptionsScopes.get(this)) {
|
20
20
|
console.warn(
|
21
|
-
"highestResAvailable() only makes sense when used within a subscription."
|
21
|
+
"highestResAvailable() only makes sense when used within a subscription.",
|
22
22
|
);
|
23
23
|
}
|
24
24
|
|
25
25
|
const resolutions = Object.keys(this).filter(
|
26
26
|
(key) =>
|
27
27
|
key.match(/^\d+x\d+$/) &&
|
28
|
-
(
|
29
|
-
Number(key.split("x")[0]) <= options.maxWidth)
|
28
|
+
(options?.maxWidth === undefined ||
|
29
|
+
Number(key.split("x")[0]) <= options.maxWidth),
|
30
30
|
) as `${number}x${number}`[];
|
31
31
|
|
32
32
|
resolutions.sort((a, b) => {
|
package/src/coValues/group.ts
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
import type { AccountID, Everyone, RawGroup, Role } from "cojson";
|
2
|
-
import type {
|
3
|
-
CoValue,
|
4
|
-
ID,
|
5
|
-
RefEncoded,
|
6
|
-
Schema,
|
7
|
-
ClassOf,
|
8
|
-
} from "../internal.js";
|
2
|
+
import type { CoValue, ID, RefEncoded, Schema, ClassOf } from "../internal.js";
|
9
3
|
import {
|
10
4
|
Account,
|
11
5
|
CoMap,
|
@@ -31,6 +25,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
31
25
|
}
|
32
26
|
declare _raw: RawGroup;
|
33
27
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
34
29
|
static _schema: any;
|
35
30
|
get _schema(): {
|
36
31
|
profile: Schema;
|
@@ -44,6 +39,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
44
39
|
profile: "json" satisfies Schema,
|
45
40
|
root: "json" satisfies Schema,
|
46
41
|
[MembersSym]: () => Account satisfies Schema,
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
47
43
|
} as any;
|
48
44
|
Object.defineProperty(this.prototype, "_schema", {
|
49
45
|
get: () => this._schema,
|
@@ -69,7 +65,8 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
69
65
|
this._loadedAs,
|
70
66
|
this._schema.profile as RefEncoded<
|
71
67
|
NonNullable<this["profile"]>
|
72
|
-
|
68
|
+
>,
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
73
70
|
) as any as this["profile"] extends Profile
|
74
71
|
? Ref<this["profile"]>
|
75
72
|
: never),
|
@@ -78,7 +75,8 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
78
75
|
(new Ref(
|
79
76
|
rootID,
|
80
77
|
this._loadedAs,
|
81
|
-
this._schema.root as RefEncoded<NonNullable<this["root"]
|
78
|
+
this._schema.root as RefEncoded<NonNullable<this["root"]>>,
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
82
80
|
) as any as this["root"] extends CoMap
|
83
81
|
? Ref<this["root"]>
|
84
82
|
: never),
|
@@ -103,7 +101,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
103
101
|
raw = rawOwner.createGroup();
|
104
102
|
} else {
|
105
103
|
throw new Error(
|
106
|
-
"Can only construct group as a controlled account"
|
104
|
+
"Can only construct group as a controlled account",
|
107
105
|
);
|
108
106
|
}
|
109
107
|
}
|
@@ -118,13 +116,13 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
118
116
|
|
119
117
|
return new Proxy(
|
120
118
|
this,
|
121
|
-
AccountAndGroupProxyHandler as ProxyHandler<this
|
119
|
+
AccountAndGroupProxyHandler as ProxyHandler<this>,
|
122
120
|
);
|
123
121
|
}
|
124
122
|
|
125
123
|
static create<G extends Group>(
|
126
124
|
this: ClassOf<G>,
|
127
|
-
options: { owner: Account }
|
125
|
+
options: { owner: Account },
|
128
126
|
) {
|
129
127
|
return new this(options);
|
130
128
|
}
|
@@ -155,7 +153,7 @@ export class Group extends CoValueBase implements CoValue<"Group", RawGroup> {
|
|
155
153
|
new Ref<NonNullable<this[MembersSym]>>(
|
156
154
|
accountID,
|
157
155
|
this._loadedAs,
|
158
|
-
this._schema[MembersSym]
|
156
|
+
this._schema[MembersSym],
|
159
157
|
);
|
160
158
|
const accessRef = () => ref?.accessFrom(this, "members." + id);
|
161
159
|
|
@@ -1,7 +1,11 @@
|
|
1
|
-
import { Effect, Sink, Stream } from "effect";
|
1
|
+
import { Effect, Option, Sink, Stream } from "effect";
|
2
2
|
import type { CojsonInternalTypes, RawCoValue } from "cojson";
|
3
3
|
import { RawAccount } from "cojson";
|
4
|
-
import type {
|
4
|
+
import type {
|
5
|
+
DeeplyLoaded,
|
6
|
+
DepthsIn,
|
7
|
+
UnavailableError,
|
8
|
+
} from "../internal.js";
|
5
9
|
import {
|
6
10
|
Account,
|
7
11
|
AccountCtx,
|
@@ -11,52 +15,67 @@ import {
|
|
11
15
|
inspect,
|
12
16
|
subscriptionsScopes,
|
13
17
|
} from "../internal.js";
|
18
|
+
import { fulfillsDepth } from "./deepLoading.js";
|
14
19
|
|
15
20
|
export type ClassOf<T> = {
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
16
22
|
new (...args: any[]): T;
|
17
23
|
};
|
18
24
|
|
19
25
|
/** @category Abstract interfaces */
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
20
27
|
export interface CoValueClass<Value extends CoValue = CoValue, Init = any> {
|
21
|
-
/** @category Construction and loading */
|
22
28
|
new (init: Init, options: { owner: Account | Group }): Value;
|
23
29
|
|
24
30
|
/** @ignore */
|
25
31
|
fromRaw(raw: Value["_raw"]): Value;
|
26
32
|
|
27
|
-
/** @category
|
28
|
-
load<V extends Value>(
|
33
|
+
/** @category Subscription & Loading */
|
34
|
+
load<V extends Value, Depth>(
|
29
35
|
this: ClassOf<V>,
|
30
36
|
id: ID<V>,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
as: Account,
|
38
|
+
depth: Depth & DepthsIn<V>,
|
39
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
40
|
+
/** @category Subscription & Loading */
|
41
|
+
load<V extends Value, Depth>(
|
42
|
+
this: ClassOf<V>,
|
43
|
+
existing: V,
|
44
|
+
depth: Depth & DepthsIn<V>,
|
45
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
36
46
|
|
37
|
-
/** @category
|
38
|
-
loadEf<V extends Value>(
|
47
|
+
/** @category Subscription & Loading */
|
48
|
+
loadEf<V extends Value, Depth>(
|
39
49
|
this: ClassOf<V>,
|
40
|
-
id: ID<V
|
41
|
-
|
50
|
+
id: ID<V>,
|
51
|
+
depth: Depth & DepthsIn<V>,
|
52
|
+
): Effect.Effect<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx>;
|
42
53
|
|
43
|
-
/** @category Subscription */
|
44
|
-
subscribe<V extends Value,
|
54
|
+
/** @category Subscription & Loading */
|
55
|
+
subscribe<V extends Value, Depth>(
|
45
56
|
this: ClassOf<V>,
|
46
57
|
id: ID<V>,
|
47
|
-
|
48
|
-
|
58
|
+
as: Account,
|
59
|
+
depth: Depth & DepthsIn<V>,
|
60
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
61
|
+
): () => void;
|
62
|
+
subscribe<V extends Value, Depth>(
|
63
|
+
this: ClassOf<V>,
|
64
|
+
existing: V,
|
65
|
+
depth: Depth & DepthsIn<V>,
|
66
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
49
67
|
): () => void;
|
50
68
|
|
51
|
-
/** @category Subscription */
|
52
|
-
subscribeEf<V extends Value>(
|
69
|
+
/** @category Subscription & Loading */
|
70
|
+
subscribeEf<V extends Value, Depth>(
|
53
71
|
this: ClassOf<V>,
|
54
72
|
id: ID<V>,
|
55
|
-
|
56
|
-
): Stream.Stream<V, UnavailableError, AccountCtx>;
|
73
|
+
depth: Depth & DepthsIn<V>,
|
74
|
+
): Stream.Stream<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx>;
|
57
75
|
}
|
58
76
|
|
59
77
|
/** @category Abstract interfaces */
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
60
79
|
export interface CoValue<Type extends string = string, Raw = any> {
|
61
80
|
/** @category Content */
|
62
81
|
readonly id: ID<this>;
|
@@ -64,23 +83,24 @@ export interface CoValue<Type extends string = string, Raw = any> {
|
|
64
83
|
_type: Type;
|
65
84
|
/** @category Collaboration */
|
66
85
|
_owner: Account | Group;
|
67
|
-
/** @category Subscription & Loading */
|
68
|
-
subscribe(listener: (update: this) => void, options?: RequireOptions<this>): () => void;
|
69
|
-
/** @category Subscription & Loading */
|
70
|
-
subscribeEf(): Stream.Stream<this, UnavailableError, never>;
|
71
86
|
/** @category Internals */
|
72
87
|
_raw: Raw;
|
73
88
|
/** @internal */
|
74
|
-
readonly _loadedAs: Account
|
89
|
+
readonly _loadedAs: Account;
|
75
90
|
/** @category Stringifying & Inspection */
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
76
92
|
toJSON(): any[] | object;
|
77
93
|
/** @category Stringifying & Inspection */
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
78
95
|
[inspect](): any;
|
79
96
|
}
|
80
97
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
81
99
|
export function isCoValue(value: any): value is CoValue {
|
82
100
|
return value && value._type !== undefined;
|
83
101
|
}
|
102
|
+
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
84
104
|
export function isCoValueClass(value: any): value is CoValueClass {
|
85
105
|
return typeof value === "function" && value.fromRaw !== undefined;
|
86
106
|
}
|
@@ -117,6 +137,7 @@ export class CoValueBase implements CoValue {
|
|
117
137
|
return Account.fromNode(this._raw.core.node);
|
118
138
|
}
|
119
139
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
120
141
|
constructor(..._args: any) {
|
121
142
|
Object.defineProperty(this, "_instanceID", {
|
122
143
|
value: `instance-${Math.random().toString(36).slice(2)}`,
|
@@ -130,108 +151,149 @@ export class CoValueBase implements CoValue {
|
|
130
151
|
}
|
131
152
|
|
132
153
|
/** @category Subscription & Loading */
|
133
|
-
static
|
154
|
+
static load<V extends CoValue, Depth>(
|
134
155
|
this: ClassOf<V> & typeof CoValueBase,
|
135
|
-
id: ID<V
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
156
|
+
id: ID<V>,
|
157
|
+
as: Account,
|
158
|
+
depth: Depth & DepthsIn<V>,
|
159
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
160
|
+
/** @category Subscription & Loading */
|
161
|
+
static load<V extends CoValue, Depth>(
|
162
|
+
this: ClassOf<V> & typeof CoValueBase,
|
163
|
+
existing: V,
|
164
|
+
depth: Depth & DepthsIn<V>,
|
165
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined>;
|
166
|
+
static load<V extends CoValue, Depth>(
|
167
|
+
this: ClassOf<V> & typeof CoValueBase,
|
168
|
+
|
169
|
+
...args:
|
170
|
+
| [ID<V>, Account, Depth & DepthsIn<V>]
|
171
|
+
| [V, Depth & DepthsIn<V>]
|
172
|
+
): Promise<DeeplyLoaded<V, Depth> | undefined> {
|
173
|
+
const { id, as, depth } =
|
174
|
+
args.length === 3
|
175
|
+
? { id: args[0], as: args[1], depth: args[2] }
|
176
|
+
: { id: args[0].id, as: args[0]._loadedAs, depth: args[1] };
|
177
|
+
return Effect.runPromise(
|
178
|
+
this.loadEf(id, depth).pipe(
|
179
|
+
Effect.mapError(() => undefined),
|
180
|
+
Effect.merge,
|
181
|
+
Effect.provideService(AccountCtx, as),
|
182
|
+
),
|
183
|
+
);
|
143
184
|
}
|
144
185
|
|
145
186
|
/** @category Subscription & Loading */
|
146
|
-
static
|
187
|
+
static loadEf<V extends CoValue, Depth>(
|
147
188
|
this: ClassOf<V> & typeof CoValueBase,
|
148
189
|
id: ID<V>,
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
190
|
+
depth: Depth & DepthsIn<V>,
|
191
|
+
): Effect.Effect<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
192
|
+
return this.subscribeEf(id, depth).pipe(
|
193
|
+
Stream.runHead,
|
194
|
+
Effect.andThen(
|
195
|
+
Effect.mapError((_noSuchElem) => "unavailable" as const),
|
196
|
+
),
|
156
197
|
);
|
157
198
|
}
|
158
199
|
|
159
200
|
/** @category Subscription & Loading */
|
160
|
-
static subscribe<V extends CoValue,
|
201
|
+
static subscribe<V extends CoValue, Depth>(
|
161
202
|
this: ClassOf<V> & typeof CoValueBase,
|
162
203
|
id: ID<V>,
|
163
|
-
|
164
|
-
|
204
|
+
as: Account,
|
205
|
+
depth: Depth & DepthsIn<V>,
|
206
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
207
|
+
): () => void;
|
208
|
+
static subscribe<V extends CoValue, Depth>(
|
209
|
+
this: ClassOf<V> & typeof CoValueBase,
|
210
|
+
existing: V,
|
211
|
+
depth: Depth & DepthsIn<V>,
|
212
|
+
listener: (value: DeeplyLoaded<V, Depth>) => void,
|
213
|
+
): () => void;
|
214
|
+
static subscribe<V extends CoValue, Depth>(
|
215
|
+
this: ClassOf<V> & typeof CoValueBase,
|
216
|
+
...args:
|
217
|
+
| [
|
218
|
+
ID<V>,
|
219
|
+
Account,
|
220
|
+
Depth & DepthsIn<V>,
|
221
|
+
(value: DeeplyLoaded<V, Depth>) => void,
|
222
|
+
]
|
223
|
+
| [V, Depth & DepthsIn<V>, (value: DeeplyLoaded<V, Depth>) => void]
|
165
224
|
): () => void {
|
225
|
+
const { id, as, depth, listener } =
|
226
|
+
args.length === 4
|
227
|
+
? {
|
228
|
+
id: args[0],
|
229
|
+
as: args[1],
|
230
|
+
depth: args[2],
|
231
|
+
listener: args[3],
|
232
|
+
}
|
233
|
+
: {
|
234
|
+
id: args[0].id,
|
235
|
+
as: args[0]._loadedAs,
|
236
|
+
depth: args[1],
|
237
|
+
listener: args[2],
|
238
|
+
};
|
166
239
|
void Effect.runPromise(
|
167
240
|
Effect.provideService(
|
168
|
-
this.subscribeEf(id,
|
241
|
+
this.subscribeEf(id, depth).pipe(
|
169
242
|
Stream.run(
|
170
243
|
Sink.forEach((update) =>
|
171
|
-
Effect.sync(() =>
|
172
|
-
)
|
173
|
-
)
|
244
|
+
Effect.sync(() => listener(update)),
|
245
|
+
),
|
246
|
+
),
|
174
247
|
),
|
175
248
|
AccountCtx,
|
176
|
-
|
177
|
-
)
|
249
|
+
as,
|
250
|
+
),
|
178
251
|
);
|
179
252
|
|
180
253
|
return function unsubscribe() {};
|
181
254
|
}
|
182
255
|
|
183
256
|
/** @category Subscription & Loading */
|
184
|
-
static subscribeEf<V extends CoValue>(
|
257
|
+
static subscribeEf<V extends CoValue, Depth>(
|
185
258
|
this: ClassOf<V> & typeof CoValueBase,
|
186
259
|
id: ID<V>,
|
187
|
-
|
188
|
-
): Stream.Stream<V, UnavailableError, AccountCtx> {
|
189
|
-
return
|
190
|
-
|
260
|
+
depth: Depth & DepthsIn<V>,
|
261
|
+
): Stream.Stream<DeeplyLoaded<V, Depth>, UnavailableError, AccountCtx> {
|
262
|
+
return AccountCtx.pipe(
|
263
|
+
Effect.andThen((account) =>
|
264
|
+
new Ref(id, account, this as CoValueClass<V>).loadEf(),
|
265
|
+
),
|
266
|
+
Stream.fromEffect,
|
267
|
+
Stream.flatMap((value: V) =>
|
191
268
|
Stream.asyncScoped<V, UnavailableError>((emit) =>
|
192
269
|
Effect.gen(this, function* (_) {
|
193
270
|
const subscription = new SubscriptionScope(
|
194
271
|
value,
|
195
272
|
this,
|
196
|
-
(update) =>
|
197
|
-
if (!options?.require || options.require(update)) {
|
198
|
-
void emit.single(update as V);
|
199
|
-
}
|
200
|
-
}
|
273
|
+
(update) => void emit.single(update as V),
|
201
274
|
);
|
202
275
|
|
203
276
|
yield* _(
|
204
277
|
Effect.addFinalizer(() =>
|
205
|
-
Effect.sync(() =>
|
206
|
-
|
278
|
+
Effect.sync(() =>
|
279
|
+
subscription.unsubscribeAll(),
|
280
|
+
),
|
281
|
+
),
|
207
282
|
);
|
208
|
-
})
|
209
|
-
)
|
210
|
-
)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
this.id as unknown as ID<CoValue>,
|
218
|
-
{ as: this._loadedAs, require: options?.require as any },
|
219
|
-
listener as unknown as (update: CoValue) => void
|
220
|
-
);
|
221
|
-
}
|
222
|
-
|
223
|
-
/** @category Subscription & Loading */
|
224
|
-
subscribeEf(options?: RequireOptions<this>): Stream.Stream<this, UnavailableError, never> {
|
225
|
-
return Stream.provideService(
|
226
|
-
(this.constructor as unknown as typeof CoValueBase).subscribeEf(
|
227
|
-
this.id as unknown as ID<CoValue>,
|
228
|
-
options as any
|
283
|
+
}),
|
284
|
+
),
|
285
|
+
),
|
286
|
+
Stream.filterMap((update: V) =>
|
287
|
+
Option.fromNullable(
|
288
|
+
fulfillsDepth(depth, update)
|
289
|
+
? (update as DeeplyLoaded<V, Depth>)
|
290
|
+
: undefined,
|
291
|
+
),
|
229
292
|
),
|
230
|
-
|
231
|
-
this._loadedAs
|
232
|
-
) as unknown as Stream.Stream<this, UnavailableError, never>;
|
293
|
+
);
|
233
294
|
}
|
234
295
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
235
297
|
toJSON(): object | any[] {
|
236
298
|
return {
|
237
299
|
id: this.id,
|
@@ -254,7 +316,3 @@ export class CoValueBase implements CoValue {
|
|
254
316
|
return cast;
|
255
317
|
}
|
256
318
|
}
|
257
|
-
|
258
|
-
export type RequireOptions<V extends CoValue> = {
|
259
|
-
require?: (value: V) => boolean | undefined
|
260
|
-
};
|