@upcoming/bee-js 10.1.2 → 12.0.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.
Files changed (95) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/bee.js +105 -12
  3. package/dist/cjs/chunk/bmt.js +1 -2
  4. package/dist/cjs/chunk/cac.js +27 -32
  5. package/dist/cjs/chunk/soc.js +39 -31
  6. package/dist/cjs/feed/identifier.js +1 -2
  7. package/dist/cjs/feed/index.js +29 -19
  8. package/dist/cjs/feed/retrievable.js +1 -2
  9. package/dist/cjs/index.js +17 -7
  10. package/dist/cjs/manifest/manifest.js +19 -2
  11. package/dist/cjs/modules/bytes.js +4 -5
  12. package/dist/cjs/modules/bzz.js +4 -5
  13. package/dist/cjs/modules/chunk.js +2 -3
  14. package/dist/cjs/modules/debug/balance.js +4 -5
  15. package/dist/cjs/modules/debug/chequebook.js +8 -9
  16. package/dist/cjs/modules/debug/connectivity.js +7 -8
  17. package/dist/cjs/modules/debug/settlements.js +2 -3
  18. package/dist/cjs/modules/debug/stake.js +6 -7
  19. package/dist/cjs/modules/debug/stamps.js +23 -77
  20. package/dist/cjs/modules/debug/states.js +6 -6
  21. package/dist/cjs/modules/debug/status.js +9 -9
  22. package/dist/cjs/modules/debug/transactions.js +4 -5
  23. package/dist/cjs/modules/envelope.js +1 -2
  24. package/dist/cjs/modules/feed.js +3 -4
  25. package/dist/cjs/modules/grantee.js +3 -4
  26. package/dist/cjs/modules/gsoc.js +2 -3
  27. package/dist/cjs/modules/pinning.js +4 -5
  28. package/dist/cjs/modules/pss.js +2 -3
  29. package/dist/cjs/modules/rchash.js +1 -2
  30. package/dist/cjs/modules/soc.js +1 -2
  31. package/dist/cjs/modules/status.js +2 -3
  32. package/dist/cjs/modules/stewardship.js +2 -3
  33. package/dist/cjs/modules/tag.js +5 -6
  34. package/dist/cjs/types/debug.js +3 -3
  35. package/dist/cjs/types/index.js +2 -2
  36. package/dist/cjs/utils/bytes.js +2 -2
  37. package/dist/cjs/utils/chunk-size.js +1 -2
  38. package/dist/cjs/utils/chunk-stream.browser.js +30 -6
  39. package/dist/cjs/utils/chunk-stream.js +3 -4
  40. package/dist/cjs/utils/cid.js +3 -3
  41. package/dist/cjs/utils/collection.browser.js +2 -3
  42. package/dist/cjs/utils/collection.js +5 -6
  43. package/dist/cjs/utils/collection.node.js +2 -3
  44. package/dist/cjs/utils/data.browser.js +1 -2
  45. package/dist/cjs/utils/data.js +1 -2
  46. package/dist/cjs/utils/expose.js +4 -1
  47. package/dist/cjs/utils/file.js +2 -3
  48. package/dist/cjs/utils/headers.js +2 -3
  49. package/dist/cjs/utils/http.js +25 -5
  50. package/dist/cjs/utils/pss.js +1 -2
  51. package/dist/cjs/utils/redundancy.js +3 -4
  52. package/dist/cjs/utils/stamps.js +60 -11
  53. package/dist/cjs/utils/tar-uploader.browser.js +1 -2
  54. package/dist/cjs/utils/tar-uploader.js +1 -2
  55. package/dist/cjs/utils/tar-writer.browser.js +1 -2
  56. package/dist/cjs/utils/tar-writer.js +1 -2
  57. package/dist/cjs/utils/type.js +35 -25
  58. package/dist/cjs/utils/url.js +3 -4
  59. package/dist/cjs/utils/workaround.js +7 -5
  60. package/dist/index.browser.min.js +1 -1
  61. package/dist/index.browser.min.js.map +1 -1
  62. package/dist/mjs/bee.js +93 -9
  63. package/dist/mjs/chunk/cac.js +21 -30
  64. package/dist/mjs/chunk/soc.js +16 -17
  65. package/dist/mjs/feed/index.js +7 -6
  66. package/dist/mjs/manifest/manifest.js +19 -2
  67. package/dist/mjs/modules/debug/stamps.js +37 -110
  68. package/dist/mjs/modules/debug/states.js +3 -0
  69. package/dist/mjs/modules/debug/status.js +1 -1
  70. package/dist/mjs/utils/chunk-stream.browser.js +29 -5
  71. package/dist/mjs/utils/expose.js +1 -1
  72. package/dist/mjs/utils/http.js +25 -3
  73. package/dist/mjs/utils/stamps.js +48 -0
  74. package/dist/mjs/utils/type.js +2 -1
  75. package/dist/mjs/utils/workaround.js +5 -2
  76. package/dist/types/bee.d.ts +67 -4
  77. package/dist/types/chunk/cac.d.ts +27 -13
  78. package/dist/types/chunk/soc.d.ts +43 -11
  79. package/dist/types/index.d.ts +3 -0
  80. package/dist/types/modules/bzz.d.ts +0 -1
  81. package/dist/types/modules/debug/status.d.ts +1 -1
  82. package/dist/types/modules/gsoc.d.ts +0 -1
  83. package/dist/types/modules/pss.d.ts +0 -1
  84. package/dist/types/types/debug.d.ts +1 -0
  85. package/dist/types/types/index.d.ts +1 -0
  86. package/dist/types/utils/constants.d.ts +3 -3
  87. package/dist/types/utils/error.d.ts +2 -2
  88. package/dist/types/utils/expose.d.ts +1 -1
  89. package/dist/types/utils/stamps.d.ts +15 -1
  90. package/dist/types/utils/tar-uploader.browser.d.ts +1 -1
  91. package/dist/types/utils/tar-uploader.d.ts +1 -1
  92. package/dist/types/utils/tar.browser.d.ts +1 -1
  93. package/dist/types/utils/tar.d.ts +0 -1
  94. package/dist/types/utils/type.d.ts +0 -1
  95. package/package.json +10 -13
package/README.md CHANGED
@@ -200,7 +200,7 @@ The `toString` method uses `toHex`.
200
200
  | `pssSend` | `POST /pss/send/:topic/:target` [🔗](https://docs.ethswarm.org/api/#tag/Postal-Service-for-Swarm/paths/~1pss~1send~1%7Btopic%7D~1%7Btargets%7D/post) | ❌✅✅ |
201
201
  | `pssSubscribe` _Websocket_ | `GET /pss/subscribe/:topic` [🔗](https://docs.ethswarm.org/api/#tag/Postal-Service-for-Swarm/paths/~1pss~1subscribe~1%7Btopic%7D/get) | ❌❌✅ |
202
202
  | `pssReceive` | `GET /pss/subscribe/:topic` [🔗](https://docs.ethswarm.org/api/#tag/Postal-Service-for-Swarm/paths/~1pss~1subscribe~1%7Btopic%7D/get) | ❌❌✅ |
203
- | `getAllPostageBatch` | `GET /stamps` [🔗](https://docs.ethswarm.org/api/#tag/Postage-Stamps/paths/~1stamps/get) | ❌✅✅ |
203
+ | `getPostageBatches` | `GET /stamps` [🔗](https://docs.ethswarm.org/api/#tag/Postage-Stamps/paths/~1stamps/get) | ❌✅✅ |
204
204
  | `getGlobalPostageBatches` | `GET /batches` [🔗](https://docs.ethswarm.org/api/#tag/Postage-Stamps/paths/~1batches/get) | ❌✅✅ |
205
205
  | `getPostageBatch` | `GET /stamps/:batchId` [🔗](https://docs.ethswarm.org/api/#tag/Postage-Stamps/paths/~1stamps~1%7Bbatch_id%7D/get) | ❌✅✅ |
206
206
  | `getPostageBatchBuckets` | `GET /stamps/:batchId/buckets` [🔗](https://docs.ethswarm.org/api/#tag/Postage-Stamps/paths/~1stamps~1%7Bbatch_id%7D~1buckets/get) | ❌✅✅ |
@@ -266,7 +266,7 @@ async function getOrCreatePostageBatch() {
266
266
  const bee = new Bee('http://localhost:1633')
267
267
  let batchId
268
268
 
269
- const batches = await bee.getAllPostageBatch()
269
+ const batches = await bee.getPostageBatches()
270
270
  const usable = batches.find(x => x.usable)
271
271
 
272
272
  if (usable) {
package/dist/cjs/bee.js CHANGED
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.Bee = void 0;
27
37
  const cafe_utility_1 = require("cafe-utility");
@@ -184,7 +194,7 @@ class Bee {
184
194
  * Chunks uploaded with this method should be retrieved with the {@link downloadChunk} method.
185
195
  *
186
196
  * @param stamp Postage Batch ID or an Envelope created with the {@link createEnvelope} method.
187
- * @param data Raw chunk to be uploaded
197
+ * @param data Raw chunk to be uploaded (Content Addressed Chunk or Single Owner Chunk)
188
198
  * @param options Additional options like tag, encryption, pinning, content-type and request options
189
199
  * @param requestOptions Options for making requests, such as timeouts, custom HTTP agents, headers, etc.
190
200
  *
@@ -193,6 +203,7 @@ class Bee {
193
203
  * @see [Bee API reference - `POST /chunks`](https://docs.ethswarm.org/api/#tag/Chunk/paths/~1chunks/post)
194
204
  */
195
205
  async uploadChunk(stamp, data, options, requestOptions) {
206
+ const isSOC = 'identifier' in data && 'signature' in data && 'owner' in data;
196
207
  data = data instanceof Uint8Array ? data : data.data;
197
208
  if (options) {
198
209
  options = (0, type_1.prepareUploadOptions)(options);
@@ -200,8 +211,11 @@ class Bee {
200
211
  if (data.length < typed_bytes_1.Span.LENGTH) {
201
212
  throw new error_1.BeeArgumentError(`Chunk has to have size of at least ${typed_bytes_1.Span.LENGTH}.`, data);
202
213
  }
203
- if (data.length > types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH) {
204
- throw new error_1.BeeArgumentError(`Chunk has to have size of at most ${types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH}.`, data);
214
+ if (!isSOC && data.length > types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH) {
215
+ throw new error_1.BeeArgumentError(`Content Addressed Chunk must not exceed ${types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH} bytes.`, data);
216
+ }
217
+ if (isSOC && data.length > types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH + typed_bytes_1.Signature.LENGTH + typed_bytes_1.Identifier.LENGTH) {
218
+ throw new error_1.BeeArgumentError(`Single Owner Chunk must not exceed ${types_1.CHUNK_SIZE + typed_bytes_1.Span.LENGTH + typed_bytes_1.Signature.LENGTH + typed_bytes_1.Identifier.LENGTH} bytes.`, data);
205
219
  }
206
220
  return chunk.upload(this.getRequestOptionsForCall(requestOptions), data, stamp, options);
207
221
  }
@@ -837,7 +851,7 @@ class Bee {
837
851
  signer = new typed_bytes_1.PrivateKey(signer);
838
852
  identifier = new typed_bytes_1.Identifier(identifier);
839
853
  const cac = (0, cac_1.makeContentAddressedChunk)(data);
840
- const soc = (0, soc_1.makeSingleOwnerChunk)(cac, identifier, signer);
854
+ const soc = cac.toSingleOwnerChunk(identifier, signer);
841
855
  return gsoc.send(this.getRequestOptionsForCall(requestOptions), soc, postageBatchId, options);
842
856
  }
843
857
  /**
@@ -968,6 +982,67 @@ class Bee {
968
982
  owner = new typed_bytes_1.EthAddress(owner);
969
983
  return (0, feed_2.fetchLatestFeedUpdate)(this.getRequestOptionsForCall(requestOptions), owner, topic);
970
984
  }
985
+ /**
986
+ * Creates a Content Addressed Chunk.
987
+ *
988
+ * To be uploaded with the {@link uploadChunk} method.
989
+ *
990
+ * Payload size must be between 1 and 4096 bytes.
991
+ *
992
+ * @param rawPayload Data to be stored in the chunk. If the data is a string, it will be converted to UTF-8 bytes.
993
+ * @param span Optional span for the chunk. If not provided, it will be set to the length of the payload.
994
+ */
995
+ makeContentAddressedChunk(rawPayload, span) {
996
+ return (0, cac_1.makeContentAddressedChunk)(rawPayload, span);
997
+ }
998
+ /**
999
+ * Attempts to unmarshal arbitrary data into a Content Addressed Chunk.
1000
+ * Throws an error if the data is not a valid CAC.
1001
+ *
1002
+ * @param data The chunk data (`span` and `payload`)
1003
+ */
1004
+ unmarshalContentAddressedChunk(data) {
1005
+ return (0, cac_1.unmarshalContentAddressedChunk)(data);
1006
+ }
1007
+ /**
1008
+ * Creates a Single Owner Chunk.
1009
+ *
1010
+ * To be uploaded with the {@link uploadChunk} method.
1011
+ *
1012
+ * Identical to chaining `makeContentAddressedChunk` and `toSingleOwnerChunk`.
1013
+ *
1014
+ * Payload size must be between 1 and 4096 bytes.
1015
+ *
1016
+ * @param address Address of the Content Addressed Chunk
1017
+ * @param span Span of the Content Addressed Chunk
1018
+ * @param payload Payload of the Content Addressed Chunk
1019
+ * @param identifier The identifier of the chunk
1020
+ * @param signer The signer interface for signing the chunk
1021
+ */
1022
+ makeSingleOwnerChunk(address, span, payload, identifier, signer) {
1023
+ return (0, soc_1.makeSingleOwnerChunk)(address, span, payload, identifier, signer);
1024
+ }
1025
+ /**
1026
+ * Calculates the address of a Single Owner Chunk based on its identifier and owner address.
1027
+ *
1028
+ * @param identifier
1029
+ * @param address
1030
+ */
1031
+ calculateSingleOwnerChunkAddress(identifier, address) {
1032
+ return (0, soc_1.makeSOCAddress)(identifier, address);
1033
+ }
1034
+ /**
1035
+ * Attempts to unmarshal arbitrary data into a Single Owner Chunk.
1036
+ * Throws an error if the data is not a valid SOC.
1037
+ *
1038
+ * @param data The chunk data
1039
+ * @param address The address of the single owner chunk
1040
+ *
1041
+ * @returns a single owner chunk or throws error
1042
+ */
1043
+ unmarshalSingleOwnerChunk(data, address) {
1044
+ return (0, soc_1.unmarshalSingleOwnerChunk)(data, address);
1045
+ }
971
1046
  /**
972
1047
  * Returns an object for reading single owner chunks
973
1048
  *
@@ -1550,7 +1625,9 @@ class Bee {
1550
1625
  const blockTime = this.network === 'gnosis' ? 5 : 15;
1551
1626
  const additionalAmount = (0, stamps_1.getAmountForDuration)(duration, chainState.currentPrice, blockTime);
1552
1627
  const currentAmount = (0, stamps_1.getAmountForDuration)(batch.duration, chainState.currentPrice, blockTime);
1553
- const targetAmount = duration.isZero() ? currentAmount * multiplier : currentAmount + additionalAmount * multiplier;
1628
+ const targetAmount = duration.isZero()
1629
+ ? currentAmount * multiplier
1630
+ : (currentAmount + additionalAmount) * multiplier;
1554
1631
  const amountDelta = targetAmount - currentAmount;
1555
1632
  const transactionId = await this.topUpBatch(batch.batchID, amountDelta, requestOptions);
1556
1633
  if (depthDelta > 0) {
@@ -1680,6 +1757,22 @@ class Bee {
1680
1757
  const amount = (0, stamps_1.getAmountForDuration)(duration, chainState.currentPrice, this.network === 'gnosis' ? 5 : 15);
1681
1758
  return (0, stamps_1.getStampCost)(batch.depth, amount);
1682
1759
  }
1760
+ /**
1761
+ * Calculates the `amount` and expected duration extension for topping up a postage batch with a given BZZ value.
1762
+ *
1763
+ * @param postageBatchId
1764
+ * @param bzz The amount of BZZ to spend on the top-up.
1765
+ * @param requestOptions Options for making requests, such as timeouts, custom HTTP agents, headers, etc.
1766
+ * @returns An object with `amount` (to pass to {@link topUpBatch}) and `duration` (the expected TTL extension).
1767
+ */
1768
+ async calculateTopUpForBzz(postageBatchId, bzz, requestOptions) {
1769
+ const batch = await this.getPostageBatch(postageBatchId, requestOptions);
1770
+ const chainState = await this.getChainState(requestOptions);
1771
+ const blockTime = this.network === 'gnosis' ? 5 : 15;
1772
+ const amount = bzz.toPLURBigInt() / 2n ** BigInt(batch.depth);
1773
+ const duration = (0, stamps_1.getStampDuration)(amount, chainState.currentPrice, blockTime);
1774
+ return { amount, duration };
1775
+ }
1683
1776
  /**
1684
1777
  * Increases the duration of a postage batch by increasing its amount.
1685
1778
  *
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateChunkAddress = void 0;
3
+ exports.calculateChunkAddress = calculateChunkAddress;
4
4
  const cafe_utility_1 = require("cafe-utility");
5
5
  const error_1 = require("../utils/error");
6
6
  const typed_bytes_1 = require("../utils/typed-bytes");
@@ -27,7 +27,6 @@ function calculateChunkAddress(chunkContent) {
27
27
  const chunkHash = cafe_utility_1.Binary.keccak256(cafe_utility_1.Binary.concatBytes(span, rootHash));
28
28
  return new typed_bytes_1.Reference(chunkHash);
29
29
  }
30
- exports.calculateChunkAddress = calculateChunkAddress;
31
30
  function calculateBmtRootHash(payload) {
32
31
  if (payload.length > MAX_CHUNK_PAYLOAD_SIZE) {
33
32
  throw new error_1.BeeArgumentError(`payload size ${payload.length} exceeds maximum chunk payload size ${MAX_CHUNK_PAYLOAD_SIZE}`, payload);
@@ -1,46 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.asContentAddressedChunk = exports.makeContentAddressedChunk = exports.MAX_PAYLOAD_SIZE = exports.MIN_PAYLOAD_SIZE = void 0;
3
+ exports.MAX_PAYLOAD_SIZE = exports.MIN_PAYLOAD_SIZE = void 0;
4
+ exports.unmarshalContentAddressedChunk = unmarshalContentAddressedChunk;
5
+ exports.makeContentAddressedChunk = makeContentAddressedChunk;
4
6
  const cafe_utility_1 = require("cafe-utility");
5
7
  const bytes_1 = require("../utils/bytes");
6
8
  const typed_bytes_1 = require("../utils/typed-bytes");
7
9
  const bmt_1 = require("./bmt");
10
+ const soc_1 = require("./soc");
8
11
  exports.MIN_PAYLOAD_SIZE = 1;
9
12
  exports.MAX_PAYLOAD_SIZE = 4096;
10
- const ENCODER = new TextEncoder();
11
- /**
12
- * Creates a content addressed chunk and verifies the payload size.
13
- *
14
- * @param payloadBytes the data to be stored in the chunk
15
- */
16
- function makeContentAddressedChunk(payloadBytes) {
17
- if (!(payloadBytes instanceof Uint8Array)) {
18
- payloadBytes = ENCODER.encode(payloadBytes);
19
- }
20
- if (payloadBytes.length < exports.MIN_PAYLOAD_SIZE || payloadBytes.length > exports.MAX_PAYLOAD_SIZE) {
21
- throw new RangeError(`payload size ${payloadBytes.length} exceeds limits [${exports.MIN_PAYLOAD_SIZE}, ${exports.MAX_PAYLOAD_SIZE}]`);
22
- }
23
- const span = typed_bytes_1.Span.fromBigInt(BigInt(payloadBytes.length));
24
- const data = cafe_utility_1.Binary.concatBytes(span.toUint8Array(), payloadBytes);
25
- return {
26
- data,
27
- span,
28
- payload: bytes_1.Bytes.fromSlice(data, typed_bytes_1.Span.LENGTH),
29
- address: (0, bmt_1.calculateChunkAddress)(data),
30
- };
13
+ function unmarshalContentAddressedChunk(data) {
14
+ data = new bytes_1.Bytes(data);
15
+ return makeContentAddressedChunk(data.toUint8Array().slice(typed_bytes_1.Span.LENGTH), typed_bytes_1.Span.fromSlice(data.toUint8Array(), 0));
31
16
  }
32
- exports.makeContentAddressedChunk = makeContentAddressedChunk;
33
- function asContentAddressedChunk(chunkBytes) {
34
- if (chunkBytes.length < exports.MIN_PAYLOAD_SIZE + typed_bytes_1.Span.LENGTH || chunkBytes.length > exports.MAX_PAYLOAD_SIZE + typed_bytes_1.Span.LENGTH) {
35
- throw new RangeError(`chunk size ${chunkBytes.length} exceeds limits [${exports.MIN_PAYLOAD_SIZE + typed_bytes_1.Span.LENGTH}, ${typed_bytes_1.Span.LENGTH}]`);
17
+ function makeContentAddressedChunk(rawPayload, span) {
18
+ if (cafe_utility_1.Types.isString(rawPayload)) {
19
+ rawPayload = bytes_1.Bytes.fromUtf8(rawPayload);
20
+ }
21
+ if (rawPayload.length < exports.MIN_PAYLOAD_SIZE || rawPayload.length > exports.MAX_PAYLOAD_SIZE) {
22
+ throw new RangeError(`payload size ${rawPayload.length} exceeds limits [${exports.MIN_PAYLOAD_SIZE}, ${exports.MAX_PAYLOAD_SIZE}]`);
36
23
  }
37
- const span = typed_bytes_1.Span.fromSlice(chunkBytes, 0);
38
- const data = cafe_utility_1.Binary.concatBytes(span.toUint8Array(), chunkBytes.slice(typed_bytes_1.Span.LENGTH));
24
+ const typedSpan = span
25
+ ? typeof span === 'bigint'
26
+ ? typed_bytes_1.Span.fromBigInt(span)
27
+ : span
28
+ : typed_bytes_1.Span.fromBigInt(BigInt(rawPayload.length));
29
+ const payload = new bytes_1.Bytes(rawPayload);
30
+ const data = cafe_utility_1.Binary.concatBytes(typedSpan.toUint8Array(), payload.toUint8Array());
31
+ const address = (0, bmt_1.calculateChunkAddress)(data);
39
32
  return {
40
33
  data,
41
- span,
42
- payload: bytes_1.Bytes.fromSlice(data, typed_bytes_1.Span.LENGTH),
43
- address: (0, bmt_1.calculateChunkAddress)(data),
34
+ span: typedSpan,
35
+ payload,
36
+ address,
37
+ toSingleOwnerChunk: (identifier, signer) => {
38
+ return (0, soc_1.makeSingleOwnerChunk)(address, typedSpan, payload, identifier, signer);
39
+ },
44
40
  };
45
41
  }
46
- exports.asContentAddressedChunk = asContentAddressedChunk;
@@ -15,15 +15,31 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.downloadSingleOwnerChunk = exports.uploadSingleOwnerChunkWithWrappedChunk = exports.uploadSingleOwnerChunkData = exports.uploadSingleOwnerChunk = exports.makeSingleOwnerChunk = exports.makeSOCAddress = exports.makeSingleOwnerChunkFromData = void 0;
36
+ exports.unmarshalSingleOwnerChunk = unmarshalSingleOwnerChunk;
37
+ exports.makeSOCAddress = makeSOCAddress;
38
+ exports.makeSingleOwnerChunk = makeSingleOwnerChunk;
39
+ exports.uploadSingleOwnerChunk = uploadSingleOwnerChunk;
40
+ exports.uploadSingleOwnerChunkData = uploadSingleOwnerChunkData;
41
+ exports.uploadSingleOwnerChunkWithWrappedChunk = uploadSingleOwnerChunkWithWrappedChunk;
42
+ exports.downloadSingleOwnerChunk = downloadSingleOwnerChunk;
27
43
  const cafe_utility_1 = require("cafe-utility");
28
44
  const chunkAPI = __importStar(require("../modules/chunk"));
29
45
  const socAPI = __importStar(require("../modules/soc"));
@@ -33,8 +49,8 @@ const typed_bytes_1 = require("../utils/typed-bytes");
33
49
  const bmt_1 = require("./bmt");
34
50
  const cac_1 = require("./cac");
35
51
  const SOC_SIGNATURE_OFFSET = typed_bytes_1.Identifier.LENGTH;
36
- const SOC_SPAN_OFFSET = SOC_SIGNATURE_OFFSET + typed_bytes_1.Signature.LENGTH;
37
- const SOC_PAYLOAD_OFFSET = SOC_SPAN_OFFSET + typed_bytes_1.Span.LENGTH;
52
+ const SOC_SPAN_OFFSET = typed_bytes_1.Identifier.LENGTH + typed_bytes_1.Signature.LENGTH;
53
+ const SOC_PAYLOAD_OFFSET = typed_bytes_1.Identifier.LENGTH + typed_bytes_1.Signature.LENGTH + typed_bytes_1.Span.LENGTH;
38
54
  function recoverChunkOwner(data) {
39
55
  const cacData = data.slice(SOC_SPAN_OFFSET);
40
56
  const chunkAddress = (0, bmt_1.calculateChunkAddress)(cacData);
@@ -45,21 +61,22 @@ function recoverChunkOwner(data) {
45
61
  return ownerAddress;
46
62
  }
47
63
  /**
48
- * Verifies if the data is a valid single owner chunk
64
+ * Unmarshals arbitrary data into a Single Owner Chunk.
65
+ * Throws an error if the data is not a valid SOC.
49
66
  *
50
67
  * @param data The chunk data
51
68
  * @param address The address of the single owner chunk
52
69
  *
53
70
  * @returns a single owner chunk or throws error
54
71
  */
55
- function makeSingleOwnerChunkFromData(data, address) {
72
+ function unmarshalSingleOwnerChunk(data, address) {
56
73
  data = data instanceof bytes_1.Bytes ? data.toUint8Array() : data;
57
74
  address = new typed_bytes_1.Reference(address);
58
75
  const ownerAddress = recoverChunkOwner(data);
59
76
  const identifier = bytes_1.Bytes.fromSlice(data, 0, typed_bytes_1.Identifier.LENGTH);
60
77
  const socAddress = new typed_bytes_1.Reference(cafe_utility_1.Binary.keccak256(cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), ownerAddress.toUint8Array())));
61
78
  if (!cafe_utility_1.Binary.equals(address.toUint8Array(), socAddress.toUint8Array())) {
62
- throw new error_1.BeeError('SOC Data does not match given address!');
79
+ throw new error_1.BeeError('SOC data does not match given address!');
63
80
  }
64
81
  const signature = typed_bytes_1.Signature.fromSlice(data, SOC_SIGNATURE_OFFSET);
65
82
  const span = typed_bytes_1.Span.fromSlice(data, SOC_SPAN_OFFSET);
@@ -74,11 +91,9 @@ function makeSingleOwnerChunkFromData(data, address) {
74
91
  owner: ownerAddress,
75
92
  };
76
93
  }
77
- exports.makeSingleOwnerChunkFromData = makeSingleOwnerChunkFromData;
78
94
  function makeSOCAddress(identifier, address) {
79
95
  return new typed_bytes_1.Reference(cafe_utility_1.Binary.keccak256(cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), address.toUint8Array())));
80
96
  }
81
- exports.makeSOCAddress = makeSOCAddress;
82
97
  /**
83
98
  * Creates a single owner chunk object
84
99
  *
@@ -86,25 +101,22 @@ exports.makeSOCAddress = makeSOCAddress;
86
101
  * @param identifier The identifier of the chunk
87
102
  * @param signer The signer interface for signing the chunk
88
103
  */
89
- function makeSingleOwnerChunk(chunk, identifier, signer) {
104
+ function makeSingleOwnerChunk(address, span, payload, identifier, signer) {
90
105
  identifier = new typed_bytes_1.Identifier(identifier);
91
106
  signer = new typed_bytes_1.PrivateKey(signer);
92
- const address = makeSOCAddress(identifier, signer.publicKey().address());
93
- const signature = signer.sign(cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), chunk.address.toUint8Array()));
94
- const data = cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), signature.toUint8Array(), chunk.data);
95
- const span = typed_bytes_1.Span.fromSlice(chunk.data, 0);
96
- const payload = bytes_1.Bytes.fromSlice(chunk.data, typed_bytes_1.Span.LENGTH);
107
+ const socAddress = makeSOCAddress(identifier, signer.publicKey().address());
108
+ const signature = signer.sign(cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), address.toUint8Array()));
109
+ const data = cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), signature.toUint8Array(), span.toUint8Array(), payload.toUint8Array());
97
110
  return {
98
111
  data,
99
112
  identifier,
100
113
  signature,
101
114
  span,
102
115
  payload,
103
- address,
116
+ address: socAddress,
104
117
  owner: signer.publicKey().address(),
105
118
  };
106
119
  }
107
- exports.makeSingleOwnerChunk = makeSingleOwnerChunk;
108
120
  /**
109
121
  * Helper function to upload a chunk.
110
122
  *
@@ -119,7 +131,6 @@ async function uploadSingleOwnerChunk(requestOptions, chunk, stamp, options) {
119
131
  const data = cafe_utility_1.Binary.concatBytes(chunk.span.toUint8Array(), chunk.payload.toUint8Array());
120
132
  return socAPI.upload(requestOptions, chunk.owner, chunk.identifier, chunk.signature, data, stamp, options);
121
133
  }
122
- exports.uploadSingleOwnerChunk = uploadSingleOwnerChunk;
123
134
  /**
124
135
  * Helper function to create and upload SOC.
125
136
  *
@@ -134,17 +145,15 @@ async function uploadSingleOwnerChunkData(requestOptions, signer, stamp, identif
134
145
  signer = new typed_bytes_1.PrivateKey(signer);
135
146
  identifier = new typed_bytes_1.Identifier(identifier);
136
147
  const cac = (0, cac_1.makeContentAddressedChunk)(data);
137
- const soc = makeSingleOwnerChunk(cac, identifier, signer);
148
+ const soc = cac.toSingleOwnerChunk(identifier, signer);
138
149
  return uploadSingleOwnerChunk(requestOptions, soc, stamp, options);
139
150
  }
140
- exports.uploadSingleOwnerChunkData = uploadSingleOwnerChunkData;
141
- async function uploadSingleOwnerChunkWithWrappedChunk(requestOptions, signer, stamp, identifier, rootChunk, options) {
151
+ async function uploadSingleOwnerChunkWithWrappedChunk(requestOptions, signer, stamp, identifier, wrappedChunk, options) {
142
152
  signer = new typed_bytes_1.PrivateKey(signer);
143
153
  identifier = new typed_bytes_1.Identifier(identifier);
144
- const soc = makeSingleOwnerChunk((0, cac_1.asContentAddressedChunk)(rootChunk), identifier, signer);
154
+ const soc = wrappedChunk.toSingleOwnerChunk(identifier, signer);
145
155
  return uploadSingleOwnerChunk(requestOptions, soc, stamp, options);
146
156
  }
147
- exports.uploadSingleOwnerChunkWithWrappedChunk = uploadSingleOwnerChunkWithWrappedChunk;
148
157
  /**
149
158
  * Helper function to download SOC.
150
159
  *
@@ -157,6 +166,5 @@ async function downloadSingleOwnerChunk(requestOptions, ownerAddress, identifier
157
166
  ownerAddress = new typed_bytes_1.EthAddress(ownerAddress);
158
167
  const address = makeSOCAddress(identifier, ownerAddress);
159
168
  const cac = await chunkAPI.download(requestOptions, address.toHex());
160
- return makeSingleOwnerChunkFromData(cac, address);
169
+ return unmarshalSingleOwnerChunk(cac, address);
161
170
  }
162
- exports.downloadSingleOwnerChunk = downloadSingleOwnerChunk;
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.makeFeedIdentifier = void 0;
3
+ exports.makeFeedIdentifier = makeFeedIdentifier;
4
4
  const cafe_utility_1 = require("cafe-utility");
5
5
  const typed_bytes_1 = require("../utils/typed-bytes");
6
6
  function makeFeedIdentifier(topic, index) {
7
7
  index = typeof index === 'number' ? typed_bytes_1.FeedIndex.fromBigInt(BigInt(index)) : index;
8
8
  return new typed_bytes_1.Identifier(cafe_utility_1.Binary.keccak256(cafe_utility_1.Binary.concatBytes(topic.toUint8Array(), index.toUint8Array())));
9
9
  }
10
- exports.makeFeedIdentifier = makeFeedIdentifier;
@@ -15,15 +15,32 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.makeFeedWriter = exports.makeFeedReader = exports.downloadFeedUpdateAsCAC = exports.downloadFeedUpdate = exports.getFeedUpdateChunkReference = exports.updateFeedWithPayload = exports.updateFeedWithReference = exports.findNextIndex = void 0;
36
+ exports.findNextIndex = findNextIndex;
37
+ exports.updateFeedWithReference = updateFeedWithReference;
38
+ exports.updateFeedWithPayload = updateFeedWithPayload;
39
+ exports.getFeedUpdateChunkReference = getFeedUpdateChunkReference;
40
+ exports.downloadFeedUpdate = downloadFeedUpdate;
41
+ exports.downloadFeedUpdateAsCAC = downloadFeedUpdateAsCAC;
42
+ exports.makeFeedReader = makeFeedReader;
43
+ exports.makeFeedWriter = makeFeedWriter;
27
44
  const cafe_utility_1 = require("cafe-utility");
28
45
  const cac_1 = require("../chunk/cac");
29
46
  const soc_1 = require("../chunk/soc");
@@ -53,7 +70,6 @@ async function findNextIndex(requestOptions, owner, topic) {
53
70
  throw e;
54
71
  }
55
72
  }
56
- exports.findNextIndex = findNextIndex;
57
73
  async function updateFeedWithReference(requestOptions, signer, topic, reference, postageBatchId, options) {
58
74
  reference = new typed_bytes_1.Reference(reference);
59
75
  const nextIndex = options?.index ?? (await findNextIndex(requestOptions, signer.publicKey().address(), topic));
@@ -63,28 +79,25 @@ async function updateFeedWithReference(requestOptions, signer, topic, reference,
63
79
  const payloadBytes = cafe_utility_1.Binary.concatBytes(timestamp, reference.toUint8Array());
64
80
  return (0, soc_1.uploadSingleOwnerChunkData)(requestOptions, signer, postageBatchId, identifier, payloadBytes, options);
65
81
  }
66
- exports.updateFeedWithReference = updateFeedWithReference;
67
82
  async function updateFeedWithPayload(requestOptions, signer, topic, data, postageBatchId, options) {
68
83
  const nextIndex = options?.index ?? (await findNextIndex(requestOptions, signer.publicKey().address(), topic));
69
84
  const identifier = (0, identifier_1.makeFeedIdentifier)(topic, nextIndex);
70
85
  if (data.length > 4096) {
71
86
  const uploadResult = await bytes.upload(requestOptions, data, postageBatchId, options);
72
- const rootChunk = await chunkAPI.download(requestOptions, uploadResult.reference);
87
+ const rootChunk = (0, cac_1.unmarshalContentAddressedChunk)(await chunkAPI.download(requestOptions, uploadResult.reference));
73
88
  return (0, soc_1.uploadSingleOwnerChunkWithWrappedChunk)(requestOptions, signer, postageBatchId, identifier, rootChunk, options);
74
89
  }
75
90
  return (0, soc_1.uploadSingleOwnerChunkData)(requestOptions, signer, postageBatchId, identifier, cafe_utility_1.Types.isString(data) ? bytes_1.Bytes.fromUtf8(data).toUint8Array() : data, options);
76
91
  }
77
- exports.updateFeedWithPayload = updateFeedWithPayload;
78
92
  function getFeedUpdateChunkReference(owner, topic, index) {
79
93
  const identifier = (0, identifier_1.makeFeedIdentifier)(topic, index);
80
94
  return new typed_bytes_1.Reference(cafe_utility_1.Binary.keccak256(cafe_utility_1.Binary.concatBytes(identifier.toUint8Array(), owner.toUint8Array())));
81
95
  }
82
- exports.getFeedUpdateChunkReference = getFeedUpdateChunkReference;
83
96
  async function downloadFeedUpdate(requestOptions, owner, topic, index, hasTimestamp = false) {
84
97
  index = typeof index === 'number' ? typed_bytes_1.FeedIndex.fromBigInt(BigInt(index)) : index;
85
98
  const address = getFeedUpdateChunkReference(owner, topic, index);
86
99
  const data = await chunkAPI.download(requestOptions, address.toHex());
87
- const soc = (0, soc_1.makeSingleOwnerChunkFromData)(data, address);
100
+ const soc = (0, soc_1.unmarshalSingleOwnerChunk)(data, address);
88
101
  let timestamp = cafe_utility_1.Optional.empty();
89
102
  if (hasTimestamp) {
90
103
  const timestampBytes = bytes_1.Bytes.fromSlice(soc.payload.toUint8Array(), TIMESTAMP_PAYLOAD_OFFSET, TIMESTAMP_PAYLOAD_SIZE);
@@ -95,14 +108,13 @@ async function downloadFeedUpdate(requestOptions, owner, topic, index, hasTimest
95
108
  payload: new bytes_1.Bytes(soc.payload.offset(hasTimestamp ? REFERENCE_PAYLOAD_OFFSET : 0)),
96
109
  };
97
110
  }
98
- exports.downloadFeedUpdate = downloadFeedUpdate;
99
111
  async function downloadFeedUpdateAsCAC(requestOptions, owner, topic, index) {
100
112
  index = typeof index === 'number' ? typed_bytes_1.FeedIndex.fromBigInt(BigInt(index)) : index;
101
113
  const address = getFeedUpdateChunkReference(owner, topic, index);
102
114
  const data = await chunkAPI.download(requestOptions, address);
103
- return (0, cac_1.asContentAddressedChunk)(data.slice(typed_bytes_1.Identifier.LENGTH + typed_bytes_1.Signature.LENGTH));
115
+ const soc = (0, soc_1.unmarshalSingleOwnerChunk)(data, address);
116
+ return (0, cac_1.makeContentAddressedChunk)(soc.payload, soc.span);
104
117
  }
105
- exports.downloadFeedUpdateAsCAC = downloadFeedUpdateAsCAC;
106
118
  function makeFeedReader(requestOptions, topic, owner) {
107
119
  // TODO: remove after enough time has passed in deprecated version
108
120
  const download = async (options) => {
@@ -152,7 +164,6 @@ function makeFeedReader(requestOptions, topic, owner) {
152
164
  topic,
153
165
  };
154
166
  }
155
- exports.makeFeedReader = makeFeedReader;
156
167
  function makeFeedWriter(requestOptions, topic, signer) {
157
168
  const upload = async (postageBatchId, reference, options) => {
158
169
  return updateFeedWithReference(requestOptions, signer, topic, reference, postageBatchId, options);
@@ -167,4 +178,3 @@ function makeFeedWriter(requestOptions, topic, signer) {
167
178
  uploadPayload,
168
179
  };
169
180
  }
170
- exports.makeFeedWriter = makeFeedWriter;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.areAllSequentialFeedsUpdateRetrievable = void 0;
3
+ exports.areAllSequentialFeedsUpdateRetrievable = areAllSequentialFeedsUpdateRetrievable;
4
4
  const cafe_utility_1 = require("cafe-utility");
5
5
  const typed_bytes_1 = require("../utils/typed-bytes");
6
6
  const index_1 = require("./index");
@@ -44,4 +44,3 @@ async function areAllSequentialFeedsUpdateRetrievable(bee, owner, topic, index,
44
44
  const chunkRetrievablePromises = getAllSequenceUpdateReferences(owner, topic, index).map(async (reference) => isChunkRetrievable(bee, reference, options, requestOptions));
45
45
  return (await Promise.all(chunkRetrievablePromises)).every(result => result);
46
46
  }
47
- exports.areAllSequentialFeedsUpdateRetrievable = areAllSequentialFeedsUpdateRetrievable;
package/dist/cjs/index.js CHANGED
@@ -18,13 +18,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
18
18
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
19
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
20
  };
21
- var __importStar = (this && this.__importStar) || function (mod) {
22
- if (mod && mod.__esModule) return mod;
23
- var result = {};
24
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25
- __setModuleDefault(result, mod);
26
- return result;
27
- };
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.Stamper = exports.BeeDev = exports.Bee = exports.Size = exports.Utils = exports.Duration = exports.Bytes = exports.SUPPORTED_BEE_VERSION_EXACT = exports.SUPPORTED_BEE_VERSION = exports.MantarayNode = exports.MerkleTree = void 0;
30
40
  const bee_1 = require("./bee");
@@ -316,7 +316,17 @@ class MantarayNode {
316
316
  */
317
317
  async saveRecursively(bee, postageBatchId, options, requestOptions) {
318
318
  for (const fork of this.forks.values()) {
319
- await fork.node.saveRecursively(bee, postageBatchId, options, requestOptions);
319
+ const uploadResult = await fork.node.saveRecursively(bee, postageBatchId, options, requestOptions);
320
+ if (options?.act) {
321
+ let historyAddress;
322
+ uploadResult.historyAddress.ifPresent(ref => (historyAddress = ref));
323
+ if (historyAddress) {
324
+ if (!fork.node.metadata) {
325
+ fork.node.metadata = {};
326
+ }
327
+ fork.node.metadata['swarm-act-history-address'] = historyAddress.toHex();
328
+ }
329
+ }
320
330
  }
321
331
  const result = await bee.uploadData(postageBatchId, await this.marshal(), options, requestOptions);
322
332
  this.selfAddress = result.reference.toUint8Array();
@@ -330,7 +340,14 @@ class MantarayNode {
330
340
  if (!fork.node.selfAddress) {
331
341
  throw Error('MantarayNode#loadRecursively fork.node.selfAddress is not set');
332
342
  }
333
- const node = await MantarayNode.unmarshal(bee, fork.node.selfAddress, options, requestOptions);
343
+ let downloadOptions = options;
344
+ if (fork.node.metadata && fork.node.metadata['swarm-act-history-address']) {
345
+ downloadOptions = {
346
+ ...options,
347
+ actHistoryAddress: fork.node.metadata['swarm-act-history-address'],
348
+ };
349
+ }
350
+ const node = await MantarayNode.unmarshal(bee, fork.node.selfAddress, downloadOptions, requestOptions);
334
351
  fork.node.targetAddress = node.targetAddress;
335
352
  fork.node.forks = node.forks;
336
353
  fork.node.path = fork.prefix;