@peerbit/document 15.0.14 → 15.0.16

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.
@@ -1,3 +1,4 @@
1
+ import type { PublicSignKey, SignatureWithKey } from "@peerbit/crypto";
1
2
  import * as indexerTypes from "@peerbit/indexer-interface";
2
3
  import { Entry } from "@peerbit/log";
3
4
  import {
@@ -8,6 +9,402 @@ import {
8
9
  PutWithKeyOperation,
9
10
  } from "./operation.js";
10
11
 
12
+ type LazyPropertyFactories = Map<PropertyKey, () => unknown>;
13
+
14
+ const isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>
15
+ !!value &&
16
+ (typeof value === "object" || typeof value === "function") &&
17
+ typeof (value as { then?: unknown }).then === "function";
18
+
19
+ const mapMaybePromise = (
20
+ value: unknown,
21
+ map: (value: any) => unknown,
22
+ ): unknown => (isPromiseLike(value) ? value.then(map) : map(value));
23
+
24
+ const copyOptionalBytes = (
25
+ bytes: Uint8Array | undefined,
26
+ ): Uint8Array | undefined =>
27
+ bytes == null ? undefined : new Uint8Array(bytes);
28
+
29
+ const preserveArrayIntegrity = <T>(source: readonly T[], copy: T[]): T[] => {
30
+ if (Object.isFrozen(source)) {
31
+ Object.freeze(copy);
32
+ } else if (Object.isSealed(source)) {
33
+ Object.seal(copy);
34
+ } else if (!Object.isExtensible(source)) {
35
+ Object.preventExtensions(copy);
36
+ }
37
+ return copy;
38
+ };
39
+
40
+ const detachArray = <T>(
41
+ values: readonly T[],
42
+ detach: (value: T) => T = (value) => value,
43
+ ): T[] => preserveArrayIntegrity(values, values.map(detach));
44
+
45
+ const getInheritedPropertyDescriptor = (
46
+ value: object,
47
+ key: PropertyKey,
48
+ ): PropertyDescriptor | undefined => {
49
+ let prototype = Object.getPrototypeOf(value) as object | null;
50
+ while (prototype) {
51
+ const descriptor = Reflect.getOwnPropertyDescriptor(prototype, key);
52
+ if (descriptor) {
53
+ return descriptor;
54
+ }
55
+ prototype = Object.getPrototypeOf(prototype) as object | null;
56
+ }
57
+ return undefined;
58
+ };
59
+
60
+ /**
61
+ * Clone an object without resolving selected nested values. For normal
62
+ * objects the selected fields become callback-local lazy accessors. The clone
63
+ * receives the source's frozen/sealed/non-extensible state only after those
64
+ * accessors are installed, so a no-touch callback never resolves lazy source
65
+ * fields.
66
+ */
67
+ const cloneWithLazyProperties = <T extends object>(
68
+ value: T,
69
+ factories: LazyPropertyFactories,
70
+ ): T => {
71
+ const descriptors = Object.getOwnPropertyDescriptors(value) as Record<
72
+ PropertyKey,
73
+ PropertyDescriptor
74
+ >;
75
+ const extensible = Object.isExtensible(value);
76
+ for (const [key, factory] of factories) {
77
+ const ownDescriptor = descriptors[key];
78
+ const descriptor =
79
+ ownDescriptor ?? getInheritedPropertyDescriptor(value, key);
80
+ let resolved = false;
81
+ let detachedValue: unknown;
82
+ const writable = descriptor
83
+ ? (ownDescriptor != null || extensible) &&
84
+ ("value" in descriptor
85
+ ? descriptor.writable !== false
86
+ : descriptor.set != null)
87
+ : extensible;
88
+ descriptors[key] = {
89
+ configurable: descriptor?.configurable ?? true,
90
+ enumerable: descriptor?.enumerable ?? true,
91
+ get() {
92
+ if (!resolved) {
93
+ detachedValue = factory();
94
+ resolved = true;
95
+ }
96
+ return detachedValue;
97
+ },
98
+ ...(writable
99
+ ? {
100
+ set(nextValue: unknown) {
101
+ detachedValue = nextValue;
102
+ resolved = true;
103
+ },
104
+ }
105
+ : {}),
106
+ };
107
+ }
108
+ const clone = Object.create(Object.getPrototypeOf(value), descriptors) as T;
109
+ if (Object.isFrozen(value)) {
110
+ Object.freeze(clone);
111
+ } else if (Object.isSealed(value)) {
112
+ Object.seal(clone);
113
+ } else if (!Object.isExtensible(value)) {
114
+ Object.preventExtensions(clone);
115
+ }
116
+ return clone;
117
+ };
118
+
119
+ const addOwnByteFactories = (
120
+ value: object,
121
+ factories: LazyPropertyFactories,
122
+ ): void => {
123
+ const descriptors = Object.getOwnPropertyDescriptors(value) as Record<
124
+ PropertyKey,
125
+ PropertyDescriptor
126
+ >;
127
+ for (const key of Reflect.ownKeys(descriptors)) {
128
+ const descriptor = descriptors[key];
129
+ if (descriptor && "value" in descriptor) {
130
+ const bytes = descriptor.value;
131
+ if (bytes instanceof Uint8Array) {
132
+ factories.set(key, () => new Uint8Array(bytes));
133
+ }
134
+ }
135
+ }
136
+ };
137
+
138
+ const addOwnArrayFactories = (
139
+ value: object,
140
+ factories: LazyPropertyFactories,
141
+ ): void => {
142
+ const descriptors = Object.getOwnPropertyDescriptors(value) as Record<
143
+ PropertyKey,
144
+ PropertyDescriptor
145
+ >;
146
+ for (const key of Reflect.ownKeys(descriptors)) {
147
+ const descriptor = descriptors[key];
148
+ if (
149
+ descriptor &&
150
+ "value" in descriptor &&
151
+ Array.isArray(descriptor.value)
152
+ ) {
153
+ const array = descriptor.value as unknown[];
154
+ factories.set(key, () =>
155
+ detachArray(array, (item) =>
156
+ item instanceof Uint8Array ? new Uint8Array(item) : item,
157
+ ),
158
+ );
159
+ }
160
+ }
161
+ };
162
+
163
+ const detachedCallbackEntryLikes = new WeakSet<object>();
164
+
165
+ const createEntryDetachmentContext = () => {
166
+ let metadata: WeakMap<object, object> | undefined;
167
+ let clocks: WeakMap<object, object> | undefined;
168
+ let timestamps: WeakMap<object, object> | undefined;
169
+ let signatures: WeakMap<object, object> | undefined;
170
+ let publicKeys: WeakMap<object, object> | undefined;
171
+ let entryLikes: WeakMap<object, object> | undefined;
172
+ let arrays: WeakMap<object, unknown[]> | undefined;
173
+
174
+ const detachValues = <T>(
175
+ values: readonly T[],
176
+ detach: (value: T) => T = (value) => value,
177
+ ): T[] => {
178
+ const cached = arrays?.get(values);
179
+ if (cached) {
180
+ return cached as T[];
181
+ }
182
+ const clone = detachArray(values, detach);
183
+ (arrays ??= new WeakMap()).set(values, clone);
184
+ return clone;
185
+ };
186
+
187
+ const detachTimestamp = <T>(value: T): T => {
188
+ if (!value || typeof value !== "object") {
189
+ return value;
190
+ }
191
+ const cached = timestamps?.get(value);
192
+ if (cached) {
193
+ return cached as T;
194
+ }
195
+ const factories: LazyPropertyFactories = new Map();
196
+ addOwnByteFactories(value, factories);
197
+ const clone = cloneWithLazyProperties(value, factories);
198
+ (timestamps ??= new WeakMap()).set(value, clone);
199
+ return clone;
200
+ };
201
+
202
+ const detachClock = <T>(value: T): T => {
203
+ if (!value || typeof value !== "object") {
204
+ return value;
205
+ }
206
+ const cached = clocks?.get(value);
207
+ if (cached) {
208
+ return cached as T;
209
+ }
210
+ const factories: LazyPropertyFactories = new Map();
211
+ addOwnByteFactories(value, factories);
212
+ if (Reflect.has(value, "id") && !factories.has("id")) {
213
+ factories.set("id", () =>
214
+ copyOptionalBytes(
215
+ Reflect.get(value, "id", value) as Uint8Array | undefined,
216
+ ),
217
+ );
218
+ }
219
+ if (Reflect.has(value, "timestamp")) {
220
+ factories.set("timestamp", () =>
221
+ detachTimestamp(Reflect.get(value, "timestamp", value)),
222
+ );
223
+ }
224
+ const clone = cloneWithLazyProperties(value, factories);
225
+ (clocks ??= new WeakMap()).set(value, clone);
226
+ return clone;
227
+ };
228
+
229
+ const detachMeta = <T>(value: T): T => {
230
+ if (!value || typeof value !== "object") {
231
+ return value;
232
+ }
233
+ const cached = metadata?.get(value);
234
+ if (cached) {
235
+ return cached as T;
236
+ }
237
+ const factories: LazyPropertyFactories = new Map();
238
+ addOwnByteFactories(value, factories);
239
+ if (Reflect.has(value, "data") && !factories.has("data")) {
240
+ factories.set("data", () =>
241
+ copyOptionalBytes(
242
+ Reflect.get(value, "data", value) as Uint8Array | undefined,
243
+ ),
244
+ );
245
+ }
246
+ if (Reflect.has(value, "clock")) {
247
+ factories.set("clock", () =>
248
+ detachClock(Reflect.get(value, "clock", value)),
249
+ );
250
+ }
251
+ if (Reflect.has(value, "next")) {
252
+ factories.set("next", () => {
253
+ const next = Reflect.get(value, "next", value);
254
+ return Array.isArray(next) ? detachValues(next) : next;
255
+ });
256
+ }
257
+ const clone = cloneWithLazyProperties(value, factories);
258
+ (metadata ??= new WeakMap()).set(value, clone);
259
+ return clone;
260
+ };
261
+
262
+ const detachPublicKey = <T>(value: T): T => {
263
+ if (!value || typeof value !== "object") {
264
+ return value;
265
+ }
266
+ const cached = publicKeys?.get(value);
267
+ if (cached) {
268
+ return cached as T;
269
+ }
270
+ const factories: LazyPropertyFactories = new Map();
271
+ addOwnByteFactories(value, factories);
272
+ const clone = cloneWithLazyProperties(value, factories);
273
+ (publicKeys ??= new WeakMap()).set(value, clone);
274
+ return clone;
275
+ };
276
+
277
+ const detachSignature = <T>(value: T): T => {
278
+ if (!value || typeof value !== "object") {
279
+ return value;
280
+ }
281
+ const cached = signatures?.get(value);
282
+ if (cached) {
283
+ return cached as T;
284
+ }
285
+ const factories: LazyPropertyFactories = new Map();
286
+ addOwnByteFactories(value, factories);
287
+ if (Reflect.has(value, "publicKey")) {
288
+ factories.set("publicKey", () =>
289
+ detachPublicKey(Reflect.get(value, "publicKey", value)),
290
+ );
291
+ }
292
+ const clone = cloneWithLazyProperties(value, factories);
293
+ (signatures ??= new WeakMap()).set(value, clone);
294
+ return clone;
295
+ };
296
+
297
+ const detachSignatures = (
298
+ values: readonly SignatureWithKey[],
299
+ ): SignatureWithKey[] => detachValues(values, detachSignature);
300
+
301
+ const detachPublicKeys = (
302
+ values: readonly PublicSignKey[],
303
+ ): PublicSignKey[] => detachValues(values, detachPublicKey);
304
+
305
+ const detachEntryLike = <T extends object>(value: T): T => {
306
+ if (detachedCallbackEntryLikes.has(value)) {
307
+ return value;
308
+ }
309
+ const cached = entryLikes?.get(value);
310
+ if (cached) {
311
+ return cached as T;
312
+ }
313
+ const factories: LazyPropertyFactories = new Map();
314
+ addOwnByteFactories(value, factories);
315
+ addOwnArrayFactories(value, factories);
316
+ if (Reflect.has(value, "meta")) {
317
+ factories.set("meta", () =>
318
+ detachMeta(Reflect.get(value, "meta", value)),
319
+ );
320
+ }
321
+ for (const methodName of ["getMetaBytes", "getHashDigestBytes"] as const) {
322
+ const method = Reflect.get(value, methodName, value);
323
+ if (typeof method === "function") {
324
+ factories.set(
325
+ methodName,
326
+ () =>
327
+ (...args: unknown[]) =>
328
+ mapMaybePromise(
329
+ Reflect.apply(method, value, args),
330
+ copyOptionalBytes,
331
+ ),
332
+ );
333
+ }
334
+ }
335
+ const clone = cloneWithLazyProperties(value, factories);
336
+ (entryLikes ??= new WeakMap()).set(value, clone);
337
+ detachedCallbackEntryLikes.add(clone);
338
+ return clone;
339
+ };
340
+
341
+ return {
342
+ detachArray: detachValues,
343
+ detachClock,
344
+ detachEntryLike,
345
+ detachMeta,
346
+ detachPublicKeys,
347
+ detachSignatures,
348
+ };
349
+ };
350
+
351
+ type EntryDetachmentContext = ReturnType<typeof createEntryDetachmentContext>;
352
+ type EntryDetachmentContextProvider = () => EntryDetachmentContext;
353
+
354
+ const detachPreparedAppendJoinFactsForCallback = (
355
+ facts: object,
356
+ canonicalEntry: Entry<any>,
357
+ callbackEntry: Entry<any>,
358
+ getContext: EntryDetachmentContextProvider,
359
+ ): object => {
360
+ const factories: LazyPropertyFactories = new Map();
361
+ addOwnByteFactories(facts, factories);
362
+ if (Reflect.has(facts, "bytes")) {
363
+ factories.set("bytes", () =>
364
+ copyOptionalBytes(
365
+ Reflect.get(facts, "bytes", facts) as Uint8Array | undefined,
366
+ ),
367
+ );
368
+ }
369
+ if (Reflect.has(facts, "meta")) {
370
+ factories.set("meta", () =>
371
+ getContext().detachMeta(Reflect.get(facts, "meta", facts)),
372
+ );
373
+ }
374
+ const getShallowEntry = Reflect.get(facts, "getShallowEntry", facts);
375
+ if (typeof getShallowEntry === "function") {
376
+ factories.set("getShallowEntry", () => (...args: unknown[]) => {
377
+ const shallow = Reflect.apply(getShallowEntry, facts, args) as unknown;
378
+ return shallow && typeof shallow === "object"
379
+ ? getContext().detachEntryLike(shallow)
380
+ : shallow;
381
+ });
382
+ }
383
+ const materializeEntry = Reflect.get(facts, "materializeEntry", facts);
384
+ if (typeof materializeEntry === "function") {
385
+ factories.set(
386
+ "materializeEntry",
387
+ () =>
388
+ (...args: unknown[]) =>
389
+ mapMaybePromise(
390
+ Reflect.apply(materializeEntry, facts, args),
391
+ (materialized) =>
392
+ materialized === canonicalEntry
393
+ ? callbackEntry
394
+ : materialized instanceof Entry
395
+ ? detachEntryPayloadForCallbackWithContext(
396
+ materialized,
397
+ getContext,
398
+ )
399
+ : materialized && typeof materialized === "object"
400
+ ? getContext().detachEntryLike(materialized)
401
+ : materialized,
402
+ ),
403
+ );
404
+ }
405
+ return cloneWithLazyProperties(facts, factories);
406
+ };
407
+
11
408
  /**
12
409
  * Borsh byte fields are input-buffer views. Clone only fields that can expose
13
410
  * verified operation bytes while retaining the operation's exact prototype,
@@ -176,13 +573,16 @@ export const detachCanPerformCallbackProperties = <
176
573
  };
177
574
 
178
575
  /**
179
- * Return an Entry view whose public payload accessors cannot expose the
180
- * verified payload buffer to application callbacks. The byte copy is lazy:
181
- * callbacks that only inspect hashes, clocks, or signers allocate nothing.
576
+ * Return an Entry view whose public accessors cannot expose verified payload,
577
+ * metadata, signature, public-key, or hash-digest buffers to application
578
+ * callbacks. Nested copies remain lazy, including metadata byte fields.
182
579
  */
183
580
  const detachedCallbackEntries = new WeakSet<object>();
184
581
 
185
- export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
582
+ const detachEntryPayloadForCallbackWithContext = <T>(
583
+ entry: Entry<T>,
584
+ getContext: EntryDetachmentContextProvider,
585
+ ): Entry<T> => {
186
586
  if (detachedCallbackEntries.has(entry)) {
187
587
  return entry;
188
588
  }
@@ -252,6 +652,23 @@ export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
252
652
  if (property === "payload") {
253
653
  return copyPayload(entry.payload);
254
654
  }
655
+ if (property === "meta") {
656
+ return getContext().detachMeta(Reflect.get(target, property, target));
657
+ }
658
+ if (property === "next") {
659
+ const next = Reflect.get(target, property, target);
660
+ return Array.isArray(next) ? getContext().detachArray(next) : next;
661
+ }
662
+ if (property === "signatures") {
663
+ return getContext().detachSignatures(
664
+ Reflect.get(target, property, target),
665
+ );
666
+ }
667
+ if (property === "publicKeys") {
668
+ return getContext().detachPublicKeys(
669
+ Reflect.get(target, property, target),
670
+ );
671
+ }
255
672
  if (
256
673
  property === "getPayload" &&
257
674
  typeof (entry as Entry<T> & { getPayload?: unknown }).getPayload ===
@@ -262,9 +679,83 @@ export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
262
679
  if (property === "getPayloadValue") {
263
680
  return getPayloadValue;
264
681
  }
682
+ if (property === "getMeta") {
683
+ const getMeta = Reflect.get(target, property, target);
684
+ if (typeof getMeta === "function") {
685
+ return (...args: unknown[]) =>
686
+ mapMaybePromise(
687
+ Reflect.apply(getMeta, target, args),
688
+ getContext().detachMeta,
689
+ );
690
+ }
691
+ }
692
+ if (property === "getClock") {
693
+ const getClock = Reflect.get(target, property, target);
694
+ if (typeof getClock === "function") {
695
+ return (...args: unknown[]) =>
696
+ mapMaybePromise(
697
+ Reflect.apply(getClock, target, args),
698
+ getContext().detachClock,
699
+ );
700
+ }
701
+ }
702
+ if (property === "getNext") {
703
+ const getNext = Reflect.get(target, property, target);
704
+ if (typeof getNext === "function") {
705
+ return (...args: unknown[]) =>
706
+ mapMaybePromise(Reflect.apply(getNext, target, args), (next) =>
707
+ Array.isArray(next) ? getContext().detachArray(next) : next,
708
+ );
709
+ }
710
+ }
711
+ if (property === "getSignatures") {
712
+ const getSignatures = Reflect.get(target, property, target);
713
+ if (typeof getSignatures === "function") {
714
+ return (...args: unknown[]) =>
715
+ mapMaybePromise(
716
+ Reflect.apply(getSignatures, target, args),
717
+ getContext().detachSignatures,
718
+ );
719
+ }
720
+ }
721
+ if (property === "getPublicKeys") {
722
+ const getPublicKeys = Reflect.get(target, property, target);
723
+ if (typeof getPublicKeys === "function") {
724
+ return (...args: unknown[]) =>
725
+ mapMaybePromise(
726
+ Reflect.apply(getPublicKeys, target, args),
727
+ getContext().detachPublicKeys,
728
+ );
729
+ }
730
+ }
731
+ if (property === "getMetaBytes" || property === "getHashDigestBytes") {
732
+ const getBytes = Reflect.get(target, property, target);
733
+ if (typeof getBytes === "function") {
734
+ return (...args: unknown[]) =>
735
+ mapMaybePromise(
736
+ Reflect.apply(getBytes, target, args),
737
+ copyOptionalBytes,
738
+ );
739
+ }
740
+ }
741
+ if (property === "__peerbitNext") {
742
+ const next = Reflect.get(target, property, target);
743
+ return Array.isArray(next) ? getContext().detachArray(next) : next;
744
+ }
265
745
  if (property === "getStorageBytes") {
266
746
  return () => new Uint8Array(entry.getStorageBytes());
267
747
  }
748
+ if (property === "toShallow") {
749
+ const toShallow = Reflect.get(target, property, target);
750
+ if (typeof toShallow === "function") {
751
+ return (...args: unknown[]) => {
752
+ const shallow = Reflect.apply(toShallow, target, args) as unknown;
753
+ return shallow && typeof shallow === "object"
754
+ ? getContext().detachEntryLike(shallow)
755
+ : shallow;
756
+ };
757
+ }
758
+ }
268
759
  if (property === "valueOf") {
269
760
  return () => callbackEntry;
270
761
  }
@@ -275,11 +766,35 @@ export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
275
766
  return callbackEntry;
276
767
  }
277
768
  return (detachedMaterialized ??=
278
- detachEntryPayloadForCallback(materialized));
769
+ detachEntryPayloadForCallbackWithContext(materialized, getContext));
279
770
  };
280
771
  }
281
772
  if (property === "toSignable") {
282
- return () => detachEntryPayloadForCallback(entry.toSignable());
773
+ return () =>
774
+ detachEntryPayloadForCallbackWithContext(
775
+ entry.toSignable(),
776
+ getContext,
777
+ );
778
+ }
779
+ if (property === "toPreparedAppendJoinFacts") {
780
+ const toPreparedAppendJoinFacts = Reflect.get(target, property, target);
781
+ if (typeof toPreparedAppendJoinFacts === "function") {
782
+ return (...args: unknown[]) => {
783
+ const facts = Reflect.apply(
784
+ toPreparedAppendJoinFacts,
785
+ target,
786
+ args,
787
+ ) as unknown;
788
+ return facts && typeof facts === "object"
789
+ ? detachPreparedAppendJoinFactsForCallback(
790
+ facts,
791
+ target,
792
+ callbackEntry,
793
+ getContext,
794
+ )
795
+ : facts;
796
+ };
797
+ }
283
798
  }
284
799
  if (property === "init") {
285
800
  return (properties: Parameters<Entry<T>["init"]>[0]) => {
@@ -306,3 +821,28 @@ export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
306
821
  detachedCallbackEntries.add(callbackEntry);
307
822
  return callbackEntry;
308
823
  };
824
+
825
+ export const detachEntryPayloadForCallback = <T>(entry: Entry<T>): Entry<T> => {
826
+ let context: EntryDetachmentContext | undefined;
827
+ return detachEntryPayloadForCallbackWithContext(
828
+ entry,
829
+ () => (context ??= createEntryDetachmentContext()),
830
+ );
831
+ };
832
+
833
+ /** Detach full, shallow, and replicated entries at document callback edges. */
834
+ export const detachEntryForCallback = <T>(entry: T): T => {
835
+ if (!entry || typeof entry !== "object") {
836
+ return entry;
837
+ }
838
+ return (
839
+ entry instanceof Entry
840
+ ? detachEntryPayloadForCallback(entry)
841
+ : createEntryDetachmentContext().detachEntryLike(entry)
842
+ ) as T;
843
+ };
844
+
845
+ /** Give arbitrary document transforms signer objects they cannot retain/mutate. */
846
+ export const detachPublicKeysForCallback = (
847
+ keys: readonly PublicSignKey[],
848
+ ): PublicSignKey[] => createEntryDetachmentContext().detachPublicKeys(keys);
package/src/domain.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  type ReplicationDomain,
10
10
  type SharedLog,
11
11
  } from "@peerbit/shared-log";
12
- import { detachEntryPayloadForCallback } from "./callback-detachment.js";
12
+ import { detachEntryForCallback } from "./callback-detachment.js";
13
13
  import { type Operation, isPutOperation } from "./operation.js";
14
14
  import type { DocumentIndex } from "./search.js";
15
15
 
@@ -96,8 +96,7 @@ export const createDocumentDomain =
96
96
  let maxValue = args.resolution === "u32" ? MAX_U32 : MAX_U64;
97
97
  const detachEntry = (
98
98
  entry: ShallowEntry | Entry<Operation> | EntryReplicated<any>,
99
- ) =>
100
- entry instanceof Entry ? detachEntryPayloadForCallback(entry) : entry;
99
+ ) => detachEntryForCallback(entry);
101
100
  let fromEntry = (args as FromEntry<InferR<DB>>).fromEntry
102
101
  ? (entry: ShallowEntry | Entry<Operation> | EntryReplicated<any>) =>
103
102
  (args as FromEntry<InferR<DB>>).fromEntry!(detachEntry(entry))