cojson 0.2.3 → 0.3.0
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/dist/account.d.ts +1 -1
- package/dist/coValue.d.ts +5 -13
- package/dist/coValue.js +14 -7
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.d.ts +6 -6
- package/dist/coValueCore.js +11 -14
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/coList.d.ts +99 -34
- package/dist/coValues/coList.js +162 -72
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.d.ts +96 -31
- package/dist/coValues/coMap.js +157 -114
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.d.ts +67 -23
- package/dist/coValues/coStream.js +131 -59
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/crypto.d.ts +8 -3
- package/dist/crypto.js +6 -6
- package/dist/crypto.js.map +1 -1
- package/dist/group.d.ts +57 -23
- package/dist/group.js +75 -33
- package/dist/group.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/{node.d.ts → localNode.d.ts} +16 -8
- package/dist/{node.js → localNode.js} +48 -40
- package/dist/localNode.js.map +1 -0
- package/dist/permissions.js +6 -3
- package/dist/permissions.js.map +1 -1
- package/dist/queriedCoValues/queriedCoList.d.ts +66 -0
- package/dist/queriedCoValues/queriedCoList.js +120 -0
- package/dist/queriedCoValues/queriedCoList.js.map +1 -0
- package/dist/queriedCoValues/queriedCoMap.d.ts +47 -0
- package/dist/queriedCoValues/queriedCoMap.js +83 -0
- package/dist/queriedCoValues/queriedCoMap.js.map +1 -0
- package/dist/queriedCoValues/queriedCoStream.d.ts +40 -0
- package/dist/queriedCoValues/queriedCoStream.js +72 -0
- package/dist/queriedCoValues/queriedCoStream.js.map +1 -0
- package/dist/queries.d.ts +29 -112
- package/dist/queries.js +44 -227
- package/dist/queries.js.map +1 -1
- package/dist/sync.d.ts +1 -1
- package/dist/sync.js +1 -1
- package/dist/sync.js.map +1 -1
- package/dist/tests/testUtils.d.ts +1 -1
- package/dist/tests/testUtils.js +3 -3
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/account.ts +1 -1
- package/src/coValue.ts +25 -20
- package/src/coValueCore.ts +17 -21
- package/src/coValues/coList.ts +242 -128
- package/src/coValues/coMap.ts +293 -162
- package/src/coValues/coStream.ts +227 -94
- package/src/crypto.ts +37 -24
- package/src/group.ts +90 -63
- package/src/index.ts +35 -25
- package/src/{node.ts → localNode.ts} +64 -64
- package/src/permissions.ts +15 -18
- package/src/queriedCoValues/queriedCoList.ts +248 -0
- package/src/queriedCoValues/queriedCoMap.ts +180 -0
- package/src/queriedCoValues/queriedCoStream.ts +125 -0
- package/src/queries.ts +83 -460
- package/src/sync.ts +2 -2
- package/src/tests/account.test.ts +3 -6
- package/src/tests/coValue.test.ts +116 -110
- package/src/tests/coValueCore.test.ts +1 -1
- package/src/tests/crypto.test.ts +19 -21
- package/src/tests/permissions.test.ts +255 -242
- package/src/tests/queries.test.ts +57 -40
- package/src/tests/sync.test.ts +30 -30
- package/src/tests/testUtils.ts +3 -3
- package/dist/coValues/static.d.ts +0 -14
- package/dist/coValues/static.js +0 -20
- package/dist/coValues/static.js.map +0 -1
- package/dist/node.js.map +0 -1
- package/src/coValues/static.ts +0 -31
package/src/queries.ts
CHANGED
|
@@ -1,187 +1,26 @@
|
|
|
1
1
|
import { JsonValue } from "./jsonValue.js";
|
|
2
|
-
import { CoMap
|
|
2
|
+
import { CoMap } from "./coValues/coMap.js";
|
|
3
|
+
import { CoStream } from "./coValues/coStream.js";
|
|
4
|
+
import { CoList } from "./coValues/coList.js";
|
|
5
|
+
import { AccountID } from "./account.js";
|
|
6
|
+
import { AnyCoList, AnyCoMap, AnyCoStream, CoID, CoValue } from "./coValue.js";
|
|
7
|
+
import { LocalNode } from "./localNode.js";
|
|
3
8
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "./
|
|
10
|
-
import { Static } from "./coValues/static.js";
|
|
11
|
-
import { CoList, WriteableCoList } from "./coValues/coList.js";
|
|
12
|
-
import { CoValueCore, accountOrAgentIDfromSessionID } from "./coValueCore.js";
|
|
13
|
-
import { Group } from "./group.js";
|
|
14
|
-
import { AccountID, Profile, isAccountID } from "./account.js";
|
|
15
|
-
import {
|
|
16
|
-
AnyBinaryCoStream,
|
|
17
|
-
AnyCoList,
|
|
18
|
-
AnyCoMap,
|
|
19
|
-
AnyCoStream,
|
|
20
|
-
AnyCoValue,
|
|
21
|
-
AnyStatic,
|
|
22
|
-
CoID,
|
|
23
|
-
CoValue,
|
|
24
|
-
} from "./coValue.js";
|
|
25
|
-
import { SessionID } from "./ids.js";
|
|
26
|
-
import { LocalNode } from "./node.js";
|
|
27
|
-
|
|
28
|
-
export const AllReservedQueryProps = [
|
|
29
|
-
"id",
|
|
30
|
-
"type",
|
|
31
|
-
"meta",
|
|
32
|
-
"core",
|
|
33
|
-
"group",
|
|
34
|
-
"shadowed",
|
|
35
|
-
"edit",
|
|
36
|
-
"edits",
|
|
37
|
-
] as const;
|
|
38
|
-
|
|
39
|
-
export type ReservedQueryProps = (typeof AllReservedQueryProps)[number];
|
|
40
|
-
|
|
41
|
-
export type QueriedCoMap<T extends AnyCoMap> = T extends CoMap<
|
|
42
|
-
infer M,
|
|
43
|
-
infer Meta
|
|
44
|
-
>
|
|
45
|
-
? Readonly<{
|
|
46
|
-
[K in keyof M as Exclude<K, ReservedQueryProps>]: ValueOrSubQueried<
|
|
47
|
-
M[K]
|
|
48
|
-
>;
|
|
49
|
-
}> &
|
|
50
|
-
(keyof M & ReservedQueryProps extends never
|
|
51
|
-
? // eslint-disable-next-line @typescript-eslint/ban-types
|
|
52
|
-
{}
|
|
53
|
-
: Readonly<{
|
|
54
|
-
shadowed: Readonly<{
|
|
55
|
-
[K in keyof M as Extract<
|
|
56
|
-
K,
|
|
57
|
-
ReservedQueryProps
|
|
58
|
-
>]: ValueOrSubQueried<M[K]>;
|
|
59
|
-
}>;
|
|
60
|
-
}>) &
|
|
61
|
-
Readonly<{
|
|
62
|
-
id: CoID<T>;
|
|
63
|
-
type: "comap";
|
|
64
|
-
edits: Readonly<{
|
|
65
|
-
[K in keyof M & string]: Readonly<{
|
|
66
|
-
by?: QueriedAccountAndProfile;
|
|
67
|
-
at: Date;
|
|
68
|
-
// all: TODO;
|
|
69
|
-
}>;
|
|
70
|
-
}>;
|
|
71
|
-
meta: Meta;
|
|
72
|
-
group: Group;
|
|
73
|
-
core: CoValueCore;
|
|
74
|
-
edit: (changer: (editable: WriteableCoMap<M, Meta>) => void) => T;
|
|
75
|
-
}>
|
|
76
|
-
: never;
|
|
77
|
-
|
|
78
|
-
export type QueriedAccountAndProfile = Readonly<{
|
|
79
|
-
id: AccountID;
|
|
80
|
-
profile?: Readonly<{ name?: string; id: CoID<Profile> }>;
|
|
81
|
-
isMe?: boolean;
|
|
82
|
-
}>;
|
|
83
|
-
|
|
84
|
-
export type QueriedCoList<T extends AnyCoList> = T extends CoList<
|
|
85
|
-
infer I,
|
|
86
|
-
infer Meta
|
|
87
|
-
>
|
|
88
|
-
? readonly ValueOrSubQueried<I>[] &
|
|
89
|
-
Readonly<{
|
|
90
|
-
id: CoID<T>;
|
|
91
|
-
type: "colist";
|
|
92
|
-
meta: Meta;
|
|
93
|
-
group: Group;
|
|
94
|
-
core: CoValueCore;
|
|
95
|
-
edit: (
|
|
96
|
-
changer: (editable: WriteableCoList<I, Meta>) => void
|
|
97
|
-
) => T;
|
|
98
|
-
edits: readonly Readonly<{
|
|
99
|
-
by?: QueriedAccountAndProfile;
|
|
100
|
-
at: Date;
|
|
101
|
-
}>[] & {
|
|
102
|
-
// deletions: TODO;
|
|
103
|
-
};
|
|
104
|
-
}>
|
|
105
|
-
: never;
|
|
106
|
-
|
|
107
|
-
export type QueriedCoStreamItems<I extends JsonValue | CoValue> = Readonly<{
|
|
108
|
-
last: ValueOrSubQueried<I> | undefined;
|
|
109
|
-
by?: QueriedAccountAndProfile;
|
|
110
|
-
at?: Date;
|
|
111
|
-
all: { value: ValueOrSubQueried<I>; at: Date }[];
|
|
112
|
-
}>;
|
|
113
|
-
|
|
114
|
-
export type QueriedCoStream<T extends AnyCoStream> = T extends CoStream<
|
|
115
|
-
infer I,
|
|
116
|
-
infer Meta
|
|
117
|
-
>
|
|
118
|
-
? Readonly<{
|
|
119
|
-
id: CoID<T>;
|
|
120
|
-
type: "costream";
|
|
121
|
-
me?: QueriedCoStreamItems<I>;
|
|
122
|
-
perAccount: Readonly<{
|
|
123
|
-
[account: AccountID]: QueriedCoStreamItems<I>;
|
|
124
|
-
}>;
|
|
125
|
-
perSession: Readonly<{
|
|
126
|
-
[session: SessionID]: QueriedCoStreamItems<I>;
|
|
127
|
-
}>;
|
|
128
|
-
meta: Meta;
|
|
129
|
-
group: Group;
|
|
130
|
-
core: CoValueCore;
|
|
131
|
-
edit: (changer: (editable: WriteableCoStream<I, Meta>) => void) => T;
|
|
132
|
-
}>
|
|
133
|
-
: never;
|
|
134
|
-
|
|
135
|
-
export type QueriedBinaryCoStreamItems = Readonly<{
|
|
136
|
-
last: Uint8Array | undefined;
|
|
137
|
-
by: QueriedAccountAndProfile;
|
|
138
|
-
at: Date;
|
|
139
|
-
all: { value: Uint8Array; at: Date }[];
|
|
140
|
-
}>;
|
|
141
|
-
|
|
142
|
-
export type QueriedBinaryCoStream<T extends AnyBinaryCoStream> =
|
|
143
|
-
T extends BinaryCoStream<infer Meta>
|
|
144
|
-
? Readonly<
|
|
145
|
-
{
|
|
146
|
-
id: CoID<T>;
|
|
147
|
-
type: "costream";
|
|
148
|
-
me?: QueriedBinaryCoStreamItems;
|
|
149
|
-
perAccount: Readonly<{
|
|
150
|
-
[account: AccountID]: QueriedBinaryCoStreamItems;
|
|
151
|
-
}>;
|
|
152
|
-
perSession: Readonly<{
|
|
153
|
-
[session: SessionID]: QueriedBinaryCoStreamItems;
|
|
154
|
-
}>;
|
|
155
|
-
meta: Meta;
|
|
156
|
-
group: Group;
|
|
157
|
-
core: CoValueCore;
|
|
158
|
-
edit: (
|
|
159
|
-
changer: (editable: WriteableBinaryCoStream<Meta>) => void
|
|
160
|
-
) => T;
|
|
161
|
-
}
|
|
162
|
-
> & Readonly<BinaryStreamInfo>
|
|
163
|
-
: never;
|
|
164
|
-
|
|
165
|
-
export type QueriedStatic<T extends AnyStatic> = T extends Static<infer Meta>
|
|
166
|
-
? Readonly<{
|
|
167
|
-
id: CoID<T>;
|
|
168
|
-
type: "colist";
|
|
169
|
-
meta: Meta;
|
|
170
|
-
group: Group;
|
|
171
|
-
core: CoValueCore;
|
|
172
|
-
}>
|
|
173
|
-
: never;
|
|
9
|
+
QueriedAccountAndProfile,
|
|
10
|
+
QueriedCoMap,
|
|
11
|
+
QueriedCoMapBase,
|
|
12
|
+
} from "./queriedCoValues/queriedCoMap.js";
|
|
13
|
+
import { QueriedCoList } from "./queriedCoValues/queriedCoList.js";
|
|
14
|
+
import { QueriedCoStream } from "./queriedCoValues/queriedCoStream.js";
|
|
174
15
|
|
|
175
16
|
export type Queried<T extends CoValue> = T extends AnyCoMap
|
|
176
17
|
? QueriedCoMap<T>
|
|
177
18
|
: T extends AnyCoList
|
|
178
19
|
? QueriedCoList<T>
|
|
179
|
-
// : T extends BinaryCoStream<infer _>
|
|
180
|
-
// ? QueriedBinaryCoStream<T>
|
|
181
20
|
: T extends AnyCoStream
|
|
182
|
-
?
|
|
183
|
-
|
|
184
|
-
|
|
21
|
+
? T["meta"] extends { type: "binary" }
|
|
22
|
+
? never
|
|
23
|
+
: QueriedCoStream<T>
|
|
185
24
|
: never;
|
|
186
25
|
|
|
187
26
|
export type ValueOrSubQueried<
|
|
@@ -192,73 +31,79 @@ export type ValueOrSubQueried<
|
|
|
192
31
|
? Queried<V> | undefined
|
|
193
32
|
: V;
|
|
194
33
|
|
|
195
|
-
export
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
? {
|
|
200
|
-
[K in keyof M as M[K] extends AnyCoValue | CoID<AnyCoValue>
|
|
201
|
-
? K
|
|
202
|
-
: never]?: M[K] extends AnyCoValue
|
|
203
|
-
? true | QueryInclude<M[K]>
|
|
204
|
-
: M[K] extends CoID<infer S>
|
|
205
|
-
? true | QueryInclude<S>
|
|
206
|
-
: never;
|
|
207
|
-
}
|
|
208
|
-
: T extends CoList<infer I, infer _>
|
|
209
|
-
? I extends AnyCoValue
|
|
210
|
-
? [true] | [QueryInclude<I>]
|
|
211
|
-
: I extends CoID<infer S>
|
|
212
|
-
? [true] | [QueryInclude<S>]
|
|
213
|
-
: never
|
|
214
|
-
: never; // TODO add CoStream;
|
|
215
|
-
|
|
216
|
-
export function query<T extends CoValue>(
|
|
217
|
-
id: CoID<T>,
|
|
218
|
-
node: LocalNode,
|
|
219
|
-
callback: (queried: Queried<T> | undefined) => void
|
|
220
|
-
): () => void {
|
|
221
|
-
console.log("querying", id);
|
|
34
|
+
export interface CleanupCallbackAndUsable {
|
|
35
|
+
(): void;
|
|
36
|
+
[Symbol.dispose]: () => void;
|
|
37
|
+
}
|
|
222
38
|
|
|
223
|
-
|
|
39
|
+
export class QueryContext {
|
|
40
|
+
values: {
|
|
224
41
|
[id: CoID<CoValue>]: {
|
|
225
|
-
lastQueried:
|
|
42
|
+
lastQueried: Queried<CoValue> | undefined;
|
|
226
43
|
unsubscribe: () => void;
|
|
227
44
|
};
|
|
228
45
|
} = {};
|
|
46
|
+
node: LocalNode;
|
|
47
|
+
onUpdate: () => void;
|
|
229
48
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
onUpdate
|
|
233
|
-
}
|
|
49
|
+
constructor(node: LocalNode, onUpdate: () => void) {
|
|
50
|
+
this.node = node;
|
|
51
|
+
this.onUpdate = onUpdate;
|
|
52
|
+
}
|
|
234
53
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (!child) {
|
|
240
|
-
child = {
|
|
54
|
+
getChildLastQueriedOrSubscribe<T extends CoValue>(valueID: CoID<T>) {
|
|
55
|
+
let value = this.values[valueID];
|
|
56
|
+
if (!value) {
|
|
57
|
+
value = {
|
|
241
58
|
lastQueried: undefined,
|
|
242
|
-
unsubscribe: query(
|
|
243
|
-
|
|
244
|
-
onUpdate();
|
|
59
|
+
unsubscribe: query(valueID, this.node, (childQueried) => {
|
|
60
|
+
value!.lastQueried = childQueried as Queried<CoValue>;
|
|
61
|
+
this.onUpdate();
|
|
245
62
|
}),
|
|
246
63
|
};
|
|
247
|
-
|
|
64
|
+
this.values[valueID] = value;
|
|
248
65
|
}
|
|
249
|
-
return
|
|
66
|
+
return value.lastQueried as Queried<T> | undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
resolveAccount(accountID: AccountID) {
|
|
70
|
+
return this.getChildLastQueriedOrSubscribe(
|
|
71
|
+
accountID
|
|
72
|
+
) as QueriedAccountAndProfile;
|
|
250
73
|
}
|
|
251
74
|
|
|
252
|
-
|
|
75
|
+
resolveValue<T extends JsonValue>(
|
|
253
76
|
value: T
|
|
254
|
-
): T extends CoID<
|
|
77
|
+
): T extends CoID<infer C> ? Queried<C> | undefined : T {
|
|
255
78
|
return (
|
|
256
79
|
typeof value === "string" && value.startsWith("co_")
|
|
257
|
-
? getChildLastQueriedOrSubscribe(value as CoID<CoValue>)
|
|
80
|
+
? this.getChildLastQueriedOrSubscribe(value as CoID<CoValue>)
|
|
258
81
|
: value
|
|
259
|
-
) as T extends CoID<
|
|
82
|
+
) as T extends CoID<infer C> ? Queried<C> | undefined : T;
|
|
260
83
|
}
|
|
261
84
|
|
|
85
|
+
cleanup() {
|
|
86
|
+
for (const child of Object.values(this.values)) {
|
|
87
|
+
child.unsubscribe();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function query<T extends CoValue>(
|
|
93
|
+
id: CoID<T>,
|
|
94
|
+
node: LocalNode,
|
|
95
|
+
callback: (queried: Queried<T> | undefined) => void,
|
|
96
|
+
parentContext?: QueryContext
|
|
97
|
+
): CleanupCallbackAndUsable {
|
|
98
|
+
console.log("querying", id);
|
|
99
|
+
|
|
100
|
+
const context = parentContext || new QueryContext(node, onUpdate);
|
|
101
|
+
|
|
102
|
+
const unsubscribe = node.subscribe(id, (update) => {
|
|
103
|
+
lastRootValue = update;
|
|
104
|
+
onUpdate();
|
|
105
|
+
});
|
|
106
|
+
|
|
262
107
|
let lastRootValue: T | undefined;
|
|
263
108
|
|
|
264
109
|
function onUpdate() {
|
|
@@ -269,251 +114,29 @@ export function query<T extends CoValue>(
|
|
|
269
114
|
}
|
|
270
115
|
|
|
271
116
|
if (rootValue instanceof CoMap) {
|
|
272
|
-
callback(
|
|
117
|
+
callback(
|
|
118
|
+
QueriedCoMapBase.newWithKVPairs(
|
|
119
|
+
rootValue,
|
|
120
|
+
context
|
|
121
|
+
) as Queried<T>
|
|
122
|
+
);
|
|
273
123
|
} else if (rootValue instanceof CoList) {
|
|
274
|
-
callback(
|
|
124
|
+
callback(new QueriedCoList(rootValue, context) as Queried<T>);
|
|
275
125
|
} else if (rootValue instanceof CoStream) {
|
|
276
126
|
if (rootValue.meta?.type === "binary") {
|
|
277
127
|
// Querying binary string not yet implemented
|
|
278
|
-
return {}
|
|
128
|
+
return {};
|
|
279
129
|
} else {
|
|
280
|
-
callback(
|
|
130
|
+
callback(new QueriedCoStream(rootValue, context) as Queried<T>);
|
|
281
131
|
}
|
|
282
132
|
}
|
|
283
133
|
}
|
|
284
134
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
child.unsubscribe();
|
|
288
|
-
}
|
|
135
|
+
const cleanup = function cleanup() {
|
|
136
|
+
context.cleanup();
|
|
289
137
|
unsubscribe();
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
function queryMap(rootValue: T & CoMap<any, any>) {
|
|
293
|
-
const mapResult: {
|
|
294
|
-
[key: string]: any;
|
|
295
|
-
} = {};
|
|
296
|
-
// let allChildrenAvailable = true;
|
|
297
|
-
for (const key of rootValue.keys()) {
|
|
298
|
-
const value = rootValue.get(key);
|
|
299
|
-
|
|
300
|
-
if (value === undefined) continue;
|
|
301
|
-
|
|
302
|
-
if (AllReservedQueryProps.includes(key as ReservedQueryProps)) {
|
|
303
|
-
mapResult.shadowed = mapResult.shadowed || {};
|
|
304
|
-
mapResult.shadowed[key] = resolveValue(value);
|
|
305
|
-
} else {
|
|
306
|
-
mapResult[key] = resolveValue(value);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
Object.defineProperties(mapResult, {
|
|
311
|
-
id: { value: rootValue.id },
|
|
312
|
-
type: { value: "comap" },
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
if (
|
|
316
|
-
rootValue.meta?.type !== "account" &&
|
|
317
|
-
rootValue.meta?.type !== "profile"
|
|
318
|
-
) {
|
|
319
|
-
Object.defineProperties(mapResult, {
|
|
320
|
-
edit: {
|
|
321
|
-
value: (
|
|
322
|
-
changer: (editable: WriteableCoMap<any, any>) => void
|
|
323
|
-
) => {
|
|
324
|
-
rootValue.edit(changer);
|
|
325
|
-
return rootValue;
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
edits: {
|
|
329
|
-
value: {},
|
|
330
|
-
},
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
for (const key of rootValue.keys()) {
|
|
334
|
-
const editorID = rootValue.whoEdited(key);
|
|
335
|
-
const editor =
|
|
336
|
-
editorID && getChildLastQueriedOrSubscribe(editorID);
|
|
337
|
-
mapResult.edits[key] = {
|
|
338
|
-
by: editor && {
|
|
339
|
-
id: editorID,
|
|
340
|
-
isMe: editorID === node.account.id ? true : undefined,
|
|
341
|
-
profile: editor.profile && {
|
|
342
|
-
id: editor.profile.id,
|
|
343
|
-
name: editor.profile.name,
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
at: new Date(rootValue.getLastEntry(key)!.at),
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
Object.defineProperties(mapResult, {
|
|
352
|
-
meta: { value: rootValue.meta },
|
|
353
|
-
group: {
|
|
354
|
-
get() {
|
|
355
|
-
return rootValue.group;
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
core: {
|
|
359
|
-
get() {
|
|
360
|
-
return rootValue.core;
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
return mapResult;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function queryList(rootValue: T & CoList<any, any>) {
|
|
368
|
-
const arr: any[] & { [key: string]: any } = rootValue
|
|
369
|
-
.asArray()
|
|
370
|
-
.map(resolveValue);
|
|
371
|
-
|
|
372
|
-
Object.defineProperties(arr, {
|
|
373
|
-
type: { value: "colist" },
|
|
374
|
-
id: { value: rootValue.id },
|
|
375
|
-
edit: {
|
|
376
|
-
value: (
|
|
377
|
-
changer: (editable: WriteableCoList<any, any>) => void
|
|
378
|
-
) => {
|
|
379
|
-
rootValue.edit(changer);
|
|
380
|
-
return rootValue;
|
|
381
|
-
},
|
|
382
|
-
},
|
|
383
|
-
edits: {
|
|
384
|
-
value: [],
|
|
385
|
-
},
|
|
386
|
-
meta: { value: rootValue.meta },
|
|
387
|
-
group: {
|
|
388
|
-
get() {
|
|
389
|
-
return rootValue.group;
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
core: {
|
|
393
|
-
get() {
|
|
394
|
-
return rootValue.core;
|
|
395
|
-
},
|
|
396
|
-
},
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
for (let i = 0; i < arr.length; i++) {
|
|
400
|
-
const editorID = rootValue.whoInserted(i);
|
|
401
|
-
const editor = editorID && getChildLastQueriedOrSubscribe(editorID);
|
|
402
|
-
arr.edits[i] = {
|
|
403
|
-
by: editor && {
|
|
404
|
-
id: editorID,
|
|
405
|
-
isMe: editorID === node.account.id ? true : undefined,
|
|
406
|
-
profile: editor.profile && {
|
|
407
|
-
id: editor.profile.id,
|
|
408
|
-
name: editor.profile.name,
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
at: new Date(rootValue.entries()[i]!.madeAt),
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
return arr;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function queryStream(rootValue: T & CoStream<any, any>) {
|
|
418
|
-
const seenAccounts = new Set<AccountID>();
|
|
419
|
-
|
|
420
|
-
const perSession = Object.fromEntries(
|
|
421
|
-
Object.entries(rootValue.items).map(([sessionID, items]) => {
|
|
422
|
-
const editorID = accountOrAgentIDfromSessionID(
|
|
423
|
-
sessionID as SessionID
|
|
424
|
-
);
|
|
425
|
-
if (isAccountID(editorID)) seenAccounts.add(editorID);
|
|
426
|
-
const editor =
|
|
427
|
-
editorID &&
|
|
428
|
-
(isAccountID(editorID)
|
|
429
|
-
? getChildLastQueriedOrSubscribe(editorID)
|
|
430
|
-
: undefined);
|
|
431
|
-
const lastItem = items[items.length - 1];
|
|
432
|
-
return [
|
|
433
|
-
sessionID as SessionID,
|
|
434
|
-
{
|
|
435
|
-
last: lastItem && resolveValue(lastItem.item),
|
|
436
|
-
by: editor && {
|
|
437
|
-
id: editorID as AccountID,
|
|
438
|
-
isMe:
|
|
439
|
-
editorID === node.account.id ? true : undefined,
|
|
440
|
-
profile: editor.profile && {
|
|
441
|
-
id: editor.profile.id,
|
|
442
|
-
name: editor.profile.name,
|
|
443
|
-
},
|
|
444
|
-
},
|
|
445
|
-
at: lastItem && new Date(lastItem.madeAt),
|
|
446
|
-
all: items.map((item) => ({
|
|
447
|
-
value: item.item && resolveValue(item.item),
|
|
448
|
-
at: new Date(item.madeAt),
|
|
449
|
-
})),
|
|
450
|
-
} satisfies QueriedCoStreamItems<JsonValue>,
|
|
451
|
-
];
|
|
452
|
-
})
|
|
453
|
-
);
|
|
454
|
-
|
|
455
|
-
const perAccount = Object.fromEntries(
|
|
456
|
-
[...seenAccounts.values()].map((accountID) => {
|
|
457
|
-
const itemsFromAllMatchingSessions = Object.entries(perSession)
|
|
458
|
-
.flatMap(([sessionID, sessionItems]) =>
|
|
459
|
-
sessionID.startsWith(accountID) ? sessionItems.all : []
|
|
460
|
-
)
|
|
461
|
-
.sort((a, b) => {
|
|
462
|
-
return a.at.getTime() - b.at.getTime();
|
|
463
|
-
});
|
|
464
|
-
const editor = getChildLastQueriedOrSubscribe(accountID);
|
|
465
|
-
const lastItem =
|
|
466
|
-
itemsFromAllMatchingSessions[
|
|
467
|
-
itemsFromAllMatchingSessions.length - 1
|
|
468
|
-
];
|
|
469
|
-
|
|
470
|
-
return [
|
|
471
|
-
accountID,
|
|
472
|
-
{
|
|
473
|
-
last: lastItem?.value,
|
|
474
|
-
by: editor && {
|
|
475
|
-
id: accountID,
|
|
476
|
-
isMe:
|
|
477
|
-
accountID === node.account.id
|
|
478
|
-
? true
|
|
479
|
-
: undefined,
|
|
480
|
-
profile: editor.profile && {
|
|
481
|
-
id: editor.profile.id,
|
|
482
|
-
name: editor.profile.name,
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
at: lastItem && new Date(lastItem.at),
|
|
486
|
-
all: itemsFromAllMatchingSessions,
|
|
487
|
-
} satisfies QueriedCoStreamItems<JsonValue>,
|
|
488
|
-
];
|
|
489
|
-
})
|
|
490
|
-
);
|
|
138
|
+
} as CleanupCallbackAndUsable;
|
|
139
|
+
cleanup[Symbol.dispose] = cleanup;
|
|
491
140
|
|
|
492
|
-
|
|
493
|
-
? perAccount[node.account.id]
|
|
494
|
-
: undefined;
|
|
495
|
-
|
|
496
|
-
const streamResult: QueriedCoStream<AnyCoStream> = {
|
|
497
|
-
type: "costream",
|
|
498
|
-
id: rootValue.id,
|
|
499
|
-
perSession,
|
|
500
|
-
perAccount,
|
|
501
|
-
me,
|
|
502
|
-
meta: rootValue.meta,
|
|
503
|
-
get group() {
|
|
504
|
-
return rootValue.group;
|
|
505
|
-
},
|
|
506
|
-
get core() {
|
|
507
|
-
return rootValue.core;
|
|
508
|
-
},
|
|
509
|
-
edit: (
|
|
510
|
-
changer: (editable: WriteableCoStream<any, any>) => void
|
|
511
|
-
) => {
|
|
512
|
-
rootValue.edit(changer);
|
|
513
|
-
return rootValue;
|
|
514
|
-
},
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
return streamResult;
|
|
518
|
-
}
|
|
141
|
+
return cleanup;
|
|
519
142
|
}
|
package/src/sync.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Signature } from "./crypto.js";
|
|
2
2
|
import { CoValueHeader, Transaction } from "./coValueCore.js";
|
|
3
3
|
import { CoValueCore } from "./coValueCore.js";
|
|
4
|
-
import { LocalNode } from "./
|
|
5
|
-
import { newLoadingState } from "./
|
|
4
|
+
import { LocalNode } from "./localNode.js";
|
|
5
|
+
import { newLoadingState } from "./localNode.js";
|
|
6
6
|
import {
|
|
7
7
|
ReadableStream,
|
|
8
8
|
WritableStream,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { newRandomSessionID } from "../coValueCore.js";
|
|
2
2
|
import { cojsonReady } from "../index.js";
|
|
3
|
-
import { LocalNode } from "../
|
|
3
|
+
import { LocalNode } from "../localNode.js";
|
|
4
4
|
import { connectedPeers } from "../streamUtils.js";
|
|
5
5
|
|
|
6
6
|
beforeEach(async () => {
|
|
@@ -19,9 +19,6 @@ test("Can create a node while creating a new account with profile", async () =>
|
|
|
19
19
|
expect(node.expectProfileLoaded(accountID).get("name")).toEqual(
|
|
20
20
|
"Hermes Puggington"
|
|
21
21
|
);
|
|
22
|
-
expect((await node.loadProfile(accountID)).get("name")).toEqual(
|
|
23
|
-
"Hermes Puggington"
|
|
24
|
-
);
|
|
25
22
|
});
|
|
26
23
|
|
|
27
24
|
test("A node with an account can create groups and and objects within them", async () => {
|
|
@@ -39,7 +36,7 @@ test("A node with an account can create groups and and objects within them", asy
|
|
|
39
36
|
|
|
40
37
|
expect(map.get("foo")).toEqual("bar");
|
|
41
38
|
|
|
42
|
-
expect(map.
|
|
39
|
+
expect(map.lastEditAt("foo")?.by).toEqual(accountID);
|
|
43
40
|
});
|
|
44
41
|
|
|
45
42
|
test("Can create account with one node, and then load it on another", async () => {
|
|
@@ -57,7 +54,7 @@ test("Can create account with one node, and then load it on another", async () =
|
|
|
57
54
|
|
|
58
55
|
const [node1asPeer, node2asPeer] = connectedPeers("node1", "node2", {trace: true, peer1role: "server", peer2role: "client"});
|
|
59
56
|
|
|
60
|
-
node.
|
|
57
|
+
node.syncManager.addPeer(node2asPeer);
|
|
61
58
|
|
|
62
59
|
const node2 = await LocalNode.withLoadedAccount(
|
|
63
60
|
accountID,
|