@peerbit/log 6.1.1 → 6.2.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.
Files changed (47) hide show
  1. package/dist/benchmark/native-graph.js +447 -5
  2. package/dist/benchmark/native-graph.js.map +1 -1
  3. package/dist/src/clock.d.ts +1 -0
  4. package/dist/src/clock.d.ts.map +1 -1
  5. package/dist/src/clock.js +32 -0
  6. package/dist/src/clock.js.map +1 -1
  7. package/dist/src/entry-create.d.ts +1 -0
  8. package/dist/src/entry-create.d.ts.map +1 -1
  9. package/dist/src/entry-create.js.map +1 -1
  10. package/dist/src/entry-index.d.ts +288 -12
  11. package/dist/src/entry-index.d.ts.map +1 -1
  12. package/dist/src/entry-index.js +1478 -33
  13. package/dist/src/entry-index.js.map +1 -1
  14. package/dist/src/entry-v0.d.ts +184 -1
  15. package/dist/src/entry-v0.d.ts.map +1 -1
  16. package/dist/src/entry-v0.js +1021 -12
  17. package/dist/src/entry-v0.js.map +1 -1
  18. package/dist/src/entry.d.ts +73 -1
  19. package/dist/src/entry.d.ts.map +1 -1
  20. package/dist/src/entry.js +124 -1
  21. package/dist/src/entry.js.map +1 -1
  22. package/dist/src/index.d.ts +1 -1
  23. package/dist/src/index.d.ts.map +1 -1
  24. package/dist/src/index.js +1 -1
  25. package/dist/src/index.js.map +1 -1
  26. package/dist/src/log.d.ts +62 -13
  27. package/dist/src/log.d.ts.map +1 -1
  28. package/dist/src/log.js +2282 -100
  29. package/dist/src/log.js.map +1 -1
  30. package/dist/src/runtime.d.ts +2 -0
  31. package/dist/src/runtime.d.ts.map +1 -0
  32. package/dist/src/runtime.js +10 -0
  33. package/dist/src/runtime.js.map +1 -0
  34. package/dist/src/trim.d.ts +14 -2
  35. package/dist/src/trim.d.ts.map +1 -1
  36. package/dist/src/trim.js +92 -4
  37. package/dist/src/trim.js.map +1 -1
  38. package/package.json +17 -14
  39. package/src/clock.ts +34 -0
  40. package/src/entry-create.ts +1 -0
  41. package/src/entry-index.ts +2232 -68
  42. package/src/entry-v0.ts +1488 -13
  43. package/src/entry.ts +235 -1
  44. package/src/index.ts +7 -1
  45. package/src/log.ts +3246 -206
  46. package/src/runtime.ts +16 -0
  47. package/src/trim.ts +133 -7
@@ -32,9 +32,17 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
32
32
  }
33
33
  return useValue ? value : void 0;
34
34
  };
35
- import { field, fixedArray, option, serialize, variant, vec, } from "@dao-xyz/borsh";
36
- import {} from "@peerbit/blocks-interface";
37
- import { AccessError, DecryptedThing, Ed25519PublicKey, MaybeEncrypted, PublicSignKey, SignatureWithKey, X25519Keypair, X25519PublicKey, randomBytes, sha256Base64, toBase64, } from "@peerbit/crypto";
35
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
36
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
37
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
38
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
39
+ });
40
+ }
41
+ return path;
42
+ };
43
+ import { deserialize, field, fixedArray, option, serialize, variant, vec, } from "@dao-xyz/borsh";
44
+ import { calculateRawCid } from "@peerbit/blocks-interface";
45
+ import { AccessError, DecryptedThing, Ed25519Keypair, Ed25519PublicKey, MaybeEncrypted, PublicSignKey, SignatureWithKey, X25519Keypair, X25519PublicKey, randomBytes, sha256Base64, toBase64, } from "@peerbit/crypto";
38
46
  import { verify } from "@peerbit/crypto";
39
47
  import {} from "@peerbit/keychain";
40
48
  import { compare } from "uint8arrays";
@@ -42,12 +50,223 @@ import { LamportClock as Clock, HLC, Timestamp } from "./clock.js";
42
50
  import { NO_ENCODING } from "./encoding.js";
43
51
  import { ShallowEntry, ShallowMeta } from "./entry-shallow.js";
44
52
  import { EntryType } from "./entry-type.js";
45
- import { Entry } from "./entry.js";
53
+ import { Entry, } from "./entry.js";
46
54
  import { logger as baseLogger } from "./logger.js";
47
55
  import { Payload } from "./payload.js";
56
+ import { canUseOptionalNativeModuleImports } from "./runtime.js";
48
57
  import { equals } from "./utils.js";
49
58
  const log = baseLogger.newScope("entry-v0");
50
59
  const traceLogger = log.trace;
60
+ const RANDOM_GID_BYTES = 32;
61
+ const RANDOM_GID_POOL_SIZE = 64;
62
+ const NATIVE_RAW_CID_BATCH_MIN_BYTES = 1 << 20;
63
+ let randomGidPool = [];
64
+ const createRandomGid = () => {
65
+ if (randomGidPool.length === 0) {
66
+ const bytes = randomBytes(RANDOM_GID_BYTES * RANDOM_GID_POOL_SIZE);
67
+ randomGidPool = new Array(RANDOM_GID_POOL_SIZE);
68
+ for (let i = 0; i < RANDOM_GID_POOL_SIZE; i++) {
69
+ const offset = i * RANDOM_GID_BYTES;
70
+ randomGidPool[i] = toBase64(bytes.subarray(offset, offset + RANDOM_GID_BYTES));
71
+ }
72
+ }
73
+ return randomGidPool.pop();
74
+ };
75
+ let nativeEntryV0EncoderPromise;
76
+ let nativeEntryV0EncoderLoaded = false;
77
+ let nativeEntryV0Encoder;
78
+ const isPromiseLike = (value) => !!value && typeof value.then === "function";
79
+ const getSynchronousBlockBytes = (store, cid) => {
80
+ const value = store?.get?.(cid);
81
+ return value instanceof Uint8Array ? value : undefined;
82
+ };
83
+ const nativeEntryV0EncoderFromModule = (mod) => {
84
+ if (!mod.encodeEntryV0Signable ||
85
+ !mod.encodeEntryV0Storage ||
86
+ !mod.calculateRawCidV1) {
87
+ return undefined;
88
+ }
89
+ return {
90
+ encodeEntryV0Signable: mod.encodeEntryV0Signable,
91
+ encodeEntryV0Storage: mod.encodeEntryV0Storage,
92
+ encodeEntryV0StorageWithCid: mod.encodeEntryV0StorageWithCid,
93
+ prepareEntryV0PlainChain: mod.prepareEntryV0PlainChain,
94
+ prepareEntryV0PlainEntry: mod.prepareEntryV0PlainEntry,
95
+ calculateRawCidV1: mod.calculateRawCidV1,
96
+ calculateRawCidV1Batch: mod.calculateRawCidV1Batch,
97
+ entryV0PlainPayloadDataFromStorage: mod.entryV0PlainPayloadDataFromStorage,
98
+ prepareRawEntryV0Batch: mod.prepareRawEntryV0Batch,
99
+ verifyEd25519Batch: mod.verifyEd25519Batch,
100
+ verifyEntryV0Ed25519Batch: mod.verifyEntryV0Ed25519Batch,
101
+ verifyEntryV0Ed25519StorageBatch: mod.verifyEntryV0Ed25519StorageBatch,
102
+ };
103
+ };
104
+ const loadNativeEntryV0Encoder = () => {
105
+ if (nativeEntryV0EncoderLoaded) {
106
+ return nativeEntryV0Encoder;
107
+ }
108
+ if (!canUseOptionalNativeModuleImports()) {
109
+ nativeEntryV0EncoderLoaded = true;
110
+ return undefined;
111
+ }
112
+ if (!nativeEntryV0EncoderPromise) {
113
+ try {
114
+ nativeEntryV0EncoderPromise = import(__rewriteRelativeImportExtension(
115
+ /* @vite-ignore */ ["@peerbit", "log-rust"].join("/")))
116
+ .then((mod) => {
117
+ nativeEntryV0Encoder = nativeEntryV0EncoderFromModule(mod);
118
+ nativeEntryV0EncoderLoaded = true;
119
+ return nativeEntryV0Encoder;
120
+ })
121
+ .catch(() => {
122
+ nativeEntryV0Encoder = undefined;
123
+ nativeEntryV0EncoderLoaded = true;
124
+ return undefined;
125
+ });
126
+ }
127
+ catch {
128
+ nativeEntryV0Encoder = undefined;
129
+ nativeEntryV0EncoderLoaded = true;
130
+ return undefined;
131
+ }
132
+ }
133
+ return nativeEntryV0EncoderPromise;
134
+ };
135
+ export const calculateRawCidV1Batch = async (blocks) => {
136
+ if (blocks.length === 0) {
137
+ return [];
138
+ }
139
+ const totalBytes = blocks.reduce((sum, block) => sum + block.byteLength, 0);
140
+ if (totalBytes < NATIVE_RAW_CID_BATCH_MIN_BYTES) {
141
+ // Small raw-head messages are faster through the JS hasher because they
142
+ // avoid copying every block into wasm.
143
+ return Promise.all(blocks.map(async (bytes) => (await calculateRawCid(bytes)).cid));
144
+ }
145
+ const nativeEncoder = loadNativeEntryV0Encoder();
146
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
147
+ ? await nativeEncoder
148
+ : nativeEncoder;
149
+ if (resolvedNativeEncoder?.calculateRawCidV1Batch) {
150
+ return resolvedNativeEncoder.calculateRawCidV1Batch(blocks);
151
+ }
152
+ return Promise.all(blocks.map(async (bytes) => (await calculateRawCid(bytes)).cid));
153
+ };
154
+ export const prepareRawEntryV0Batch = async (blocks) => {
155
+ if (blocks.length === 0) {
156
+ return [];
157
+ }
158
+ const nativeEncoder = loadNativeEntryV0Encoder();
159
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
160
+ ? await nativeEncoder
161
+ : nativeEncoder;
162
+ return resolvedNativeEncoder?.prepareRawEntryV0Batch?.(blocks);
163
+ };
164
+ export const entryV0PlainPayloadDataFromStorage = async (bytes) => {
165
+ const nativeEncoder = loadNativeEntryV0Encoder();
166
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
167
+ ? await nativeEncoder
168
+ : nativeEncoder;
169
+ return resolvedNativeEncoder?.entryV0PlainPayloadDataFromStorage?.(bytes);
170
+ };
171
+ export const verifyEd25519Batch = async (inputs) => {
172
+ if (inputs.length === 0) {
173
+ return [];
174
+ }
175
+ const nativeEncoder = loadNativeEntryV0Encoder();
176
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
177
+ ? await nativeEncoder
178
+ : nativeEncoder;
179
+ return resolvedNativeEncoder?.verifyEd25519Batch?.(inputs);
180
+ };
181
+ export const verifyEntryV0Ed25519Batch = async (inputs) => {
182
+ if (inputs.length === 0) {
183
+ return [];
184
+ }
185
+ const nativeEncoder = loadNativeEntryV0Encoder();
186
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
187
+ ? await nativeEncoder
188
+ : nativeEncoder;
189
+ return resolvedNativeEncoder?.verifyEntryV0Ed25519Batch?.(inputs);
190
+ };
191
+ export const verifyEntryV0Ed25519StorageBatch = async (blocks) => {
192
+ if (blocks.length === 0) {
193
+ return [];
194
+ }
195
+ const nativeEncoder = loadNativeEntryV0Encoder();
196
+ const resolvedNativeEncoder = isPromiseLike(nativeEncoder)
197
+ ? await nativeEncoder
198
+ : nativeEncoder;
199
+ return resolvedNativeEncoder?.verifyEntryV0Ed25519StorageBatch?.(blocks);
200
+ };
201
+ export const verifyEntryV0Ed25519BatchFromEntries = async (entries) => {
202
+ if (entries.length === 0) {
203
+ return [];
204
+ }
205
+ const preparedStorageBytes = [];
206
+ let allHavePreparedStorageBytes = true;
207
+ for (const entry of entries) {
208
+ const bytes = Entry.getPreparedStorageBytes(entry);
209
+ if (!bytes) {
210
+ allHavePreparedStorageBytes = false;
211
+ break;
212
+ }
213
+ preparedStorageBytes.push(bytes);
214
+ }
215
+ if (allHavePreparedStorageBytes) {
216
+ try {
217
+ const verified = await verifyEntryV0Ed25519StorageBatch(preparedStorageBytes);
218
+ if (verified) {
219
+ return verified;
220
+ }
221
+ }
222
+ catch {
223
+ // Fall through to field extraction for encrypted or non-Ed25519 entries.
224
+ }
225
+ }
226
+ const inputs = [];
227
+ for (const entry of entries) {
228
+ if (!(entry instanceof EntryV0)) {
229
+ return undefined;
230
+ }
231
+ const rawEntry = entry;
232
+ if (!(rawEntry._meta instanceof DecryptedThing) ||
233
+ !(rawEntry._payload instanceof DecryptedThing)) {
234
+ return undefined;
235
+ }
236
+ let signatures;
237
+ let meta;
238
+ let payload;
239
+ try {
240
+ signatures = entry.signatures;
241
+ meta = entry.meta;
242
+ payload = entry.payload;
243
+ }
244
+ catch {
245
+ return undefined;
246
+ }
247
+ if (signatures.length !== 1) {
248
+ return undefined;
249
+ }
250
+ const signature = signatures[0];
251
+ if (!(signature.publicKey instanceof Ed25519PublicKey) ||
252
+ signature.prehash !== 0) {
253
+ return undefined;
254
+ }
255
+ inputs.push({
256
+ clockId: meta.clock.id,
257
+ wallTime: meta.clock.timestamp.wallTime,
258
+ logical: meta.clock.timestamp.logical,
259
+ gid: meta.gid,
260
+ next: meta.next,
261
+ type: meta.type,
262
+ metaData: meta.data,
263
+ payloadData: payload.data,
264
+ signature: signature.signature,
265
+ publicKey: signature.publicKey.publicKey,
266
+ });
267
+ }
268
+ return verifyEntryV0Ed25519Batch(inputs);
269
+ };
51
270
  const isMaybeEryptionPublicKey = (o) => {
52
271
  if (!o) {
53
272
  return true;
@@ -225,6 +444,7 @@ let EntryV0 = (() => {
225
444
  createdLocally = __runInitializers(this, _hash_extraInitializers);
226
445
  _keychain;
227
446
  _encoding;
447
+ _hashDigestBytes;
228
448
  constructor(obj) {
229
449
  super();
230
450
  this._meta = obj.meta;
@@ -257,6 +477,17 @@ let EntryV0 = (() => {
257
477
  await this._meta.decrypt(this._keychain);
258
478
  return this.meta;
259
479
  }
480
+ getMetaBytes() {
481
+ try {
482
+ return this._meta.decrypted._data;
483
+ }
484
+ catch {
485
+ return undefined;
486
+ }
487
+ }
488
+ getHashDigestBytes() {
489
+ return this._hashDigestBytes;
490
+ }
260
491
  async getClock() {
261
492
  return (await this.getMeta()).clock;
262
493
  }
@@ -393,7 +624,738 @@ let EntryV0 = (() => {
393
624
  await store.rm(this.hash);
394
625
  }
395
626
  static createGid(seed) {
396
- return seed ? sha256Base64(seed) : toBase64(randomBytes(32));
627
+ return seed ? sha256Base64(seed) : createRandomGid();
628
+ }
629
+ static createGids(count) {
630
+ if (count === 0) {
631
+ return [];
632
+ }
633
+ const bytes = randomBytes(count * RANDOM_GID_BYTES);
634
+ const gids = new Array(count);
635
+ for (let i = 0; i < count; i++) {
636
+ const offset = i * RANDOM_GID_BYTES;
637
+ gids[i] = toBase64(bytes.subarray(offset, offset + RANDOM_GID_BYTES));
638
+ }
639
+ return gids;
640
+ }
641
+ static async createPlainAppendChain(properties) {
642
+ return (await EntryV0.createPlainAppendChainBatch(properties))?.entries;
643
+ }
644
+ static async createPlainAppendEntriesBatch(properties) {
645
+ if (!properties.deferStore) {
646
+ return undefined;
647
+ }
648
+ if (!(properties.identity instanceof Ed25519Keypair)) {
649
+ return undefined;
650
+ }
651
+ const nativeCommit = properties.nativeGraph?.prepareEntryV0PlainEntriesCommit;
652
+ if (!nativeCommit) {
653
+ return undefined;
654
+ }
655
+ if (properties.meta.gids.length !== properties.data.length ||
656
+ (properties.meta.nexts &&
657
+ properties.meta.nexts.length !== properties.data.length) ||
658
+ (properties.payloadDatas &&
659
+ properties.payloadDatas.length !== properties.data.length)) {
660
+ throw new Error("Expected one gid and next list per entry");
661
+ }
662
+ const clocks = properties.meta.clocks();
663
+ if (clocks.length !== properties.data.length) {
664
+ throw new Error("Expected one clock per entry");
665
+ }
666
+ for (let i = 0; i < clocks.length; i++) {
667
+ for (const next of properties.meta.nexts?.[i] ?? []) {
668
+ if (Timestamp.compare(next.meta.clock.timestamp, clocks[i].timestamp) >=
669
+ 0) {
670
+ throw new Error("Expecting next(s) to happen before entry, got: " +
671
+ next.meta.clock.timestamp +
672
+ " > " +
673
+ clocks[i].timestamp);
674
+ }
675
+ }
676
+ }
677
+ const payloadDatas = properties.payloadDatas ??
678
+ properties.data.map((data) => properties.encoding.encoder(data));
679
+ const input = {
680
+ clockId: properties.identity.publicKey.bytes,
681
+ privateKey: properties.identity.privateKey.privateKey,
682
+ publicKey: properties.identity.publicKey.publicKey,
683
+ wallTimes: clocks.map((clock) => clock.timestamp.wallTime),
684
+ logicals: clocks.map((clock) => clock.timestamp.logical),
685
+ gids: properties.meta.gids,
686
+ nexts: properties.meta.nexts?.map((nexts) => nexts.map((next) => next.hash)),
687
+ type: properties.meta.type,
688
+ metaDatas: properties.meta.datas,
689
+ payloadDatas,
690
+ };
691
+ const preparedValue = nativeCommit.call(properties.nativeGraph, input, properties.nativeBlockStore);
692
+ const prepared = isPromiseLike(preparedValue)
693
+ ? await preparedValue
694
+ : preparedValue;
695
+ if (!prepared) {
696
+ return undefined;
697
+ }
698
+ if (prepared.length !== properties.data.length) {
699
+ throw new Error("Unexpected prepared entry batch length");
700
+ }
701
+ const entries = [];
702
+ const shallowEntries = [];
703
+ const appendFacts = [];
704
+ const nativeEntries = [];
705
+ const entryType = properties.meta.type ?? EntryType.APPEND;
706
+ for (let index = 0; index < prepared.length; index++) {
707
+ const preparedEntry = prepared[index];
708
+ const clock = clocks[index];
709
+ const entryGid = properties.meta.gids[index];
710
+ const metaData = properties.meta.datas?.[index];
711
+ const meta = new Meta({
712
+ clock,
713
+ gid: entryGid,
714
+ type: entryType,
715
+ data: metaData,
716
+ next: preparedEntry.next,
717
+ });
718
+ const payloadSize = payloadDatas[index].byteLength;
719
+ const payload = properties.cachePreparedEntries === false
720
+ ? undefined
721
+ : new Payload({
722
+ data: payloadDatas[index],
723
+ value: properties.data[index],
724
+ encoding: properties.encoding,
725
+ });
726
+ const signature = properties.cachePreparedEntries === false
727
+ ? undefined
728
+ : new SignatureWithKey({
729
+ signature: preparedEntry.signature,
730
+ publicKey: properties.identity.publicKey,
731
+ prehash: 0,
732
+ });
733
+ const entry = new EntryV0({
734
+ meta: new DecryptedThing({
735
+ data: preparedEntry.metaBytes,
736
+ value: meta,
737
+ }),
738
+ payload: new DecryptedThing({
739
+ data: preparedEntry.payloadBytes,
740
+ value: payload,
741
+ }),
742
+ signatures: new Signatures({
743
+ signatures: [
744
+ new DecryptedThing({
745
+ data: preparedEntry.signatureBytes,
746
+ value: signature,
747
+ }),
748
+ ],
749
+ }),
750
+ createdLocally: true,
751
+ });
752
+ if (properties.cachePreparedEntries === false) {
753
+ entry.hash = preparedEntry.cid;
754
+ entry.size = preparedEntry.byteLength;
755
+ }
756
+ else {
757
+ if (!preparedEntry.bytes) {
758
+ throw new Error("Missing prepared entry bytes");
759
+ }
760
+ entry.hash = Entry.prepareMultihashBytes(entry, preparedEntry.bytes, preparedEntry.cid);
761
+ }
762
+ entry._hashDigestBytes = preparedEntry.hashDigestBytes;
763
+ const shallowEntry = new ShallowEntry({
764
+ hash: entry.hash,
765
+ payloadSize,
766
+ head: true,
767
+ meta: new ShallowMeta({
768
+ gid: entryGid,
769
+ data: metaData,
770
+ clock,
771
+ next: preparedEntry.next,
772
+ type: entryType,
773
+ }),
774
+ });
775
+ const nativeEntry = properties.cachePreparedEntries === false
776
+ ? undefined
777
+ : {
778
+ hash: entry.hash,
779
+ gid: entryGid,
780
+ next: preparedEntry.next,
781
+ type: entryType,
782
+ head: true,
783
+ payloadSize,
784
+ data: metaData,
785
+ clock: {
786
+ timestamp: {
787
+ wallTime: clock.timestamp.wallTime,
788
+ logical: clock.timestamp.logical,
789
+ },
790
+ },
791
+ };
792
+ if (properties.cachePreparedEntries !== false) {
793
+ Entry.prepareShallowEntry(entry, shallowEntry);
794
+ Entry.prepareNativeLogEntry(entry, nativeEntry);
795
+ entry.init({ encoding: properties.encoding });
796
+ }
797
+ entries.push(entry);
798
+ shallowEntries.push(shallowEntry);
799
+ appendFacts.push({
800
+ hash: entry.hash,
801
+ gid: entryGid,
802
+ next: preparedEntry.next,
803
+ wallTime: clock.timestamp.wallTime,
804
+ logical: clock.timestamp.logical,
805
+ clockId: clock.id,
806
+ type: entryType,
807
+ metaData,
808
+ payloadSize,
809
+ metaBytes: preparedEntry.metaBytes,
810
+ hashDigestBytes: preparedEntry.hashDigestBytes,
811
+ });
812
+ if (nativeEntry) {
813
+ nativeEntries.push(nativeEntry);
814
+ }
815
+ }
816
+ return {
817
+ entries,
818
+ shallowEntries,
819
+ appendFacts,
820
+ nativeEntries,
821
+ nativeGraphUpdated: true,
822
+ nativeBlocksCommitted: true,
823
+ };
824
+ }
825
+ static createPlainAppendChainCommitOnly(properties) {
826
+ if (!properties.deferStore || properties.data.length !== 1) {
827
+ return undefined;
828
+ }
829
+ if (!(properties.identity instanceof Ed25519Keypair)) {
830
+ return undefined;
831
+ }
832
+ if (!properties.nativeGraph?.prepareEntryV0PlainEntryCommit &&
833
+ !properties.nativeGraph?.prepareEntryV0PlainEntryAndPut) {
834
+ return undefined;
835
+ }
836
+ const nexts = properties.meta?.next ?? [];
837
+ const nextHashes = [];
838
+ let gid = null;
839
+ if (nexts.length > 0) {
840
+ if (properties.meta?.gid) {
841
+ throw new Error("Expecting '.meta.gid' property to be undefined if '.meta.next' is provided");
842
+ }
843
+ for (const next of nexts) {
844
+ if (!next.hash) {
845
+ throw new Error("Expecting hash to be defined to next entries");
846
+ }
847
+ nextHashes.push(next.hash);
848
+ gid =
849
+ gid == null
850
+ ? next.meta.gid
851
+ : next.meta.gid < gid
852
+ ? next.meta.gid
853
+ : gid;
854
+ }
855
+ }
856
+ else if (properties.meta?.gid) {
857
+ gid = properties.meta.gid;
858
+ }
859
+ else {
860
+ const createdGid = EntryV0.createGid(properties.meta?.gidSeed);
861
+ return isPromiseLike(createdGid)
862
+ ? createdGid.then((resolvedGid) => EntryV0.finishPlainAppendChainCommitOnly(properties, nexts, nextHashes, resolvedGid))
863
+ : EntryV0.finishPlainAppendChainCommitOnly(properties, nexts, nextHashes, createdGid);
864
+ }
865
+ return EntryV0.finishPlainAppendChainCommitOnly(properties, nexts, nextHashes, gid);
866
+ }
867
+ static finishPlainAppendChainCommitOnly(properties, nexts, nextHashes, gid) {
868
+ if (!properties.nativeGraph ||
869
+ !(properties.identity instanceof Ed25519Keypair)) {
870
+ return undefined;
871
+ }
872
+ const nativeGraph = properties.nativeGraph;
873
+ const identity = properties.identity;
874
+ const clocks = properties.meta?.clocks();
875
+ if (!clocks || clocks.length !== 1) {
876
+ throw new Error("Expected one clock per entry");
877
+ }
878
+ const clock = clocks[0];
879
+ for (const next of nexts) {
880
+ if (Timestamp.compare(next.meta.clock.timestamp, clock.timestamp) >= 0) {
881
+ throw new Error("Expecting next(s) to happen before entry, got: " +
882
+ next.meta.clock.timestamp +
883
+ " > " +
884
+ clock.timestamp);
885
+ }
886
+ }
887
+ const payloadData = properties.payloadDatas?.[0] ??
888
+ properties.encoding.encoder(properties.data[0]);
889
+ const entryType = properties.meta?.type ?? EntryType.APPEND;
890
+ const singleInput = {
891
+ clockId: identity.publicKey.bytes,
892
+ privateKey: identity.privateKey.privateKey,
893
+ publicKey: identity.publicKey.publicKey,
894
+ wallTime: clock.timestamp.wallTime,
895
+ logical: clock.timestamp.logical,
896
+ gid: gid,
897
+ next: nextHashes,
898
+ type: entryType,
899
+ metaData: properties.meta?.data,
900
+ payloadData,
901
+ includeMaterializationBytes: properties.includeMaterializationBytes,
902
+ includeAppendFactsBytes: properties.includeAppendFactsBytes,
903
+ trimLengthTo: properties.nativeTrimLengthTo,
904
+ resolveTrimmedEntries: properties.nativeTrimLengthTo == null ? undefined : false,
905
+ };
906
+ let nativeBlocksCommitted = false;
907
+ let nativeGraphUpdated = false;
908
+ const finishWithPreparedEntry = (preparedEntry) => {
909
+ if (!preparedEntry) {
910
+ return undefined;
911
+ }
912
+ const payloadSize = payloadData.byteLength;
913
+ const shallowEntry = new ShallowEntry({
914
+ hash: preparedEntry.cid,
915
+ payloadSize,
916
+ head: true,
917
+ meta: new ShallowMeta({
918
+ gid: gid,
919
+ data: properties.meta?.data,
920
+ clock,
921
+ next: preparedEntry.next,
922
+ type: entryType,
923
+ }),
924
+ });
925
+ const appendFacts = {
926
+ hash: preparedEntry.cid,
927
+ gid: gid,
928
+ next: preparedEntry.next,
929
+ wallTime: clock.timestamp.wallTime,
930
+ logical: clock.timestamp.logical,
931
+ clockId: clock.id,
932
+ type: entryType,
933
+ metaData: properties.meta?.data,
934
+ payloadSize,
935
+ metaBytes: preparedEntry.metaBytes,
936
+ hashDigestBytes: preparedEntry.hashDigestBytes,
937
+ };
938
+ let materialized;
939
+ const materializeEntry = (index = 0) => {
940
+ if (index !== 0) {
941
+ throw new Error("Prepared commit-only append only has one entry");
942
+ }
943
+ if (materialized) {
944
+ return materialized;
945
+ }
946
+ const payload = new Payload({
947
+ data: payloadData,
948
+ value: properties.data[0],
949
+ encoding: properties.encoding,
950
+ });
951
+ if (!preparedEntry.metaBytes ||
952
+ !preparedEntry.payloadBytes ||
953
+ !preparedEntry.signature ||
954
+ !preparedEntry.signatureBytes) {
955
+ const bytes = preparedEntry.bytes ??
956
+ getSynchronousBlockBytes(properties.nativeBlockStore, preparedEntry.cid);
957
+ if (!bytes) {
958
+ throw new Error("Missing prepared entry bytes");
959
+ }
960
+ const entry = deserialize(bytes, Entry);
961
+ entry.hash = preparedEntry.cid;
962
+ entry.size = preparedEntry.byteLength;
963
+ entry.createdLocally = true;
964
+ entry._hashDigestBytes = preparedEntry.hashDigestBytes;
965
+ Entry.prepareShallowEntry(entry, shallowEntry);
966
+ entry.init({ encoding: properties.encoding });
967
+ materialized = entry;
968
+ return entry;
969
+ }
970
+ const signature = new SignatureWithKey({
971
+ signature: preparedEntry.signature,
972
+ publicKey: properties.identity.publicKey,
973
+ prehash: 0,
974
+ });
975
+ const meta = new Meta({
976
+ clock,
977
+ gid: gid,
978
+ type: entryType,
979
+ data: properties.meta?.data,
980
+ next: preparedEntry.next,
981
+ });
982
+ const entry = new EntryV0({
983
+ meta: new DecryptedThing({
984
+ data: preparedEntry.metaBytes,
985
+ value: meta,
986
+ }),
987
+ payload: new DecryptedThing({
988
+ data: preparedEntry.payloadBytes,
989
+ value: payload,
990
+ }),
991
+ signatures: new Signatures({
992
+ signatures: [
993
+ new DecryptedThing({
994
+ data: preparedEntry.signatureBytes,
995
+ value: signature,
996
+ }),
997
+ ],
998
+ }),
999
+ createdLocally: true,
1000
+ });
1001
+ entry.hash = preparedEntry.cid;
1002
+ entry.size = preparedEntry.byteLength;
1003
+ entry._hashDigestBytes = preparedEntry.hashDigestBytes;
1004
+ Entry.prepareShallowEntry(entry, shallowEntry);
1005
+ entry.init({ encoding: properties.encoding });
1006
+ materialized = entry;
1007
+ return entry;
1008
+ };
1009
+ const preparedBlock = preparedEntry.bytes && !nativeBlocksCommitted
1010
+ ? Entry.preparedBlockFromBytes(preparedEntry.bytes, preparedEntry.cid)
1011
+ : undefined;
1012
+ return {
1013
+ materializeEntry,
1014
+ materializeEntries: () => [materializeEntry(0)],
1015
+ blocks: preparedBlock ? [preparedBlock] : undefined,
1016
+ shallowEntries: [shallowEntry],
1017
+ appendFacts: [appendFacts],
1018
+ trimmedNativeEntries: preparedEntry.trimmedEntries,
1019
+ trimmedNativeEntryHashes: preparedEntry.trimmedEntryHashes,
1020
+ trimmedNativeBlocksDeleted: nativeBlocksCommitted,
1021
+ nativeGraphUpdated,
1022
+ nativeBlocksCommitted,
1023
+ };
1024
+ };
1025
+ const prepareAndPutFallback = () => {
1026
+ const nativePrepareAndPut = nativeGraph.prepareEntryV0PlainEntryAndPut;
1027
+ const preparedEntryValue = nativePrepareAndPut
1028
+ ? nativePrepareAndPut.call(nativeGraph, {
1029
+ ...singleInput,
1030
+ })
1031
+ : undefined;
1032
+ if (isPromiseLike(preparedEntryValue)) {
1033
+ return preparedEntryValue.then((preparedEntry) => {
1034
+ nativeGraphUpdated = !!preparedEntry && !!nativePrepareAndPut;
1035
+ return finishWithPreparedEntry(preparedEntry);
1036
+ });
1037
+ }
1038
+ nativeGraphUpdated = !!preparedEntryValue && !!nativePrepareAndPut;
1039
+ return finishWithPreparedEntry(preparedEntryValue);
1040
+ };
1041
+ const nativeCommit = nativeGraph.prepareEntryV0PlainEntryCommit;
1042
+ if (nativeCommit) {
1043
+ const preparedEntryValue = nativeCommit.call(nativeGraph, singleInput, properties.nativeBlockStore);
1044
+ if (isPromiseLike(preparedEntryValue)) {
1045
+ return preparedEntryValue.then((preparedEntry) => {
1046
+ if (preparedEntry) {
1047
+ nativeBlocksCommitted = true;
1048
+ nativeGraphUpdated = true;
1049
+ return finishWithPreparedEntry(preparedEntry);
1050
+ }
1051
+ return prepareAndPutFallback();
1052
+ });
1053
+ }
1054
+ if (preparedEntryValue) {
1055
+ nativeBlocksCommitted = true;
1056
+ nativeGraphUpdated = true;
1057
+ return finishWithPreparedEntry(preparedEntryValue);
1058
+ }
1059
+ }
1060
+ return prepareAndPutFallback();
1061
+ }
1062
+ static async createPlainAppendChainBatch(properties) {
1063
+ if (!properties.deferStore) {
1064
+ return undefined;
1065
+ }
1066
+ if (!(properties.identity instanceof Ed25519Keypair)) {
1067
+ return undefined;
1068
+ }
1069
+ const nativeEncoderValue = loadNativeEntryV0Encoder();
1070
+ const nativeEncoder = isPromiseLike(nativeEncoderValue)
1071
+ ? await nativeEncoderValue
1072
+ : nativeEncoderValue;
1073
+ if (!nativeEncoder?.prepareEntryV0PlainChain) {
1074
+ return undefined;
1075
+ }
1076
+ const nexts = properties.meta?.next ?? [];
1077
+ const nextHashes = [];
1078
+ let gid = null;
1079
+ if (nexts.length > 0) {
1080
+ if (properties.meta?.gid) {
1081
+ throw new Error("Expecting '.meta.gid' property to be undefined if '.meta.next' is provided");
1082
+ }
1083
+ for (const next of nexts) {
1084
+ if (!next.hash) {
1085
+ throw new Error("Expecting hash to be defined to next entries");
1086
+ }
1087
+ nextHashes.push(next.hash);
1088
+ gid =
1089
+ gid == null
1090
+ ? next.meta.gid
1091
+ : next.meta.gid < gid
1092
+ ? next.meta.gid
1093
+ : gid;
1094
+ }
1095
+ }
1096
+ else {
1097
+ if (properties.meta?.gid) {
1098
+ gid = properties.meta.gid;
1099
+ }
1100
+ else {
1101
+ const createdGid = EntryV0.createGid(properties.meta?.gidSeed);
1102
+ gid = isPromiseLike(createdGid) ? await createdGid : createdGid;
1103
+ }
1104
+ }
1105
+ const clocks = properties.meta?.clocks();
1106
+ if (!clocks || clocks.length !== properties.data.length) {
1107
+ throw new Error("Expected one clock per entry");
1108
+ }
1109
+ for (const next of nexts) {
1110
+ if (Timestamp.compare(next.meta.clock.timestamp, clocks[0].timestamp) >= 0) {
1111
+ throw new Error("Expecting next(s) to happen before entry, got: " +
1112
+ next.meta.clock.timestamp +
1113
+ " > " +
1114
+ clocks[0].timestamp);
1115
+ }
1116
+ }
1117
+ for (let i = 1; i < clocks.length; i++) {
1118
+ if (Timestamp.compare(clocks[i - 1].timestamp, clocks[i].timestamp) >= 0) {
1119
+ throw new Error("Expecting generated clocks to increase across appendMany");
1120
+ }
1121
+ }
1122
+ const entryType = properties.meta?.type ?? EntryType.APPEND;
1123
+ const clockId = properties.identity.publicKey.bytes;
1124
+ const privateKey = properties.identity.privateKey.privateKey;
1125
+ const publicKey = properties.identity.publicKey.publicKey;
1126
+ let nativeBlocksCommitted = false;
1127
+ let nativeGraphUpdated = false;
1128
+ let prepared;
1129
+ let payloadDatas;
1130
+ if (properties.data.length === 1) {
1131
+ const clock = clocks[0];
1132
+ const payloadData = properties.payloadDatas?.[0] ??
1133
+ properties.encoding.encoder(properties.data[0]);
1134
+ const singleInput = {
1135
+ clockId,
1136
+ privateKey,
1137
+ publicKey,
1138
+ wallTime: clock.timestamp.wallTime,
1139
+ logical: clock.timestamp.logical,
1140
+ gid: gid,
1141
+ next: nextHashes,
1142
+ type: entryType,
1143
+ metaData: properties.meta?.data,
1144
+ payloadData,
1145
+ };
1146
+ const nativeCommit = properties.nativeGraph?.prepareEntryV0PlainEntryCommit;
1147
+ const preparedEntryValue = nativeCommit
1148
+ ? nativeCommit.call(properties.nativeGraph, singleInput, properties.nativeBlockStore)
1149
+ : undefined;
1150
+ const preparedEntry = isPromiseLike(preparedEntryValue)
1151
+ ? await preparedEntryValue
1152
+ : preparedEntryValue;
1153
+ if (preparedEntry) {
1154
+ nativeBlocksCommitted = true;
1155
+ nativeGraphUpdated = true;
1156
+ prepared = [preparedEntry];
1157
+ payloadDatas = [payloadData];
1158
+ }
1159
+ else {
1160
+ const nativePrepareAndPut = properties.nativeGraph?.prepareEntryV0PlainEntryAndPut;
1161
+ const scalarPreparedEntryValue = nativePrepareAndPut
1162
+ ? nativePrepareAndPut.call(properties.nativeGraph, singleInput)
1163
+ : nativeEncoder.prepareEntryV0PlainEntry?.(singleInput);
1164
+ const scalarPreparedEntry = isPromiseLike(scalarPreparedEntryValue)
1165
+ ? await scalarPreparedEntryValue
1166
+ : scalarPreparedEntryValue;
1167
+ if (scalarPreparedEntry) {
1168
+ nativeGraphUpdated = !!nativePrepareAndPut;
1169
+ prepared = [scalarPreparedEntry];
1170
+ payloadDatas = [payloadData];
1171
+ }
1172
+ }
1173
+ }
1174
+ if (!prepared) {
1175
+ const wallTimes = new Array(properties.data.length);
1176
+ const logicals = new Array(properties.data.length);
1177
+ const metaDatas = new Array(properties.data.length);
1178
+ if (properties.payloadDatas &&
1179
+ properties.payloadDatas.length !== properties.data.length) {
1180
+ throw new Error("Expected one payload data value per entry");
1181
+ }
1182
+ payloadDatas = properties.payloadDatas
1183
+ ? [...properties.payloadDatas]
1184
+ : new Array(properties.data.length);
1185
+ for (let i = 0; i < properties.data.length; i++) {
1186
+ const clock = clocks[i];
1187
+ wallTimes[i] = clock.timestamp.wallTime;
1188
+ logicals[i] = clock.timestamp.logical;
1189
+ metaDatas[i] = properties.meta?.data;
1190
+ payloadDatas[i] ??= properties.encoding.encoder(properties.data[i]);
1191
+ }
1192
+ const nativePlainChainInput = {
1193
+ clockId,
1194
+ privateKey,
1195
+ publicKey,
1196
+ wallTimes,
1197
+ logicals,
1198
+ gid: gid,
1199
+ initialNext: nextHashes,
1200
+ type: entryType,
1201
+ metaDatas,
1202
+ payloadDatas,
1203
+ };
1204
+ const nativeCommit = properties.nativeGraph?.prepareEntryV0PlainChainCommit;
1205
+ const preparedValue = nativeCommit
1206
+ ? nativeCommit.call(properties.nativeGraph, nativePlainChainInput, properties.nativeBlockStore)
1207
+ : undefined;
1208
+ prepared = isPromiseLike(preparedValue)
1209
+ ? await preparedValue
1210
+ : preparedValue;
1211
+ if (prepared) {
1212
+ nativeBlocksCommitted = true;
1213
+ nativeGraphUpdated = true;
1214
+ }
1215
+ else {
1216
+ const nativePrepareAndPut = properties.nativeGraph?.prepareEntryV0PlainChainAndPut;
1217
+ const preparedFallbackValue = nativePrepareAndPut
1218
+ ? nativePrepareAndPut.call(properties.nativeGraph, nativePlainChainInput)
1219
+ : nativeEncoder.prepareEntryV0PlainChain(nativePlainChainInput);
1220
+ prepared = isPromiseLike(preparedFallbackValue)
1221
+ ? await preparedFallbackValue
1222
+ : preparedFallbackValue;
1223
+ nativeGraphUpdated = !!nativePrepareAndPut;
1224
+ }
1225
+ }
1226
+ const entries = [];
1227
+ const blocks = [];
1228
+ const shallowEntries = [];
1229
+ const appendFacts = [];
1230
+ const nativeEntries = [];
1231
+ if (!payloadDatas) {
1232
+ throw new Error("Expected payload data for prepared append chain");
1233
+ }
1234
+ for (let index = 0; index < prepared.length; index++) {
1235
+ const preparedEntry = prepared[index];
1236
+ const clock = clocks[index];
1237
+ const meta = new Meta({
1238
+ clock,
1239
+ gid: gid,
1240
+ type: entryType,
1241
+ data: properties.meta?.data,
1242
+ next: preparedEntry.next,
1243
+ });
1244
+ const payloadSize = payloadDatas[index].byteLength;
1245
+ const payload = properties.cachePreparedEntries === false
1246
+ ? undefined
1247
+ : new Payload({
1248
+ data: payloadDatas[index],
1249
+ value: properties.data[index],
1250
+ encoding: properties.encoding,
1251
+ });
1252
+ const signature = properties.cachePreparedEntries === false
1253
+ ? undefined
1254
+ : new SignatureWithKey({
1255
+ signature: preparedEntry.signature,
1256
+ publicKey: properties.identity.publicKey,
1257
+ prehash: 0,
1258
+ });
1259
+ const entry = new EntryV0({
1260
+ meta: new DecryptedThing({
1261
+ data: preparedEntry.metaBytes,
1262
+ value: meta,
1263
+ }),
1264
+ payload: new DecryptedThing({
1265
+ data: preparedEntry.payloadBytes,
1266
+ value: payload,
1267
+ }),
1268
+ signatures: new Signatures({
1269
+ signatures: [
1270
+ new DecryptedThing({
1271
+ data: preparedEntry.signatureBytes,
1272
+ value: signature,
1273
+ }),
1274
+ ],
1275
+ }),
1276
+ createdLocally: true,
1277
+ });
1278
+ const preparedBlock = preparedEntry.bytes && !nativeBlocksCommitted
1279
+ ? Entry.preparedBlockFromBytes(preparedEntry.bytes, preparedEntry.cid)
1280
+ : undefined;
1281
+ if (properties.cachePreparedEntries === false) {
1282
+ entry.hash = preparedEntry.cid;
1283
+ entry.size = preparedEntry.byteLength;
1284
+ }
1285
+ else {
1286
+ if (!preparedEntry.bytes) {
1287
+ throw new Error("Missing prepared entry bytes");
1288
+ }
1289
+ entry.hash = Entry.prepareMultihashBytes(entry, preparedEntry.bytes, preparedEntry.cid);
1290
+ }
1291
+ entry._hashDigestBytes = preparedEntry.hashDigestBytes;
1292
+ const shallowEntry = new ShallowEntry({
1293
+ hash: entry.hash,
1294
+ payloadSize,
1295
+ head: index === prepared.length - 1,
1296
+ meta: new ShallowMeta({
1297
+ gid: gid,
1298
+ data: properties.meta?.data,
1299
+ clock,
1300
+ next: preparedEntry.next,
1301
+ type: entryType,
1302
+ }),
1303
+ });
1304
+ const nativeEntry = nativeGraphUpdated && properties.cachePreparedEntries === false
1305
+ ? undefined
1306
+ : {
1307
+ hash: entry.hash,
1308
+ gid: gid,
1309
+ next: preparedEntry.next,
1310
+ type: entryType,
1311
+ head: index === prepared.length - 1,
1312
+ payloadSize,
1313
+ data: properties.meta?.data,
1314
+ clock: {
1315
+ timestamp: {
1316
+ wallTime: clock.timestamp.wallTime,
1317
+ logical: clock.timestamp.logical,
1318
+ },
1319
+ },
1320
+ };
1321
+ if (properties.cachePreparedEntries !== false) {
1322
+ Entry.prepareShallowEntry(entry, shallowEntry);
1323
+ Entry.prepareNativeLogEntry(entry, nativeEntry);
1324
+ }
1325
+ if (properties.cachePreparedEntries !== false) {
1326
+ entry.init({ encoding: properties.encoding });
1327
+ }
1328
+ entries.push(entry);
1329
+ if (preparedBlock) {
1330
+ blocks.push(preparedBlock);
1331
+ }
1332
+ shallowEntries.push(shallowEntry);
1333
+ appendFacts.push({
1334
+ hash: entry.hash,
1335
+ gid: gid,
1336
+ next: preparedEntry.next,
1337
+ wallTime: clock.timestamp.wallTime,
1338
+ logical: clock.timestamp.logical,
1339
+ clockId: clock.id,
1340
+ type: entryType,
1341
+ metaData: properties.meta?.data,
1342
+ payloadSize,
1343
+ metaBytes: preparedEntry.metaBytes,
1344
+ hashDigestBytes: preparedEntry.hashDigestBytes,
1345
+ });
1346
+ if (nativeEntry) {
1347
+ nativeEntries.push(nativeEntry);
1348
+ }
1349
+ }
1350
+ return {
1351
+ entries,
1352
+ blocks: blocks.length > 0 ? blocks : undefined,
1353
+ shallowEntries,
1354
+ appendFacts,
1355
+ nativeEntries,
1356
+ nativeGraphUpdated,
1357
+ nativeBlocksCommitted,
1358
+ };
397
1359
  }
398
1360
  static async create(properties) {
399
1361
  if (!properties.encoding || !properties?.meta?.next) {
@@ -472,14 +1434,30 @@ let EntryV0 = (() => {
472
1434
  properties.meta?.gid ||
473
1435
  (await EntryV0.createGid(properties.meta?.gidSeed));
474
1436
  }
1437
+ const entryType = properties.meta?.type ?? EntryType.APPEND;
475
1438
  const metadataEncrypted = await maybeEncrypt(new Meta({
476
1439
  clock,
477
1440
  gid: gid,
478
- type: properties.meta?.type ?? EntryType.APPEND,
1441
+ type: entryType,
479
1442
  data: properties.meta?.data,
480
1443
  next: nextHashes,
481
1444
  }), properties.encryption?.keypair, properties.encryption?.receiver.meta);
482
1445
  const payload = await maybeEncrypt(payloadToSave, properties.encryption?.keypair, properties.encryption?.receiver.payload);
1446
+ const nativeEncoder = properties.encryption
1447
+ ? undefined
1448
+ : await loadNativeEntryV0Encoder();
1449
+ const nativePlainInput = nativeEncoder
1450
+ ? {
1451
+ clockId: clock.id,
1452
+ wallTime: clock.timestamp.wallTime,
1453
+ logical: clock.timestamp.logical,
1454
+ gid: gid,
1455
+ next: nextHashes,
1456
+ type: entryType,
1457
+ metaData: properties.meta?.data,
1458
+ payloadData: payloadToSave.data,
1459
+ }
1460
+ : undefined;
483
1461
  // Sign id, encrypted payload, clock, nexts, refs
484
1462
  const entry = new EntryV0({
485
1463
  meta: metadataEncrypted,
@@ -487,11 +1465,14 @@ let EntryV0 = (() => {
487
1465
  signatures: undefined,
488
1466
  createdLocally: true,
489
1467
  });
490
- const signers = properties.signers || [
491
- properties.identity.sign.bind(properties.identity),
492
- ];
493
- const signableBytes = entry.getSignableBytes();
494
- let signatures = await Promise.all(signers.map((signer) => signer(signableBytes)));
1468
+ const signableBytes = nativeEncoder && nativePlainInput
1469
+ ? await nativeEncoder.encodeEntryV0Signable(nativePlainInput)
1470
+ : entry.getSignableBytes();
1471
+ let signatures = properties.signers
1472
+ ? properties.signers.length === 1
1473
+ ? [await properties.signers[0](signableBytes)]
1474
+ : await Promise.all(properties.signers.map((signer) => signer(signableBytes)))
1475
+ : [await properties.identity.sign(signableBytes)];
495
1476
  signatures = signatures.sort((a, b) => compare(a.signature, b.signature));
496
1477
  const encryptedSignatures = [];
497
1478
  const encryptAllSignaturesWithSameKey = isMaybeEryptionPublicKey(properties.encryption?.receiver?.signatures);
@@ -508,8 +1489,36 @@ let EntryV0 = (() => {
508
1489
  if (properties.canAppend && !(await properties.canAppend(entry))) {
509
1490
  throw new AccessError("Not allowed to append");
510
1491
  }
1492
+ let nativeStorage;
1493
+ if (nativeEncoder &&
1494
+ nativePlainInput &&
1495
+ !properties.canAppend &&
1496
+ signatures.length === 1 &&
1497
+ signatures[0].publicKey instanceof Ed25519PublicKey) {
1498
+ const storageInput = {
1499
+ ...nativePlainInput,
1500
+ signature: signatures[0].signature,
1501
+ signaturePublicKey: signatures[0].publicKey.publicKey,
1502
+ prehash: signatures[0].prehash,
1503
+ };
1504
+ nativeStorage = nativeEncoder.encodeEntryV0StorageWithCid
1505
+ ? await nativeEncoder.encodeEntryV0StorageWithCid(storageInput)
1506
+ : await (async () => {
1507
+ const storageBytes = await nativeEncoder.encodeEntryV0Storage(storageInput);
1508
+ return {
1509
+ bytes: storageBytes,
1510
+ cid: await nativeEncoder.calculateRawCidV1(storageBytes),
1511
+ };
1512
+ })();
1513
+ }
511
1514
  // Append hash
512
- entry.hash = await Entry.toMultihash(properties.store, entry);
1515
+ entry.hash = properties.deferStore
1516
+ ? nativeStorage
1517
+ ? Entry.prepareMultihashBytes(entry, nativeStorage.bytes, nativeStorage.cid)
1518
+ : await Entry.prepareMultihash(entry)
1519
+ : nativeStorage
1520
+ ? await Entry.toMultihashBytes(properties.store, entry, nativeStorage.bytes, nativeStorage.cid)
1521
+ : await Entry.toMultihash(properties.store, entry);
513
1522
  entry.init({ encoding: properties.encoding });
514
1523
  return entry;
515
1524
  }