@peerbit/document 15.0.13 → 15.0.14
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/src/callback-detachment.d.ts +14 -0
- package/dist/src/callback-detachment.d.ts.map +1 -0
- package/dist/src/callback-detachment.js +234 -0
- package/dist/src/callback-detachment.js.map +1 -0
- package/dist/src/domain.d.ts.map +1 -1
- package/dist/src/domain.js +5 -3
- package/dist/src/domain.js.map +1 -1
- package/dist/src/program.d.ts +4 -0
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +140 -39
- package/dist/src/program.js.map +1 -1
- package/package.json +11 -11
- package/src/callback-detachment.ts +308 -0
- package/src/domain.ts +11 -3
- package/src/program.ts +220 -48
package/src/program.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AbstractType,
|
|
3
3
|
BorshError,
|
|
4
|
+
deserialize,
|
|
4
5
|
field,
|
|
5
6
|
serialize,
|
|
6
7
|
variant,
|
|
@@ -44,6 +45,10 @@ import {
|
|
|
44
45
|
SharedLog,
|
|
45
46
|
type SharedLogOptions,
|
|
46
47
|
} from "@peerbit/shared-log";
|
|
48
|
+
import {
|
|
49
|
+
detachCanPerformCallbackProperties,
|
|
50
|
+
detachEntryPayloadForCallback,
|
|
51
|
+
} from "./callback-detachment.js";
|
|
47
52
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
48
53
|
import type { CustomDocumentDomain } from "./domain.js";
|
|
49
54
|
import type { DocumentEvents, DocumentsChange } from "./events.js";
|
|
@@ -1088,12 +1093,23 @@ export class Documents<
|
|
|
1088
1093
|
private _documentChangeListenerTrackingInitialized = false;
|
|
1089
1094
|
private _documentBackend!: DocumentBackend<T>;
|
|
1090
1095
|
private _canAppendDecodedDocuments = new WeakMap<PutOperation, T>();
|
|
1096
|
+
private acceptPutOperation(
|
|
1097
|
+
operation: PutOperation,
|
|
1098
|
+
document: T | undefined,
|
|
1099
|
+
hasDocument: boolean,
|
|
1100
|
+
): PutOperation {
|
|
1101
|
+
if (hasDocument) {
|
|
1102
|
+
this._canAppendDecodedDocuments.set(operation, document!);
|
|
1103
|
+
}
|
|
1104
|
+
return operation;
|
|
1105
|
+
}
|
|
1091
1106
|
private _nativeDocumentIdExtractionPlan?: SimpleDocumentFieldExtractionPlan;
|
|
1092
1107
|
private _nativeDocumentFieldExtractionPlans?: Map<
|
|
1093
1108
|
string,
|
|
1094
1109
|
SimpleDocumentFieldExtractionPlan | undefined
|
|
1095
1110
|
>;
|
|
1096
1111
|
private _hasLogTrim = false;
|
|
1112
|
+
private _hasCustomIdResolver = false;
|
|
1097
1113
|
private idResolver!: (any: any) => indexerTypes.Ideable;
|
|
1098
1114
|
private domain?: CustomDocumentDomain<InferR<D>>;
|
|
1099
1115
|
private strictHistory: boolean;
|
|
@@ -1131,6 +1147,84 @@ export class Documents<
|
|
|
1131
1147
|
);
|
|
1132
1148
|
}
|
|
1133
1149
|
|
|
1150
|
+
private detachDomainEntryCallback(
|
|
1151
|
+
domain: CustomDocumentDomain<InferR<D>>,
|
|
1152
|
+
): CustomDocumentDomain<InferR<D>> {
|
|
1153
|
+
const boundMethods = new Map<
|
|
1154
|
+
PropertyKey,
|
|
1155
|
+
{ source: Function; bound: Function }
|
|
1156
|
+
>();
|
|
1157
|
+
const detachedFromEntry = (
|
|
1158
|
+
entry: Parameters<CustomDocumentDomain<InferR<D>>["fromEntry"]>[0],
|
|
1159
|
+
) => {
|
|
1160
|
+
const fromEntry = Reflect.get(
|
|
1161
|
+
domain,
|
|
1162
|
+
"fromEntry",
|
|
1163
|
+
domain,
|
|
1164
|
+
) as CustomDocumentDomain<InferR<D>>["fromEntry"];
|
|
1165
|
+
return Reflect.apply(fromEntry, domain, [
|
|
1166
|
+
entry instanceof Entry
|
|
1167
|
+
? detachEntryPayloadForCallback(entry)
|
|
1168
|
+
: entry,
|
|
1169
|
+
]);
|
|
1170
|
+
};
|
|
1171
|
+
const facade = Object.create(
|
|
1172
|
+
Object.getPrototypeOf(domain),
|
|
1173
|
+
) as CustomDocumentDomain<InferR<D>>;
|
|
1174
|
+
let callbackDomain: CustomDocumentDomain<InferR<D>>;
|
|
1175
|
+
callbackDomain = new Proxy(facade, {
|
|
1176
|
+
get(_target, property) {
|
|
1177
|
+
if (property === "fromEntry") {
|
|
1178
|
+
return detachedFromEntry;
|
|
1179
|
+
}
|
|
1180
|
+
if (property === "valueOf") {
|
|
1181
|
+
return () => callbackDomain;
|
|
1182
|
+
}
|
|
1183
|
+
const value = Reflect.get(domain, property, domain);
|
|
1184
|
+
if (property === "constructor" || typeof value !== "function") {
|
|
1185
|
+
return value;
|
|
1186
|
+
}
|
|
1187
|
+
const existing = boundMethods.get(property);
|
|
1188
|
+
if (existing && existing.source === value) {
|
|
1189
|
+
return existing.bound;
|
|
1190
|
+
}
|
|
1191
|
+
const bound = value.bind(domain);
|
|
1192
|
+
boundMethods.set(property, { source: value, bound });
|
|
1193
|
+
return bound;
|
|
1194
|
+
},
|
|
1195
|
+
set(_target, property, value) {
|
|
1196
|
+
return Reflect.set(domain, property, value, domain);
|
|
1197
|
+
},
|
|
1198
|
+
has(_target, property) {
|
|
1199
|
+
return Reflect.has(domain, property);
|
|
1200
|
+
},
|
|
1201
|
+
ownKeys() {
|
|
1202
|
+
return Reflect.ownKeys(domain);
|
|
1203
|
+
},
|
|
1204
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
1205
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(domain, property);
|
|
1206
|
+
if (!descriptor) {
|
|
1207
|
+
return undefined;
|
|
1208
|
+
}
|
|
1209
|
+
if (property === "fromEntry") {
|
|
1210
|
+
return "value" in descriptor
|
|
1211
|
+
? {
|
|
1212
|
+
...descriptor,
|
|
1213
|
+
value: detachedFromEntry,
|
|
1214
|
+
configurable: true,
|
|
1215
|
+
}
|
|
1216
|
+
: {
|
|
1217
|
+
...descriptor,
|
|
1218
|
+
get: () => detachedFromEntry,
|
|
1219
|
+
configurable: true,
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
return { ...descriptor, configurable: true };
|
|
1223
|
+
},
|
|
1224
|
+
});
|
|
1225
|
+
return callbackDomain;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1134
1228
|
private createNativeDocumentBackendContext(): NativeDocumentBackendContext<
|
|
1135
1229
|
T,
|
|
1136
1230
|
I
|
|
@@ -2356,6 +2450,7 @@ export class Documents<
|
|
|
2356
2450
|
: (obj: any) =>
|
|
2357
2451
|
indexerTypes.extractFieldValue(obj, idProperty as string[]));
|
|
2358
2452
|
|
|
2453
|
+
this._hasCustomIdResolver = options.id != null;
|
|
2359
2454
|
this.idResolver = idResolver;
|
|
2360
2455
|
this.strictHistory = options.strictHistory ?? false;
|
|
2361
2456
|
this._hasLogTrim = options.log?.trim != null;
|
|
@@ -2404,7 +2499,9 @@ export class Documents<
|
|
|
2404
2499
|
// 7 -> log v9) is retired; the rejection at the top of open() fires for
|
|
2405
2500
|
// any defined value before this point.
|
|
2406
2501
|
|
|
2407
|
-
this.domain = options.domain
|
|
2502
|
+
this.domain = options.domain
|
|
2503
|
+
? this.detachDomainEntryCallback(options.domain(this))
|
|
2504
|
+
: undefined;
|
|
2408
2505
|
|
|
2409
2506
|
let keepFunction:
|
|
2410
2507
|
| ((
|
|
@@ -2449,7 +2546,16 @@ export class Documents<
|
|
|
2449
2546
|
return false;
|
|
2450
2547
|
};
|
|
2451
2548
|
} else {
|
|
2452
|
-
|
|
2549
|
+
const keep = options?.keep;
|
|
2550
|
+
keepFunction = keep
|
|
2551
|
+
? function (this: unknown, entry) {
|
|
2552
|
+
return Reflect.apply(keep, this, [
|
|
2553
|
+
entry instanceof Entry
|
|
2554
|
+
? detachEntryPayloadForCallback(entry)
|
|
2555
|
+
: entry,
|
|
2556
|
+
]);
|
|
2557
|
+
}
|
|
2558
|
+
: undefined;
|
|
2453
2559
|
}
|
|
2454
2560
|
|
|
2455
2561
|
await this.log.open({
|
|
@@ -2473,7 +2579,10 @@ export class Documents<
|
|
|
2473
2579
|
distributionDebounceTime: options?.distributionDebounceTime,
|
|
2474
2580
|
strictFullReplicaFallback: false,
|
|
2475
2581
|
domain: options?.domain
|
|
2476
|
-
? () =>
|
|
2582
|
+
? () =>
|
|
2583
|
+
this.detachDomainEntryCallback(
|
|
2584
|
+
options.domain!(this),
|
|
2585
|
+
) as unknown as D
|
|
2477
2586
|
: undefined,
|
|
2478
2587
|
eagerBlocks: options?.eagerBlocks,
|
|
2479
2588
|
fanout: options?.fanout,
|
|
@@ -2565,7 +2674,7 @@ export class Documents<
|
|
|
2565
2674
|
}
|
|
2566
2675
|
|
|
2567
2676
|
try {
|
|
2568
|
-
|
|
2677
|
+
const operation: PutOperation | DeleteOperation = l0;
|
|
2569
2678
|
if (this._optionCanPerform) {
|
|
2570
2679
|
if (this._optionCanPerformNativePolicy && this.isNativeMode()) {
|
|
2571
2680
|
return this.nativeCanPerformAllowsAppend(
|
|
@@ -2575,22 +2684,22 @@ export class Documents<
|
|
|
2575
2684
|
reference?.document,
|
|
2576
2685
|
);
|
|
2577
2686
|
}
|
|
2578
|
-
let document: T | undefined
|
|
2579
|
-
if (
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
} else if (isDeleteOperation(l0)) {
|
|
2588
|
-
// Nothing to do here by default.
|
|
2589
|
-
// Checking if the document exists is not necessary since it
|
|
2590
|
-
// might already be deleted.
|
|
2591
|
-
} else {
|
|
2592
|
-
throw new Error("Unsupported operation");
|
|
2687
|
+
let document: T | undefined;
|
|
2688
|
+
if (isPutOperation(l0)) {
|
|
2689
|
+
const cachedDocument = this._canAppendDecodedDocuments.get(l0);
|
|
2690
|
+
this._canAppendDecodedDocuments.delete(l0);
|
|
2691
|
+
document =
|
|
2692
|
+
cachedDocument ??
|
|
2693
|
+
this._index.valueEncoding.decoder(new Uint8Array(l0.data));
|
|
2694
|
+
if (!document) {
|
|
2695
|
+
return false;
|
|
2593
2696
|
}
|
|
2697
|
+
} else if (isDeleteOperation(l0)) {
|
|
2698
|
+
// Nothing to do here by default.
|
|
2699
|
+
// Checking if the document exists is not necessary since it
|
|
2700
|
+
// might already be deleted.
|
|
2701
|
+
} else {
|
|
2702
|
+
throw new Error("Unsupported operation");
|
|
2594
2703
|
}
|
|
2595
2704
|
const previousEntries =
|
|
2596
2705
|
this._optionCanPerformNativePolicy &&
|
|
@@ -2598,7 +2707,9 @@ export class Documents<
|
|
|
2598
2707
|
canPerformPolicyNeedsPreviousEntries(
|
|
2599
2708
|
this._optionCanPerformNativePolicy,
|
|
2600
2709
|
)
|
|
2601
|
-
? await this.resolveCanPerformPreviousEntries(entry)
|
|
2710
|
+
? (await this.resolveCanPerformPreviousEntries(entry)).map(
|
|
2711
|
+
detachEntryPayloadForCallback,
|
|
2712
|
+
)
|
|
2602
2713
|
: undefined;
|
|
2603
2714
|
const deleteValue =
|
|
2604
2715
|
this._optionCanPerformNativePolicy &&
|
|
@@ -2610,20 +2721,22 @@ export class Documents<
|
|
|
2610
2721
|
: undefined;
|
|
2611
2722
|
if (
|
|
2612
2723
|
!(await this._optionCanPerform(
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2724
|
+
detachCanPerformCallbackProperties(
|
|
2725
|
+
isPutOperation(operation)
|
|
2726
|
+
? {
|
|
2727
|
+
type: "put",
|
|
2728
|
+
value: document!,
|
|
2729
|
+
operation,
|
|
2730
|
+
entry: entry as unknown as Entry<PutOperation>,
|
|
2731
|
+
previousEntries,
|
|
2732
|
+
}
|
|
2733
|
+
: {
|
|
2734
|
+
type: "delete",
|
|
2735
|
+
value: deleteValue,
|
|
2736
|
+
operation,
|
|
2737
|
+
entry: entry as unknown as Entry<DeleteOperation>,
|
|
2738
|
+
},
|
|
2739
|
+
),
|
|
2627
2740
|
))
|
|
2628
2741
|
) {
|
|
2629
2742
|
return false;
|
|
@@ -2712,6 +2825,12 @@ export class Documents<
|
|
|
2712
2825
|
return entries;
|
|
2713
2826
|
}
|
|
2714
2827
|
|
|
2828
|
+
private detachDocumentValueForCallback(document: T): T {
|
|
2829
|
+
return this._index.valueEncoding.decoder(
|
|
2830
|
+
this._index.valueEncoding.encoder(document),
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2715
2834
|
private async resolveCanPerformDeleteValue(
|
|
2716
2835
|
operation: DeleteOperation,
|
|
2717
2836
|
options?: { allowEntryFallback?: boolean },
|
|
@@ -2728,12 +2847,15 @@ export class Documents<
|
|
|
2728
2847
|
const indexedDocument =
|
|
2729
2848
|
await this.getLocalIdentityDocumentByHead(existingHead);
|
|
2730
2849
|
if (indexedDocument) {
|
|
2731
|
-
return indexedDocument;
|
|
2850
|
+
return this.detachDocumentValueForCallback(indexedDocument);
|
|
2732
2851
|
}
|
|
2733
2852
|
const indexedPolicyDocument =
|
|
2734
2853
|
await this.getLocalIndexedDocumentForNativeDeletePolicy(key);
|
|
2735
2854
|
if (indexedPolicyDocument) {
|
|
2736
|
-
return
|
|
2855
|
+
return deserialize(
|
|
2856
|
+
serialize(indexedPolicyDocument),
|
|
2857
|
+
this._index.indexedType,
|
|
2858
|
+
) as unknown as T;
|
|
2737
2859
|
}
|
|
2738
2860
|
if (options?.allowEntryFallback === false) {
|
|
2739
2861
|
return;
|
|
@@ -2745,7 +2867,9 @@ export class Documents<
|
|
|
2745
2867
|
if (!isPutOperation(existingOperation)) {
|
|
2746
2868
|
return;
|
|
2747
2869
|
}
|
|
2748
|
-
return this._index.valueEncoding.decoder(
|
|
2870
|
+
return this._index.valueEncoding.decoder(
|
|
2871
|
+
new Uint8Array(existingOperation.data),
|
|
2872
|
+
);
|
|
2749
2873
|
}
|
|
2750
2874
|
|
|
2751
2875
|
protected async _canAppend(
|
|
@@ -2796,17 +2920,32 @@ export class Documents<
|
|
|
2796
2920
|
if (isPutOperation(operation)) {
|
|
2797
2921
|
// check nexts
|
|
2798
2922
|
const putOperation = operation as PutOperation;
|
|
2923
|
+
let decodedDocumentForCanPerform: T | undefined;
|
|
2924
|
+
let hasDecodedDocumentForCanPerform = false;
|
|
2799
2925
|
let keyValue: indexerTypes.Ideable | undefined;
|
|
2800
2926
|
if (reference?.document) {
|
|
2801
|
-
keyValue = this.idResolver(
|
|
2927
|
+
keyValue = this.idResolver(
|
|
2928
|
+
this._hasCustomIdResolver
|
|
2929
|
+
? this.index.valueEncoding.decoder(
|
|
2930
|
+
new Uint8Array(putOperation.data),
|
|
2931
|
+
)
|
|
2932
|
+
: reference.document,
|
|
2933
|
+
);
|
|
2802
2934
|
} else {
|
|
2803
2935
|
keyValue = await this.getNativeDocumentIdFromPutOperation(putOperation);
|
|
2804
2936
|
if (keyValue == null) {
|
|
2805
2937
|
if (this.isNativeMode()) {
|
|
2806
2938
|
return false;
|
|
2807
2939
|
}
|
|
2808
|
-
const value = this.index.valueEncoding.decoder(
|
|
2809
|
-
|
|
2940
|
+
const value = this.index.valueEncoding.decoder(
|
|
2941
|
+
this._hasCustomIdResolver || this._optionCanPerform
|
|
2942
|
+
? new Uint8Array(putOperation.data)
|
|
2943
|
+
: putOperation.data,
|
|
2944
|
+
);
|
|
2945
|
+
if (this._optionCanPerform && !this._hasCustomIdResolver) {
|
|
2946
|
+
decodedDocumentForCanPerform = value;
|
|
2947
|
+
hasDecodedDocumentForCanPerform = true;
|
|
2948
|
+
}
|
|
2810
2949
|
keyValue = this.idResolver(value);
|
|
2811
2950
|
}
|
|
2812
2951
|
}
|
|
@@ -2843,7 +2982,11 @@ export class Documents<
|
|
|
2843
2982
|
return false; // can not append to immutable document
|
|
2844
2983
|
}
|
|
2845
2984
|
|
|
2846
|
-
return
|
|
2985
|
+
return this.acceptPutOperation(
|
|
2986
|
+
putOperation,
|
|
2987
|
+
decodedDocumentForCanPerform,
|
|
2988
|
+
hasDecodedDocumentForCanPerform,
|
|
2989
|
+
);
|
|
2847
2990
|
} else {
|
|
2848
2991
|
if (this.strictHistory) {
|
|
2849
2992
|
// make sure that the next pointer exist and points to the existing documents
|
|
@@ -2851,7 +2994,11 @@ export class Documents<
|
|
|
2851
2994
|
return false;
|
|
2852
2995
|
}
|
|
2853
2996
|
if (entry.meta.next[0] === existingContext.head) {
|
|
2854
|
-
return
|
|
2997
|
+
return this.acceptPutOperation(
|
|
2998
|
+
putOperation,
|
|
2999
|
+
decodedDocumentForCanPerform,
|
|
3000
|
+
hasDecodedDocumentForCanPerform,
|
|
3001
|
+
);
|
|
2855
3002
|
}
|
|
2856
3003
|
|
|
2857
3004
|
const prevEntry = await this.log.log.entryIndex.get(
|
|
@@ -2866,14 +3013,29 @@ export class Documents<
|
|
|
2866
3013
|
}
|
|
2867
3014
|
const referenceHistoryCorrectly =
|
|
2868
3015
|
await pointsToHistory(prevEntry);
|
|
2869
|
-
return referenceHistoryCorrectly
|
|
3016
|
+
return referenceHistoryCorrectly
|
|
3017
|
+
? this.acceptPutOperation(
|
|
3018
|
+
putOperation,
|
|
3019
|
+
decodedDocumentForCanPerform,
|
|
3020
|
+
hasDecodedDocumentForCanPerform,
|
|
3021
|
+
)
|
|
3022
|
+
: false;
|
|
2870
3023
|
} else {
|
|
2871
|
-
return
|
|
3024
|
+
return this.acceptPutOperation(
|
|
3025
|
+
putOperation,
|
|
3026
|
+
decodedDocumentForCanPerform,
|
|
3027
|
+
hasDecodedDocumentForCanPerform,
|
|
3028
|
+
);
|
|
2872
3029
|
}
|
|
2873
3030
|
}
|
|
2874
3031
|
} else {
|
|
2875
3032
|
// Keep existing behavior: next pointers may express document dependencies.
|
|
2876
3033
|
}
|
|
3034
|
+
return this.acceptPutOperation(
|
|
3035
|
+
putOperation,
|
|
3036
|
+
decodedDocumentForCanPerform,
|
|
3037
|
+
hasDecodedDocumentForCanPerform,
|
|
3038
|
+
);
|
|
2877
3039
|
} else if (isDeleteOperation(operation)) {
|
|
2878
3040
|
if (entry.meta.next.length !== 1) {
|
|
2879
3041
|
return false;
|
|
@@ -2924,7 +3086,6 @@ export class Documents<
|
|
|
2924
3086
|
throw new Error("Unsupported operation");
|
|
2925
3087
|
}
|
|
2926
3088
|
|
|
2927
|
-
return operation;
|
|
2928
3089
|
} catch (error) {
|
|
2929
3090
|
if (error instanceof AccessError) {
|
|
2930
3091
|
return false; // we cant index because we can not decrypt
|
|
@@ -5459,14 +5620,25 @@ export class Documents<
|
|
|
5459
5620
|
}
|
|
5460
5621
|
}
|
|
5461
5622
|
let value =
|
|
5462
|
-
|
|
5463
|
-
|
|
5623
|
+
isReferencedAppendEntry && reference?.document
|
|
5624
|
+
? reference.document
|
|
5625
|
+
: this.index.valueEncoding.decoder(
|
|
5626
|
+
new Uint8Array(payload.data),
|
|
5627
|
+
);
|
|
5464
5628
|
|
|
5465
5629
|
// get index key from value
|
|
5466
5630
|
const key =
|
|
5467
5631
|
isReferencedAppendEntry && reference?.key
|
|
5468
5632
|
? reference.key
|
|
5469
|
-
: indexerTypes.toId(
|
|
5633
|
+
: indexerTypes.toId(
|
|
5634
|
+
this.idResolver(
|
|
5635
|
+
this._hasCustomIdResolver
|
|
5636
|
+
? this.index.valueEncoding.decoder(
|
|
5637
|
+
new Uint8Array(payload.data),
|
|
5638
|
+
)
|
|
5639
|
+
: value,
|
|
5640
|
+
),
|
|
5641
|
+
);
|
|
5470
5642
|
|
|
5471
5643
|
// document is already updated with more recent entry
|
|
5472
5644
|
if (modified.has(key.primitive)) {
|