@peerbit/document 2.0.1 → 3.0.1
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/lib/esm/document-index.d.ts +17 -12
- package/lib/esm/document-index.js +89 -50
- package/lib/esm/document-index.js.map +1 -1
- package/lib/esm/document-store.d.ts +18 -11
- package/lib/esm/document-store.js +31 -17
- package/lib/esm/document-store.js.map +1 -1
- package/lib/esm/query.d.ts +5 -1
- package/lib/esm/query.js +11 -3
- package/lib/esm/query.js.map +1 -1
- package/package.json +6 -6
- package/src/document-index.ts +162 -75
- package/src/document-store.ts +65 -27
- package/src/query.ts +10 -3
package/src/document-store.ts
CHANGED
|
@@ -5,10 +5,9 @@ import {
|
|
|
5
5
|
serialize,
|
|
6
6
|
variant,
|
|
7
7
|
} from "@dao-xyz/borsh";
|
|
8
|
-
import {
|
|
8
|
+
import { Change, Entry, EntryType, TrimOptions } from "@peerbit/log";
|
|
9
9
|
import { Program, ProgramEvents } from "@peerbit/program";
|
|
10
|
-
import {
|
|
11
|
-
import { AccessError, DecryptedThing } from "@peerbit/crypto";
|
|
10
|
+
import { AccessError, DecryptedThing, PublicSignKey } from "@peerbit/crypto";
|
|
12
11
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
13
12
|
import { AppendOptions } from "@peerbit/log";
|
|
14
13
|
import { CustomEvent } from "@libp2p/interfaces/events";
|
|
@@ -18,16 +17,19 @@ import {
|
|
|
18
17
|
Replicator,
|
|
19
18
|
SharedLog,
|
|
20
19
|
SharedLogOptions,
|
|
20
|
+
SharedAppendOptions,
|
|
21
21
|
} from "@peerbit/shared-log";
|
|
22
22
|
export { Role, Observer, Replicator }; // For convenience (so that consumers does not have to do the import above from shared-log packages)
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
|
-
|
|
25
|
+
IndexableFields,
|
|
26
26
|
BORSH_ENCODING_OPERATION,
|
|
27
27
|
DeleteOperation,
|
|
28
28
|
DocumentIndex,
|
|
29
29
|
Operation,
|
|
30
30
|
PutOperation,
|
|
31
|
+
CanSearch,
|
|
32
|
+
CanRead,
|
|
31
33
|
} from "./document-index.js";
|
|
32
34
|
import { asString, checkKeyable, Keyable } from "./utils.js";
|
|
33
35
|
import { Context, Results } from "./query.js";
|
|
@@ -47,16 +49,30 @@ export interface DocumentEvents<T> {
|
|
|
47
49
|
change: CustomEvent<DocumentsChange<T>>;
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
export type TransactionContext<T> = {
|
|
53
|
+
entry: Entry<Operation<T>>;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type MaybePromise = Promise<boolean> | boolean;
|
|
57
|
+
|
|
58
|
+
export type CanPerform<T> = (
|
|
59
|
+
operation: PutOperation<T> | DeleteOperation,
|
|
60
|
+
context: TransactionContext<T>
|
|
61
|
+
) => MaybePromise;
|
|
62
|
+
|
|
50
63
|
export type SetupOptions<T> = {
|
|
51
64
|
type: AbstractType<T>;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
canOpen?: (program: T) => Promise<boolean> | boolean;
|
|
65
|
+
canOpen?: (program: T) => MaybePromise;
|
|
66
|
+
canPerform?: CanPerform<T>;
|
|
55
67
|
index?: {
|
|
56
68
|
key?: string | string[];
|
|
57
|
-
fields?:
|
|
69
|
+
fields?: IndexableFields<T>;
|
|
70
|
+
canSearch?: CanSearch;
|
|
71
|
+
canRead?: CanRead<T>;
|
|
72
|
+
};
|
|
73
|
+
log?: {
|
|
74
|
+
trim?: TrimOptions;
|
|
58
75
|
};
|
|
59
|
-
trim?: TrimOptions;
|
|
60
76
|
} & SharedLogOptions;
|
|
61
77
|
|
|
62
78
|
@variant("documents")
|
|
@@ -75,7 +91,8 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
75
91
|
|
|
76
92
|
private _clazz?: AbstractType<T>;
|
|
77
93
|
|
|
78
|
-
private
|
|
94
|
+
private _optionCanPerform?: CanPerform<T>;
|
|
95
|
+
|
|
79
96
|
canOpen?: (
|
|
80
97
|
program: T,
|
|
81
98
|
entry: Entry<Operation<T>>
|
|
@@ -109,14 +126,14 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
109
126
|
);
|
|
110
127
|
}
|
|
111
128
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
129
|
+
|
|
130
|
+
this._optionCanPerform = options.canPerform;
|
|
115
131
|
|
|
116
132
|
await this._index.open({
|
|
117
133
|
type: this._clazz,
|
|
118
134
|
log: this.log,
|
|
119
|
-
canRead: options
|
|
135
|
+
canRead: options?.index?.canRead,
|
|
136
|
+
canSearch: options.index?.canSearch,
|
|
120
137
|
fields: options.index?.fields || ((obj) => obj),
|
|
121
138
|
indexBy: options.index?.key,
|
|
122
139
|
sync: async (result: Results<T>) =>
|
|
@@ -125,12 +142,13 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
125
142
|
|
|
126
143
|
await this.log.open({
|
|
127
144
|
encoding: BORSH_ENCODING_OPERATION,
|
|
145
|
+
canReplicate: options?.canReplicate,
|
|
128
146
|
canAppend: this.canAppend.bind(this),
|
|
129
147
|
onChange: this.handleChanges.bind(this),
|
|
130
|
-
trim: options?.trim,
|
|
148
|
+
trim: options?.log?.trim,
|
|
131
149
|
sync: options?.sync,
|
|
132
150
|
role: options?.role,
|
|
133
|
-
|
|
151
|
+
replicas: options?.replicas,
|
|
134
152
|
});
|
|
135
153
|
}
|
|
136
154
|
|
|
@@ -150,8 +168,22 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
150
168
|
return false;
|
|
151
169
|
}
|
|
152
170
|
|
|
153
|
-
if (this.
|
|
154
|
-
|
|
171
|
+
if (this._optionCanPerform) {
|
|
172
|
+
const payload = await entry.getPayloadValue();
|
|
173
|
+
|
|
174
|
+
if (payload instanceof PutOperation) {
|
|
175
|
+
payload.getValue(this.index.valueEncoding); // Decode they value so callbacks can jsut do .value
|
|
176
|
+
}
|
|
177
|
+
if (
|
|
178
|
+
!(await this._optionCanPerform(
|
|
179
|
+
payload as PutOperation<T> | DeleteOperation,
|
|
180
|
+
{
|
|
181
|
+
entry,
|
|
182
|
+
}
|
|
183
|
+
))
|
|
184
|
+
) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
155
187
|
}
|
|
156
188
|
return true;
|
|
157
189
|
}
|
|
@@ -248,7 +280,7 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
248
280
|
|
|
249
281
|
public async put(
|
|
250
282
|
doc: T,
|
|
251
|
-
options?:
|
|
283
|
+
options?: SharedAppendOptions<Operation<T>> & { unique?: boolean }
|
|
252
284
|
) {
|
|
253
285
|
const key = this._index.indexByResolver(doc as any as Keyable);
|
|
254
286
|
checkKeyable(key);
|
|
@@ -269,10 +301,13 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
269
301
|
value: doc,
|
|
270
302
|
}),
|
|
271
303
|
{
|
|
272
|
-
nexts: existingDocument
|
|
273
|
-
? [await this._resolveEntry(existingDocument.context.head)]
|
|
274
|
-
: [], //
|
|
275
304
|
...options,
|
|
305
|
+
meta: {
|
|
306
|
+
next: existingDocument
|
|
307
|
+
? [await this._resolveEntry(existingDocument.context.head)]
|
|
308
|
+
: [],
|
|
309
|
+
...options?.meta,
|
|
310
|
+
}, //
|
|
276
311
|
}
|
|
277
312
|
);
|
|
278
313
|
}
|
|
@@ -293,9 +328,12 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
293
328
|
key: asString(key),
|
|
294
329
|
}),
|
|
295
330
|
{
|
|
296
|
-
nexts: [await this._resolveEntry(existing.context.head)],
|
|
297
|
-
type: EntryType.CUT,
|
|
298
331
|
...options,
|
|
332
|
+
meta: {
|
|
333
|
+
next: [await this._resolveEntry(existing.context.head)],
|
|
334
|
+
type: EntryType.CUT,
|
|
335
|
+
...options?.meta,
|
|
336
|
+
},
|
|
299
337
|
} //
|
|
300
338
|
);
|
|
301
339
|
}
|
|
@@ -358,8 +396,8 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
358
396
|
const context = new Context({
|
|
359
397
|
created:
|
|
360
398
|
this._index.index.get(key)?.context.created ||
|
|
361
|
-
item.
|
|
362
|
-
modified: item.
|
|
399
|
+
item.meta.clock.timestamp.wallTime,
|
|
400
|
+
modified: item.meta.clock.timestamp.wallTime,
|
|
363
401
|
head: item.hash,
|
|
364
402
|
});
|
|
365
403
|
|
|
@@ -378,7 +416,7 @@ export class Documents<T extends Record<string, any>> extends Program<
|
|
|
378
416
|
if (
|
|
379
417
|
(await this.canOpen!(value, item)) &&
|
|
380
418
|
this.log.role instanceof Replicator &&
|
|
381
|
-
(await this.log.replicator(item
|
|
419
|
+
(await this.log.replicator(item)) // TODO types, throw runtime error if replicator is not provided
|
|
382
420
|
) {
|
|
383
421
|
await this.node.open(value, {
|
|
384
422
|
parent: this as Program<any, any>,
|
package/src/query.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
variant,
|
|
7
7
|
vec,
|
|
8
8
|
} from "@dao-xyz/borsh";
|
|
9
|
+
|
|
9
10
|
import { asString } from "./utils.js";
|
|
10
11
|
import { randomBytes, sha256Base64Sync } from "@peerbit/crypto";
|
|
11
12
|
|
|
@@ -431,8 +432,10 @@ export class ResultWithSource<T> extends Result {
|
|
|
431
432
|
}
|
|
432
433
|
}
|
|
433
434
|
|
|
435
|
+
export abstract class AbstractSearchResult<T> {}
|
|
436
|
+
|
|
434
437
|
@variant(0)
|
|
435
|
-
export class Results<T> {
|
|
438
|
+
export class Results<T> extends AbstractSearchResult<T> {
|
|
436
439
|
@field({ type: vec(ResultWithSource) })
|
|
437
440
|
results: ResultWithSource<T>[];
|
|
438
441
|
|
|
@@ -440,11 +443,15 @@ export class Results<T> {
|
|
|
440
443
|
kept: bigint; // how many results that were not sent, but can be collected later
|
|
441
444
|
|
|
442
445
|
constructor(properties: { results: ResultWithSource<T>[]; kept: bigint }) {
|
|
446
|
+
super();
|
|
443
447
|
this.kept = properties.kept;
|
|
444
448
|
this.results = properties.results;
|
|
445
449
|
}
|
|
446
450
|
}
|
|
447
451
|
|
|
452
|
+
@variant(1)
|
|
453
|
+
export class NoAccess extends AbstractSearchResult<any> {}
|
|
454
|
+
|
|
448
455
|
/* @variant(5)
|
|
449
456
|
export class LogQuery extends Query { } */
|
|
450
457
|
|
|
@@ -464,7 +471,7 @@ export class EntryEncryptedByQuery
|
|
|
464
471
|
>
|
|
465
472
|
{
|
|
466
473
|
@field({ type: vec(X25519PublicKey) })
|
|
467
|
-
|
|
474
|
+
meta: X25519PublicKey[];
|
|
468
475
|
|
|
469
476
|
@field({ type: vec(X25519PublicKey) })
|
|
470
477
|
payload: X25519PublicKey[];
|
|
@@ -476,7 +483,7 @@ export class EntryEncryptedByQuery
|
|
|
476
483
|
signatures: X25519PublicKey[];
|
|
477
484
|
|
|
478
485
|
constructor(properties?: {
|
|
479
|
-
|
|
486
|
+
meta: X25519PublicKey[];
|
|
480
487
|
next: X25519PublicKey[];
|
|
481
488
|
payload: X25519PublicKey[];
|
|
482
489
|
signatures: X25519PublicKey[];
|