jazz-tools 0.8.15 → 0.8.16
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +276 -269
- package/dist/native/coValues/account.js +3 -6
- package/dist/native/coValues/account.js.map +1 -1
- package/dist/native/coValues/coList.js +3 -7
- package/dist/native/coValues/coList.js.map +1 -1
- package/dist/native/coValues/coMap.js +8 -14
- package/dist/native/coValues/coMap.js.map +1 -1
- package/dist/native/coValues/coStream.js +7 -12
- package/dist/native/coValues/coStream.js.map +1 -1
- package/dist/native/coValues/deepLoading.js +6 -3
- package/dist/native/coValues/deepLoading.js.map +1 -1
- package/dist/native/coValues/extensions/imageDef.js.map +1 -1
- package/dist/native/coValues/group.js +3 -6
- package/dist/native/coValues/group.js.map +1 -1
- package/dist/native/coValues/interfaces.js +4 -3
- package/dist/native/coValues/interfaces.js.map +1 -1
- package/dist/native/exports.js +3 -9
- package/dist/native/exports.js.map +1 -1
- package/dist/native/implementation/createContext.js +1 -2
- package/dist/native/implementation/createContext.js.map +1 -1
- package/dist/native/implementation/devtoolsFormatters.js +5 -25
- package/dist/native/implementation/devtoolsFormatters.js.map +1 -1
- package/dist/native/implementation/refs.js +1 -2
- package/dist/native/implementation/refs.js.map +1 -1
- package/dist/native/implementation/schema.js +1 -1
- package/dist/native/implementation/schema.js.map +1 -1
- package/dist/native/implementation/subscriptionScope.js +2 -4
- package/dist/native/implementation/subscriptionScope.js.map +1 -1
- package/dist/native/index.native.js +1 -1
- package/dist/native/index.native.js.map +1 -1
- package/dist/native/lib/cache.js.map +1 -1
- package/dist/native/lib/cache.test.js +1 -1
- package/dist/native/lib/cache.test.js.map +1 -1
- package/dist/web/coValues/account.js +3 -6
- package/dist/web/coValues/account.js.map +1 -1
- package/dist/web/coValues/coList.js +3 -7
- package/dist/web/coValues/coList.js.map +1 -1
- package/dist/web/coValues/coMap.js +8 -14
- package/dist/web/coValues/coMap.js.map +1 -1
- package/dist/web/coValues/coStream.js +7 -12
- package/dist/web/coValues/coStream.js.map +1 -1
- package/dist/web/coValues/deepLoading.js +6 -3
- package/dist/web/coValues/deepLoading.js.map +1 -1
- package/dist/web/coValues/extensions/imageDef.js.map +1 -1
- package/dist/web/coValues/group.js +3 -6
- package/dist/web/coValues/group.js.map +1 -1
- package/dist/web/coValues/interfaces.js +4 -3
- package/dist/web/coValues/interfaces.js.map +1 -1
- package/dist/web/exports.js +3 -9
- package/dist/web/exports.js.map +1 -1
- package/dist/web/implementation/createContext.js +1 -2
- package/dist/web/implementation/createContext.js.map +1 -1
- package/dist/web/implementation/devtoolsFormatters.js +5 -25
- package/dist/web/implementation/devtoolsFormatters.js.map +1 -1
- package/dist/web/implementation/refs.js +1 -2
- package/dist/web/implementation/refs.js.map +1 -1
- package/dist/web/implementation/schema.js +1 -1
- package/dist/web/implementation/schema.js.map +1 -1
- package/dist/web/implementation/subscriptionScope.js +2 -4
- package/dist/web/implementation/subscriptionScope.js.map +1 -1
- package/dist/web/lib/cache.js.map +1 -1
- package/dist/web/lib/cache.test.js +1 -1
- package/dist/web/lib/cache.test.js.map +1 -1
- package/package.json +5 -9
- package/src/coValues/account.ts +330 -339
- package/src/coValues/coList.ts +474 -495
- package/src/coValues/coMap.ts +584 -604
- package/src/coValues/coStream.ts +624 -650
- package/src/coValues/deepLoading.ts +184 -200
- package/src/coValues/extensions/imageDef.ts +44 -44
- package/src/coValues/group.ts +196 -210
- package/src/coValues/interfaces.ts +197 -199
- package/src/exports.ts +38 -26
- package/src/implementation/createContext.ts +206 -213
- package/src/implementation/devtoolsFormatters.ts +80 -100
- package/src/implementation/refs.ts +127 -139
- package/src/implementation/schema.ts +124 -128
- package/src/implementation/subscriptionScope.ts +111 -121
- package/src/index.native.ts +3 -3
- package/src/lib/cache.test.ts +48 -48
- package/src/lib/cache.ts +9 -9
- package/src/tests/coList.test.ts +264 -283
- package/src/tests/coMap.test.ts +741 -761
- package/src/tests/coStream.test.ts +405 -438
- package/src/tests/deepLoading.test.ts +251 -256
- package/src/tests/groupsAndAccounts.test.ts +70 -74
- package/src/tests/schema.test.ts +198 -198
- package/src/tests/subscribe.test.ts +312 -299
- package/tsconfig.json +2 -4
- package/tsconfig.native.json +4 -10
- package/tsconfig.web.json +4 -10
- package/.eslintrc.cjs +0 -24
- package/.prettierrc.js +0 -9
package/src/coValues/coList.ts
CHANGED
@@ -1,40 +1,40 @@
|
|
1
1
|
import type { JsonValue, RawCoList } from "cojson";
|
2
2
|
import { RawAccount } from "cojson";
|
3
3
|
import type {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
CoValue,
|
5
|
+
CoValueClass,
|
6
|
+
CoValueFromRaw,
|
7
|
+
DeeplyLoaded,
|
8
|
+
DepthsIn,
|
9
|
+
ID,
|
10
|
+
RefEncoded,
|
11
|
+
Schema,
|
12
|
+
SchemaFor,
|
13
|
+
UnCo,
|
14
14
|
} from "../internal.js";
|
15
15
|
import {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
16
|
+
Account,
|
17
|
+
AnonymousJazzAgent,
|
18
|
+
Group,
|
19
|
+
ItemsSym,
|
20
|
+
Ref,
|
21
|
+
SchemaInit,
|
22
|
+
co,
|
23
|
+
ensureCoValueLoaded,
|
24
|
+
inspect,
|
25
|
+
isRefEncoded,
|
26
|
+
loadCoValue,
|
27
|
+
makeRefs,
|
28
|
+
subscribeToCoValue,
|
29
|
+
subscribeToExistingCoValue,
|
30
|
+
subscriptionsScopes,
|
31
31
|
} from "../internal.js";
|
32
32
|
import { coValuesCache } from "../lib/cache.js";
|
33
33
|
|
34
34
|
/**
|
35
35
|
* CoLists are collaborative versions of plain arrays.
|
36
36
|
*
|
37
|
-
*
|
37
|
+
* @categoryDescription Content
|
38
38
|
* You can access items on a `CoList` as if they were normal items on a plain array, using `[]` notation, etc.
|
39
39
|
*
|
40
40
|
* Since `CoList` is a subclass of `Array`, you can use all the normal array methods like `push`, `pop`, `splice`, etc.
|
@@ -50,504 +50,483 @@ import { coValuesCache } from "../lib/cache.js";
|
|
50
50
|
*/
|
51
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
52
52
|
export class CoList<Item = any> extends Array<Item> implements CoValue {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
53
|
+
/**
|
54
|
+
* Declare a `CoList` by subclassing `CoList.Of(...)` and passing the item schema using `co`.
|
55
|
+
*
|
56
|
+
* @example
|
57
|
+
* ```ts
|
58
|
+
* class ColorList extends CoList.Of(
|
59
|
+
* co.string
|
60
|
+
* ) {}
|
61
|
+
* class AnimalList extends CoList.Of(
|
62
|
+
* co.ref(Animal)
|
63
|
+
* ) {}
|
64
|
+
* ```
|
65
|
+
*
|
66
|
+
* @category Declaration
|
67
|
+
*/
|
68
|
+
static Of<Item>(item: Item): typeof CoList<Item> {
|
69
|
+
// TODO: cache superclass for item class
|
70
|
+
return class CoListOf extends CoList<Item> {
|
71
|
+
[co.items] = item;
|
72
|
+
};
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* @ignore
|
77
|
+
* @deprecated Use UPPERCASE `CoList.Of` instead! */
|
78
|
+
static of(..._args: never): never {
|
79
|
+
throw new Error("Can't use Array.of with CoLists");
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* The ID of this `CoList`
|
84
|
+
* @category Content */
|
85
|
+
declare id: ID<this>;
|
86
|
+
/** @category Type Helpers */
|
87
|
+
declare _type: "CoList";
|
88
|
+
static {
|
89
|
+
this.prototype._type = "CoList";
|
90
|
+
}
|
91
|
+
/** @category Internals */
|
92
|
+
declare _raw: RawCoList;
|
93
|
+
/** @category Internals */
|
94
|
+
declare _instanceID: string;
|
95
|
+
|
96
|
+
/** @internal This is only a marker type and doesn't exist at runtime */
|
97
|
+
[ItemsSym]!: Item;
|
98
|
+
/** @internal */
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
100
|
+
static _schema: any;
|
101
|
+
/** @internal */
|
102
|
+
get _schema(): {
|
103
|
+
[ItemsSym]: SchemaFor<Item>;
|
104
|
+
} {
|
105
|
+
return (this.constructor as typeof CoList)._schema;
|
106
|
+
}
|
107
|
+
|
108
|
+
/** @category Collaboration */
|
109
|
+
get _owner(): Account | Group {
|
110
|
+
return this._raw.group instanceof RawAccount
|
111
|
+
? Account.fromRaw(this._raw.group)
|
112
|
+
: Group.fromRaw(this._raw.group);
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* If a `CoList`'s items are a `co.ref(...)`, you can use `coList._refs[i]` to access
|
117
|
+
* the `Ref` instead of the potentially loaded/null value.
|
118
|
+
*
|
119
|
+
* This allows you to always get the ID or load the value manually.
|
120
|
+
*
|
121
|
+
* @example
|
122
|
+
* ```ts
|
123
|
+
* animals._refs[0].id; // => ID<Animal>
|
124
|
+
* animals._refs[0].value;
|
125
|
+
* // => Animal | null
|
126
|
+
* const animal = await animals._refs[0].load();
|
127
|
+
* ```
|
128
|
+
*
|
129
|
+
* @category Content
|
130
|
+
**/
|
131
|
+
get _refs(): {
|
132
|
+
[idx: number]: Exclude<Item, null> extends CoValue
|
133
|
+
? Ref<UnCo<Exclude<Item, null>>>
|
134
|
+
: never;
|
135
|
+
} & {
|
136
|
+
length: number;
|
137
|
+
[Symbol.iterator](): IterableIterator<
|
138
|
+
Exclude<Item, null> extends CoValue ? Ref<Exclude<Item, null>> : never
|
139
|
+
>;
|
140
|
+
} {
|
141
|
+
return makeRefs<number>(
|
142
|
+
(idx) => this._raw.get(idx) as unknown as ID<CoValue>,
|
143
|
+
() => Array.from({ length: this._raw.entries().length }, (_, idx) => idx),
|
144
|
+
this._loadedAs,
|
145
|
+
(_idx) => this._schema[ItemsSym] as RefEncoded<CoValue>,
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
147
|
+
) as any;
|
148
|
+
}
|
149
|
+
|
150
|
+
get _edits(): {
|
151
|
+
[idx: number]: {
|
152
|
+
value?: Item;
|
153
|
+
ref?: Item extends CoValue ? Ref<Item> : never;
|
154
|
+
by?: Account;
|
155
|
+
madeAt: Date;
|
156
|
+
};
|
157
|
+
} {
|
158
|
+
throw new Error("Not implemented");
|
159
|
+
}
|
160
|
+
|
161
|
+
get _loadedAs() {
|
162
|
+
const rawAccount = this._raw.core.node.account;
|
163
|
+
|
164
|
+
if (rawAccount instanceof RawAccount) {
|
165
|
+
return coValuesCache.get(rawAccount, () => Account.fromRaw(rawAccount));
|
73
166
|
}
|
74
167
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
168
|
+
return new AnonymousJazzAgent(this._raw.core.node);
|
169
|
+
}
|
170
|
+
|
171
|
+
static get [Symbol.species]() {
|
172
|
+
return Array;
|
173
|
+
}
|
174
|
+
|
175
|
+
constructor(options: { fromRaw: RawCoList } | undefined) {
|
176
|
+
super();
|
177
|
+
|
178
|
+
Object.defineProperty(this, "_instanceID", {
|
179
|
+
value: `instance-${Math.random().toString(36).slice(2)}`,
|
180
|
+
enumerable: false,
|
181
|
+
});
|
182
|
+
|
183
|
+
if (options && "fromRaw" in options) {
|
184
|
+
Object.defineProperties(this, {
|
185
|
+
id: {
|
186
|
+
value: options.fromRaw.id,
|
187
|
+
enumerable: false,
|
188
|
+
},
|
189
|
+
_raw: { value: options.fromRaw, enumerable: false },
|
190
|
+
});
|
80
191
|
}
|
81
192
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
193
|
+
return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* Create a new CoList with the given initial values and owner.
|
198
|
+
*
|
199
|
+
* The owner (a Group or Account) determines access rights to the CoMap.
|
200
|
+
*
|
201
|
+
* The CoList will immediately be persisted and synced to connected peers.
|
202
|
+
*
|
203
|
+
* @example
|
204
|
+
* ```ts
|
205
|
+
* const colours = ColorList.create(
|
206
|
+
* ["red", "green", "blue"],
|
207
|
+
* { owner: me }
|
208
|
+
* );
|
209
|
+
* const animals = AnimalList.create(
|
210
|
+
* [cat, dog, fish],
|
211
|
+
* { owner: me }
|
212
|
+
* );
|
213
|
+
* ```
|
214
|
+
*
|
215
|
+
* @category Creation
|
216
|
+
**/
|
217
|
+
static create<L extends CoList>(
|
218
|
+
this: CoValueClass<L>,
|
219
|
+
items: UnCo<L[number]>[],
|
220
|
+
options: { owner: Account | Group },
|
221
|
+
) {
|
222
|
+
const instance = new this({ init: items, owner: options.owner });
|
223
|
+
const raw = options.owner._raw.createList(
|
224
|
+
toRawItems(items, instance._schema[ItemsSym]),
|
225
|
+
);
|
226
|
+
|
227
|
+
Object.defineProperties(instance, {
|
228
|
+
id: {
|
229
|
+
value: raw.id,
|
230
|
+
enumerable: false,
|
231
|
+
},
|
232
|
+
_raw: { value: raw, enumerable: false },
|
233
|
+
});
|
234
|
+
|
235
|
+
return instance;
|
236
|
+
}
|
237
|
+
|
238
|
+
push(...items: Item[]): number {
|
239
|
+
for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
|
240
|
+
this._raw.append(item);
|
106
241
|
}
|
107
242
|
|
108
|
-
|
109
|
-
|
110
|
-
return this._raw.group instanceof RawAccount
|
111
|
-
? Account.fromRaw(this._raw.group)
|
112
|
-
: Group.fromRaw(this._raw.group);
|
113
|
-
}
|
243
|
+
return this._raw.entries().length;
|
244
|
+
}
|
114
245
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
*
|
119
|
-
* This allows you to always get the ID or load the value manually.
|
120
|
-
*
|
121
|
-
* @example
|
122
|
-
* ```ts
|
123
|
-
* animals._refs[0].id; // => ID<Animal>
|
124
|
-
* animals._refs[0].value;
|
125
|
-
* // => Animal | null
|
126
|
-
* const animal = await animals._refs[0].load();
|
127
|
-
* ```
|
128
|
-
*
|
129
|
-
* @category Content
|
130
|
-
**/
|
131
|
-
get _refs(): {
|
132
|
-
[idx: number]: Exclude<Item, null> extends CoValue
|
133
|
-
? Ref<UnCo<Exclude<Item, null>>>
|
134
|
-
: never;
|
135
|
-
} & {
|
136
|
-
length: number;
|
137
|
-
[Symbol.iterator](): IterableIterator<
|
138
|
-
Exclude<Item, null> extends CoValue
|
139
|
-
? Ref<Exclude<Item, null>>
|
140
|
-
: never
|
141
|
-
>;
|
142
|
-
} {
|
143
|
-
return makeRefs<number>(
|
144
|
-
(idx) => this._raw.get(idx) as unknown as ID<CoValue>,
|
145
|
-
() =>
|
146
|
-
Array.from(
|
147
|
-
{ length: this._raw.entries().length },
|
148
|
-
(_, idx) => idx,
|
149
|
-
),
|
150
|
-
this._loadedAs,
|
151
|
-
(_idx) => this._schema[ItemsSym] as RefEncoded<CoValue>,
|
152
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
153
|
-
) as any;
|
246
|
+
unshift(...items: Item[]): number {
|
247
|
+
for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
|
248
|
+
this._raw.prepend(item);
|
154
249
|
}
|
155
250
|
|
156
|
-
|
157
|
-
|
158
|
-
value?: Item;
|
159
|
-
ref?: Item extends CoValue ? Ref<Item> : never;
|
160
|
-
by?: Account;
|
161
|
-
madeAt: Date;
|
162
|
-
};
|
163
|
-
} {
|
164
|
-
throw new Error("Not implemented");
|
165
|
-
}
|
251
|
+
return this._raw.entries().length;
|
252
|
+
}
|
166
253
|
|
167
|
-
|
168
|
-
|
254
|
+
pop(): Item | undefined {
|
255
|
+
const last = this[this.length - 1];
|
169
256
|
|
170
|
-
|
171
|
-
return coValuesCache.get(rawAccount, () => Account.fromRaw(rawAccount)) ;
|
172
|
-
}
|
257
|
+
this._raw.delete(this.length - 1);
|
173
258
|
|
174
|
-
|
175
|
-
|
259
|
+
return last;
|
260
|
+
}
|
176
261
|
|
177
|
-
|
178
|
-
|
179
|
-
}
|
262
|
+
shift(): Item | undefined {
|
263
|
+
const first = this[0];
|
180
264
|
|
181
|
-
|
182
|
-
super();
|
183
|
-
|
184
|
-
Object.defineProperty(this, "_instanceID", {
|
185
|
-
value: `instance-${Math.random().toString(36).slice(2)}`,
|
186
|
-
enumerable: false,
|
187
|
-
});
|
188
|
-
|
189
|
-
if (options && "fromRaw" in options) {
|
190
|
-
Object.defineProperties(this, {
|
191
|
-
id: {
|
192
|
-
value: options.fromRaw.id,
|
193
|
-
enumerable: false,
|
194
|
-
},
|
195
|
-
_raw: { value: options.fromRaw, enumerable: false },
|
196
|
-
});
|
197
|
-
}
|
198
|
-
|
199
|
-
return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
|
200
|
-
}
|
265
|
+
this._raw.delete(0);
|
201
266
|
|
202
|
-
|
203
|
-
|
204
|
-
*
|
205
|
-
* The owner (a Group or Account) determines access rights to the CoMap.
|
206
|
-
*
|
207
|
-
* The CoList will immediately be persisted and synced to connected peers.
|
208
|
-
*
|
209
|
-
* @example
|
210
|
-
* ```ts
|
211
|
-
* const colours = ColorList.create(
|
212
|
-
* ["red", "green", "blue"],
|
213
|
-
* { owner: me }
|
214
|
-
* );
|
215
|
-
* const animals = AnimalList.create(
|
216
|
-
* [cat, dog, fish],
|
217
|
-
* { owner: me }
|
218
|
-
* );
|
219
|
-
* ```
|
220
|
-
*
|
221
|
-
* @category Creation
|
222
|
-
**/
|
223
|
-
static create<L extends CoList>(
|
224
|
-
this: CoValueClass<L>,
|
225
|
-
items: UnCo<L[number]>[],
|
226
|
-
options: { owner: Account | Group },
|
227
|
-
) {
|
228
|
-
const instance = new this({ init: items, owner: options.owner });
|
229
|
-
const raw = options.owner._raw.createList(
|
230
|
-
toRawItems(items, instance._schema[ItemsSym]),
|
231
|
-
);
|
232
|
-
|
233
|
-
Object.defineProperties(instance, {
|
234
|
-
id: {
|
235
|
-
value: raw.id,
|
236
|
-
enumerable: false,
|
237
|
-
},
|
238
|
-
_raw: { value: raw, enumerable: false },
|
239
|
-
});
|
240
|
-
|
241
|
-
return instance;
|
242
|
-
}
|
267
|
+
return first;
|
268
|
+
}
|
243
269
|
|
244
|
-
|
245
|
-
|
246
|
-
items as Item[],
|
247
|
-
this._schema[ItemsSym],
|
248
|
-
)) {
|
249
|
-
this._raw.append(item);
|
250
|
-
}
|
251
|
-
|
252
|
-
return this._raw.entries().length;
|
253
|
-
}
|
270
|
+
splice(start: number, deleteCount: number, ...items: Item[]): Item[] {
|
271
|
+
const deleted = this.slice(start, start + deleteCount);
|
254
272
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
}
|
262
|
-
|
263
|
-
return this._raw.entries().length;
|
264
|
-
}
|
265
|
-
|
266
|
-
pop(): Item | undefined {
|
267
|
-
const last = this[this.length - 1];
|
268
|
-
|
269
|
-
this._raw.delete(this.length - 1);
|
270
|
-
|
271
|
-
return last;
|
273
|
+
for (
|
274
|
+
let idxToDelete = start + deleteCount - 1;
|
275
|
+
idxToDelete >= start;
|
276
|
+
idxToDelete--
|
277
|
+
) {
|
278
|
+
this._raw.delete(idxToDelete);
|
272
279
|
}
|
273
280
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
return first;
|
281
|
+
let appendAfter = Math.max(start - 1, 0);
|
282
|
+
for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
|
283
|
+
console.log(this._raw.asArray(), appendAfter);
|
284
|
+
this._raw.append(item, appendAfter);
|
285
|
+
appendAfter++;
|
280
286
|
}
|
281
287
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
return deleted;
|
288
|
+
return deleted;
|
289
|
+
}
|
290
|
+
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
292
|
+
toJSON(_key?: string, seenAbove?: ID<CoValue>[]): any[] {
|
293
|
+
const itemDescriptor = this._schema[ItemsSym] as Schema;
|
294
|
+
if (itemDescriptor === "json") {
|
295
|
+
return this._raw.asArray();
|
296
|
+
} else if ("encoded" in itemDescriptor) {
|
297
|
+
return this._raw.asArray().map((e) => itemDescriptor.encoded.encode(e));
|
298
|
+
} else if (isRefEncoded(itemDescriptor)) {
|
299
|
+
return this.map((item, idx) =>
|
300
|
+
seenAbove?.includes((item as CoValue)?.id)
|
301
|
+
? { _circular: (item as CoValue).id }
|
302
|
+
: (item as unknown as CoValue)?.toJSON(idx + "", [
|
303
|
+
...(seenAbove || []),
|
304
|
+
this.id,
|
305
|
+
]),
|
306
|
+
);
|
307
|
+
} else {
|
308
|
+
return [];
|
304
309
|
}
|
305
|
-
|
310
|
+
}
|
311
|
+
|
312
|
+
[inspect]() {
|
313
|
+
return this.toJSON();
|
314
|
+
}
|
315
|
+
|
316
|
+
/** @category Internals */
|
317
|
+
static fromRaw<V extends CoList>(
|
318
|
+
this: CoValueClass<V> & typeof CoList,
|
319
|
+
raw: RawCoList,
|
320
|
+
) {
|
321
|
+
return new this({ fromRaw: raw });
|
322
|
+
}
|
323
|
+
|
324
|
+
/** @internal */
|
325
|
+
static schema<V extends CoList>(
|
306
326
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
327
|
+
this: { new (...args: any): V } & typeof CoList,
|
328
|
+
def: { [ItemsSym]: V["_schema"][ItemsSym] },
|
329
|
+
) {
|
330
|
+
this._schema ||= {};
|
331
|
+
Object.assign(this._schema, def);
|
332
|
+
}
|
333
|
+
|
334
|
+
/**
|
335
|
+
* Load a `CoList` with a given ID, as a given account.
|
336
|
+
*
|
337
|
+
* `depth` specifies if item CoValue references should be loaded as well before resolving.
|
338
|
+
* The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
|
339
|
+
*
|
340
|
+
* You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
|
341
|
+
*
|
342
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
|
343
|
+
*
|
344
|
+
* @example
|
345
|
+
* ```ts
|
346
|
+
* const animalsWithVets =
|
347
|
+
* await ListOfAnimals.load(
|
348
|
+
* "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
|
349
|
+
* me,
|
350
|
+
* [{ vet: {} }]
|
351
|
+
* );
|
352
|
+
* ```
|
353
|
+
*
|
354
|
+
* @category Subscription & Loading
|
355
|
+
*/
|
356
|
+
static load<L extends CoList, Depth>(
|
357
|
+
this: CoValueClass<L>,
|
358
|
+
id: ID<L>,
|
359
|
+
as: Account,
|
360
|
+
depth: Depth & DepthsIn<L>,
|
361
|
+
): Promise<DeeplyLoaded<L, Depth> | undefined> {
|
362
|
+
return loadCoValue(this, id, as, depth);
|
363
|
+
}
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Load and subscribe to a `CoList` with a given ID, as a given account.
|
367
|
+
*
|
368
|
+
* Automatically also subscribes to updates to all referenced/nested CoValues as soon as they are accessed in the listener.
|
369
|
+
*
|
370
|
+
* `depth` specifies if item CoValue references should be loaded as well before calling `listener` for the first time.
|
371
|
+
* The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
|
372
|
+
*
|
373
|
+
* You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
|
374
|
+
*
|
375
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
|
376
|
+
*
|
377
|
+
* Returns an unsubscribe function that you should call when you no longer need updates.
|
378
|
+
*
|
379
|
+
* Also see the `useCoState` hook to reactively subscribe to a CoValue in a React component.
|
380
|
+
*
|
381
|
+
* @example
|
382
|
+
* ```ts
|
383
|
+
* const unsub = ListOfAnimals.subscribe(
|
384
|
+
* "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
|
385
|
+
* me,
|
386
|
+
* { vet: {} },
|
387
|
+
* (animalsWithVets) => console.log(animalsWithVets)
|
388
|
+
* );
|
389
|
+
* ```
|
390
|
+
*
|
391
|
+
* @category Subscription & Loading
|
392
|
+
*/
|
393
|
+
static subscribe<L extends CoList, Depth>(
|
394
|
+
this: CoValueClass<L>,
|
395
|
+
id: ID<L>,
|
396
|
+
as: Account,
|
397
|
+
depth: Depth & DepthsIn<L>,
|
398
|
+
listener: (value: DeeplyLoaded<L, Depth>) => void,
|
399
|
+
): () => void {
|
400
|
+
return subscribeToCoValue<L, Depth>(this, id, as, depth, listener);
|
401
|
+
}
|
402
|
+
|
403
|
+
/**
|
404
|
+
* Given an already loaded `CoList`, ensure that items are loaded to the specified depth.
|
405
|
+
*
|
406
|
+
* Works like `CoList.load()`, but you don't need to pass the ID or the account to load as again.
|
407
|
+
*
|
408
|
+
* @category Subscription & Loading
|
409
|
+
*/
|
410
|
+
ensureLoaded<L extends CoList, Depth>(
|
411
|
+
this: L,
|
412
|
+
depth: Depth & DepthsIn<L>,
|
413
|
+
): Promise<DeeplyLoaded<L, Depth> | undefined> {
|
414
|
+
return ensureCoValueLoaded(this, depth);
|
415
|
+
}
|
416
|
+
|
417
|
+
/**
|
418
|
+
* Given an already loaded `CoList`, subscribe to updates to the `CoList` and ensure that items are loaded to the specified depth.
|
419
|
+
*
|
420
|
+
* Works like `CoList.subscribe()`, but you don't need to pass the ID or the account to load as again.
|
421
|
+
*
|
422
|
+
* Returns an unsubscribe function that you should call when you no longer need updates.
|
423
|
+
*
|
424
|
+
* @category Subscription & Loading
|
425
|
+
**/
|
426
|
+
subscribe<L extends CoList, Depth>(
|
427
|
+
this: L,
|
428
|
+
depth: Depth & DepthsIn<L>,
|
429
|
+
listener: (value: DeeplyLoaded<L, Depth>) => void,
|
430
|
+
): () => void {
|
431
|
+
return subscribeToExistingCoValue(this, depth, listener);
|
432
|
+
}
|
433
|
+
|
434
|
+
/** @category Type Helpers */
|
435
|
+
castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
|
436
|
+
cl: Cl,
|
437
|
+
): InstanceType<Cl> {
|
438
|
+
const casted = cl.fromRaw(this._raw) as InstanceType<Cl>;
|
439
|
+
const subscriptionScope = subscriptionsScopes.get(this);
|
440
|
+
if (subscriptionScope) {
|
441
|
+
subscriptionsScopes.set(casted, subscriptionScope);
|
331
442
|
}
|
443
|
+
return casted;
|
444
|
+
}
|
445
|
+
}
|
332
446
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
447
|
+
function toRawItems<Item>(items: Item[], itemDescriptor: Schema) {
|
448
|
+
const rawItems =
|
449
|
+
itemDescriptor === "json"
|
450
|
+
? (items as JsonValue[])
|
451
|
+
: "encoded" in itemDescriptor
|
452
|
+
? items?.map((e) => itemDescriptor.encoded.encode(e))
|
453
|
+
: isRefEncoded(itemDescriptor)
|
454
|
+
? items?.map((v) => (v as unknown as CoValue).id)
|
455
|
+
: (() => {
|
456
|
+
throw new Error("Invalid element descriptor");
|
457
|
+
})();
|
458
|
+
return rawItems;
|
459
|
+
}
|
340
460
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
461
|
+
const CoListProxyHandler: ProxyHandler<CoList> = {
|
462
|
+
get(target, key, receiver) {
|
463
|
+
if (typeof key === "string" && !isNaN(+key)) {
|
464
|
+
const itemDescriptor = target._schema[ItemsSym] as Schema;
|
465
|
+
const rawValue = target._raw.get(Number(key));
|
466
|
+
if (itemDescriptor === "json") {
|
467
|
+
return rawValue;
|
468
|
+
} else if ("encoded" in itemDescriptor) {
|
469
|
+
return rawValue === undefined
|
470
|
+
? undefined
|
471
|
+
: itemDescriptor.encoded.decode(rawValue);
|
472
|
+
} else if (isRefEncoded(itemDescriptor)) {
|
473
|
+
return rawValue === undefined
|
474
|
+
? undefined
|
475
|
+
: new Ref(
|
476
|
+
rawValue as unknown as ID<CoValue>,
|
477
|
+
target._loadedAs,
|
478
|
+
itemDescriptor,
|
479
|
+
).accessFrom(receiver, Number(key));
|
480
|
+
}
|
481
|
+
} else if (key === "length") {
|
482
|
+
return target._raw.entries().length;
|
483
|
+
} else {
|
484
|
+
return Reflect.get(target, key, receiver);
|
349
485
|
}
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
* You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
|
358
|
-
*
|
359
|
-
* Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
|
360
|
-
*
|
361
|
-
* @example
|
362
|
-
* ```ts
|
363
|
-
* const animalsWithVets =
|
364
|
-
* await ListOfAnimals.load(
|
365
|
-
* "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
|
366
|
-
* me,
|
367
|
-
* [{ vet: {} }]
|
368
|
-
* );
|
369
|
-
* ```
|
370
|
-
*
|
371
|
-
* @category Subscription & Loading
|
372
|
-
*/
|
373
|
-
static load<L extends CoList, Depth>(
|
374
|
-
this: CoValueClass<L>,
|
375
|
-
id: ID<L>,
|
376
|
-
as: Account,
|
377
|
-
depth: Depth & DepthsIn<L>,
|
378
|
-
): Promise<DeeplyLoaded<L, Depth> | undefined> {
|
379
|
-
return loadCoValue(this, id, as, depth);
|
486
|
+
},
|
487
|
+
set(target, key, value, receiver) {
|
488
|
+
if (key === ItemsSym && typeof value === "object" && SchemaInit in value) {
|
489
|
+
(target.constructor as typeof CoList)._schema ||= {};
|
490
|
+
(target.constructor as typeof CoList)._schema[ItemsSym] =
|
491
|
+
value[SchemaInit];
|
492
|
+
return true;
|
380
493
|
}
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
*
|
396
|
-
* Also see the `useCoState` hook to reactively subscribe to a CoValue in a React component.
|
397
|
-
*
|
398
|
-
* @example
|
399
|
-
* ```ts
|
400
|
-
* const unsub = ListOfAnimals.subscribe(
|
401
|
-
* "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
|
402
|
-
* me,
|
403
|
-
* { vet: {} },
|
404
|
-
* (animalsWithVets) => console.log(animalsWithVets)
|
405
|
-
* );
|
406
|
-
* ```
|
407
|
-
*
|
408
|
-
* @category Subscription & Loading
|
409
|
-
*/
|
410
|
-
static subscribe<L extends CoList, Depth>(
|
411
|
-
this: CoValueClass<L>,
|
412
|
-
id: ID<L>,
|
413
|
-
as: Account,
|
414
|
-
depth: Depth & DepthsIn<L>,
|
415
|
-
listener: (value: DeeplyLoaded<L, Depth>) => void,
|
416
|
-
): () => void {
|
417
|
-
return subscribeToCoValue<L, Depth>(this, id, as, depth, listener);
|
494
|
+
if (typeof key === "string" && !isNaN(+key)) {
|
495
|
+
const itemDescriptor = target._schema[ItemsSym] as Schema;
|
496
|
+
let rawValue;
|
497
|
+
if (itemDescriptor === "json") {
|
498
|
+
rawValue = value;
|
499
|
+
} else if ("encoded" in itemDescriptor) {
|
500
|
+
rawValue = itemDescriptor.encoded.encode(value);
|
501
|
+
} else if (isRefEncoded(itemDescriptor)) {
|
502
|
+
rawValue = value.id;
|
503
|
+
}
|
504
|
+
target._raw.replace(Number(key), rawValue);
|
505
|
+
return true;
|
506
|
+
} else {
|
507
|
+
return Reflect.set(target, key, value, receiver);
|
418
508
|
}
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
509
|
+
},
|
510
|
+
defineProperty(target, key, descriptor) {
|
511
|
+
if (
|
512
|
+
descriptor.value &&
|
513
|
+
key === ItemsSym &&
|
514
|
+
typeof descriptor.value === "object" &&
|
515
|
+
SchemaInit in descriptor.value
|
516
|
+
) {
|
517
|
+
(target.constructor as typeof CoList)._schema ||= {};
|
518
|
+
(target.constructor as typeof CoList)._schema[ItemsSym] =
|
519
|
+
descriptor.value[SchemaInit];
|
520
|
+
return true;
|
521
|
+
} else {
|
522
|
+
return Reflect.defineProperty(target, key, descriptor);
|
432
523
|
}
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
* Returns an unsubscribe function that you should call when you no longer need updates.
|
440
|
-
*
|
441
|
-
* @category Subscription & Loading
|
442
|
-
**/
|
443
|
-
subscribe<L extends CoList, Depth>(
|
444
|
-
this: L,
|
445
|
-
depth: Depth & DepthsIn<L>,
|
446
|
-
listener: (value: DeeplyLoaded<L, Depth>) => void,
|
447
|
-
): () => void {
|
448
|
-
return subscribeToExistingCoValue(this, depth, listener);
|
524
|
+
},
|
525
|
+
has(target, key) {
|
526
|
+
if (typeof key === "string" && !isNaN(+key)) {
|
527
|
+
return Number(key) < target._raw.entries().length;
|
528
|
+
} else {
|
529
|
+
return Reflect.has(target, key);
|
449
530
|
}
|
450
|
-
|
451
|
-
/** @category Type Helpers */
|
452
|
-
castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
|
453
|
-
cl: Cl,
|
454
|
-
): InstanceType<Cl> {
|
455
|
-
const casted = cl.fromRaw(this._raw) as InstanceType<Cl>;
|
456
|
-
const subscriptionScope = subscriptionsScopes.get(this);
|
457
|
-
if (subscriptionScope) {
|
458
|
-
subscriptionsScopes.set(casted, subscriptionScope);
|
459
|
-
}
|
460
|
-
return casted;
|
461
|
-
}
|
462
|
-
}
|
463
|
-
|
464
|
-
function toRawItems<Item>(items: Item[], itemDescriptor: Schema) {
|
465
|
-
const rawItems =
|
466
|
-
itemDescriptor === "json"
|
467
|
-
? (items as JsonValue[])
|
468
|
-
: "encoded" in itemDescriptor
|
469
|
-
? items?.map((e) => itemDescriptor.encoded.encode(e))
|
470
|
-
: isRefEncoded(itemDescriptor)
|
471
|
-
? items?.map((v) => (v as unknown as CoValue).id)
|
472
|
-
: (() => {
|
473
|
-
throw new Error("Invalid element descriptor");
|
474
|
-
})();
|
475
|
-
return rawItems;
|
476
|
-
}
|
477
|
-
|
478
|
-
const CoListProxyHandler: ProxyHandler<CoList> = {
|
479
|
-
get(target, key, receiver) {
|
480
|
-
if (typeof key === "string" && !isNaN(+key)) {
|
481
|
-
const itemDescriptor = target._schema[ItemsSym] as Schema;
|
482
|
-
const rawValue = target._raw.get(Number(key));
|
483
|
-
if (itemDescriptor === "json") {
|
484
|
-
return rawValue;
|
485
|
-
} else if ("encoded" in itemDescriptor) {
|
486
|
-
return rawValue === undefined
|
487
|
-
? undefined
|
488
|
-
: itemDescriptor.encoded.decode(rawValue);
|
489
|
-
} else if (isRefEncoded(itemDescriptor)) {
|
490
|
-
return rawValue === undefined
|
491
|
-
? undefined
|
492
|
-
: new Ref(
|
493
|
-
rawValue as unknown as ID<CoValue>,
|
494
|
-
target._loadedAs,
|
495
|
-
itemDescriptor,
|
496
|
-
).accessFrom(receiver, Number(key));
|
497
|
-
}
|
498
|
-
} else if (key === "length") {
|
499
|
-
return target._raw.entries().length;
|
500
|
-
} else {
|
501
|
-
return Reflect.get(target, key, receiver);
|
502
|
-
}
|
503
|
-
},
|
504
|
-
set(target, key, value, receiver) {
|
505
|
-
if (
|
506
|
-
key === ItemsSym &&
|
507
|
-
typeof value === "object" &&
|
508
|
-
SchemaInit in value
|
509
|
-
) {
|
510
|
-
(target.constructor as typeof CoList)._schema ||= {};
|
511
|
-
(target.constructor as typeof CoList)._schema[ItemsSym] =
|
512
|
-
value[SchemaInit];
|
513
|
-
return true;
|
514
|
-
}
|
515
|
-
if (typeof key === "string" && !isNaN(+key)) {
|
516
|
-
const itemDescriptor = target._schema[ItemsSym] as Schema;
|
517
|
-
let rawValue;
|
518
|
-
if (itemDescriptor === "json") {
|
519
|
-
rawValue = value;
|
520
|
-
} else if ("encoded" in itemDescriptor) {
|
521
|
-
rawValue = itemDescriptor.encoded.encode(value);
|
522
|
-
} else if (isRefEncoded(itemDescriptor)) {
|
523
|
-
rawValue = value.id;
|
524
|
-
}
|
525
|
-
target._raw.replace(Number(key), rawValue);
|
526
|
-
return true;
|
527
|
-
} else {
|
528
|
-
return Reflect.set(target, key, value, receiver);
|
529
|
-
}
|
530
|
-
},
|
531
|
-
defineProperty(target, key, descriptor) {
|
532
|
-
if (
|
533
|
-
descriptor.value &&
|
534
|
-
key === ItemsSym &&
|
535
|
-
typeof descriptor.value === "object" &&
|
536
|
-
SchemaInit in descriptor.value
|
537
|
-
) {
|
538
|
-
(target.constructor as typeof CoList)._schema ||= {};
|
539
|
-
(target.constructor as typeof CoList)._schema[ItemsSym] =
|
540
|
-
descriptor.value[SchemaInit];
|
541
|
-
return true;
|
542
|
-
} else {
|
543
|
-
return Reflect.defineProperty(target, key, descriptor);
|
544
|
-
}
|
545
|
-
},
|
546
|
-
has(target, key) {
|
547
|
-
if (typeof key === "string" && !isNaN(+key)) {
|
548
|
-
return Number(key) < target._raw.entries().length;
|
549
|
-
} else {
|
550
|
-
return Reflect.has(target, key);
|
551
|
-
}
|
552
|
-
},
|
531
|
+
},
|
553
532
|
};
|