@net-protocol/storage 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,54 @@
1
1
  # @net-protocol/storage
2
2
 
3
- Net Storage SDK for key-value storage on the Net protocol. Supports regular storage, chunked storage, and XML storage patterns.
3
+ **Status: Alpha** - Usable but may have breaking changes over time. Suitable for early adopters and testing.
4
+
5
+ Net Storage SDK for permanent onchain key-value storage built on Net Protocol.
6
+
7
+ ## What is Net Storage?
8
+
9
+ Net Storage provides permanent, versioned key-value storage on the blockchain. Every write creates a new version, preserving complete history. Unlike traditional databases, Storage data is:
10
+
11
+ - **Immutable**: Once stored, data cannot be modified
12
+ - **Versioned**: Complete history of all changes preserved
13
+ - **Transparent**: All data is publicly verifiable
14
+ - **Decentralized**: No central servers or databases
15
+
16
+ ## Storage Types
17
+
18
+ Net Storage supports three storage patterns for different file sizes:
19
+
20
+ ### Regular Storage
21
+
22
+ **Best for**: Small data (< 20KB)
23
+ **How it works**: Stores data directly as Net messages
24
+ **Use cases**: User settings, configuration, small metadata
25
+
26
+ ### Chunked Storage
27
+
28
+ **Best for**: Medium files (20KB-80KB)
29
+ **How it works**: Compresses data (gzip) and splits into 20KB chunks
30
+ **Use cases**: Images, documents, medium-sized data
31
+
32
+ ### XML Storage
33
+
34
+ **Best for**: Large files (multi-MB)
35
+ **How it works**: Splits large files into 80KB pieces, stores each using ChunkedStorage, maintains references as XML metadata
36
+ **Use cases**: Videos, large images, datasets, any large file
37
+
38
+ ## What can you do with this package?
39
+
40
+ - **Store data permanently**: Write key-value pairs that persist forever on the blockchain
41
+ - **Access version history**: Read any historical version of stored data
42
+ - **Store files of any size**: From small settings to multi-MB files
43
+ - **Build storage apps**: Create applications that need permanent, verifiable data storage
44
+
45
+ This package provides both React hooks (for UI) and client classes (for non-React code).
46
+
47
+ ## Learn More
48
+
49
+ - [Net Storage Documentation](https://docs.netprotocol.app/docs/apps/storage/01-overview) - Complete storage documentation
50
+ - [Storage Developer Guide](https://docs.netprotocol.app/docs/apps/storage/03-developer-guide) - Technical implementation details
51
+ - [Net Protocol Documentation](https://docs.netprotocol.app) - Core protocol documentation
4
52
 
5
53
  ## Installation
6
54
 
@@ -23,7 +71,11 @@ yarn add @net-protocol/storage
23
71
  ### React Hooks
24
72
 
25
73
  ```typescript
26
- import { useStorage, useXmlStorage, useStorageFromRouter } from "@net-protocol/storage";
74
+ import {
75
+ useStorage,
76
+ useXmlStorage,
77
+ useStorageFromRouter,
78
+ } from "@net-protocol/storage";
27
79
 
28
80
  // Basic storage read
29
81
  function MyComponent() {
@@ -35,7 +87,7 @@ function MyComponent() {
35
87
 
36
88
  if (isLoading) return <div>Loading...</div>;
37
89
  if (error) return <div>Error: {error.message}</div>;
38
-
90
+
39
91
  const [text, data] = data || [];
40
92
  return <div>{text}</div>;
41
93
  }
@@ -102,7 +154,11 @@ function XmlWithFormats() {
102
154
  });
103
155
 
104
156
  // Return as object format (default)
105
- const { data: objectData, filename, isXml } = useXmlStorage({
157
+ const {
158
+ data: objectData,
159
+ filename,
160
+ isXml,
161
+ } = useXmlStorage({
106
162
  chainId: 8453,
107
163
  key: "my-xml-key",
108
164
  operatorAddress: "0x...",
@@ -180,7 +236,7 @@ const chunks = chunkDataForStorage("large data string");
180
236
  const assembled = assembleChunks(chunks);
181
237
 
182
238
  // Parse XML references
183
- const references = parseNetReferences("<net k=\"hash\" v=\"0.0.1\" />");
239
+ const references = parseNetReferences('<net k="hash" v="0.0.1" />');
184
240
 
185
241
  // Process data for XML storage
186
242
  const result = processDataForStorage(data, operatorAddress);
@@ -229,4 +285,3 @@ Hierarchical storage using XML references. Supports recursive resolution and ope
229
285
  ## License
230
286
 
231
287
  MIT
232
-
package/dist/index.d.mts CHANGED
@@ -3,9 +3,12 @@ import { Abi, PublicClient } from 'viem';
3
3
  import { WriteTransactionConfig } from '@net-protocol/core';
4
4
 
5
5
  /**
6
- * Storage data tuple: [text, data]
6
+ * Storage data object: { text, value }
7
7
  */
8
- type StorageData = [string, string];
8
+ type StorageData = {
9
+ text: string;
10
+ value: string;
11
+ };
9
12
  /**
10
13
  * Bulk storage key for batch operations
11
14
  */
@@ -73,7 +76,6 @@ type UseXmlStorageOptions = {
73
76
  index?: number;
74
77
  keyFormat?: "raw" | "bytes32";
75
78
  useRouter?: boolean;
76
- returnFormat?: "object" | "tuple";
77
79
  outputFormat?: "hex" | "string";
78
80
  };
79
81
  /**
@@ -96,8 +98,11 @@ declare function useStorageForOperator({ chainId, operatorAddress, }: UseStorage
96
98
  isLoading: boolean;
97
99
  error: undefined;
98
100
  };
99
- declare function useStorageForOperatorAndKey({ chainId, key, operatorAddress, keyFormat, }: UseStorageOptions): {
100
- data: StorageData | undefined;
101
+ declare function useStorageForOperatorAndKey({ chainId, key, operatorAddress, keyFormat, outputFormat, }: UseStorageOptions): {
102
+ data: {
103
+ text: string;
104
+ value: string;
105
+ } | undefined;
101
106
  isLoading: boolean;
102
107
  error: Error | undefined;
103
108
  };
@@ -130,15 +135,9 @@ declare function useStorageTotalWrites({ chainId, key, operatorAddress, enabled,
130
135
  error: viem.ReadContractErrorType | null | undefined;
131
136
  };
132
137
 
133
- declare function useXmlStorage({ chainId, key, operatorAddress, skipXmlParsing, enabled, content, index, keyFormat, useRouter, returnFormat, outputFormat, }: UseXmlStorageOptions): {
134
- data: StorageData | undefined;
135
- isLoading: boolean;
136
- error: Error | undefined;
137
- filename?: undefined;
138
- isXml?: undefined;
139
- } | {
140
- data: string | undefined;
141
- filename: string;
138
+ declare function useXmlStorage({ chainId, key, operatorAddress, skipXmlParsing, enabled, content, index, keyFormat, useRouter, outputFormat, }: UseXmlStorageOptions): {
139
+ text: string;
140
+ value: string;
142
141
  isLoading: boolean;
143
142
  error: Error | undefined;
144
143
  isXml: boolean;
package/dist/index.d.ts CHANGED
@@ -3,9 +3,12 @@ import { Abi, PublicClient } from 'viem';
3
3
  import { WriteTransactionConfig } from '@net-protocol/core';
4
4
 
5
5
  /**
6
- * Storage data tuple: [text, data]
6
+ * Storage data object: { text, value }
7
7
  */
8
- type StorageData = [string, string];
8
+ type StorageData = {
9
+ text: string;
10
+ value: string;
11
+ };
9
12
  /**
10
13
  * Bulk storage key for batch operations
11
14
  */
@@ -73,7 +76,6 @@ type UseXmlStorageOptions = {
73
76
  index?: number;
74
77
  keyFormat?: "raw" | "bytes32";
75
78
  useRouter?: boolean;
76
- returnFormat?: "object" | "tuple";
77
79
  outputFormat?: "hex" | "string";
78
80
  };
79
81
  /**
@@ -96,8 +98,11 @@ declare function useStorageForOperator({ chainId, operatorAddress, }: UseStorage
96
98
  isLoading: boolean;
97
99
  error: undefined;
98
100
  };
99
- declare function useStorageForOperatorAndKey({ chainId, key, operatorAddress, keyFormat, }: UseStorageOptions): {
100
- data: StorageData | undefined;
101
+ declare function useStorageForOperatorAndKey({ chainId, key, operatorAddress, keyFormat, outputFormat, }: UseStorageOptions): {
102
+ data: {
103
+ text: string;
104
+ value: string;
105
+ } | undefined;
101
106
  isLoading: boolean;
102
107
  error: Error | undefined;
103
108
  };
@@ -130,15 +135,9 @@ declare function useStorageTotalWrites({ chainId, key, operatorAddress, enabled,
130
135
  error: viem.ReadContractErrorType | null | undefined;
131
136
  };
132
137
 
133
- declare function useXmlStorage({ chainId, key, operatorAddress, skipXmlParsing, enabled, content, index, keyFormat, useRouter, returnFormat, outputFormat, }: UseXmlStorageOptions): {
134
- data: StorageData | undefined;
135
- isLoading: boolean;
136
- error: Error | undefined;
137
- filename?: undefined;
138
- isXml?: undefined;
139
- } | {
140
- data: string | undefined;
141
- filename: string;
138
+ declare function useXmlStorage({ chainId, key, operatorAddress, skipXmlParsing, enabled, content, index, keyFormat, useRouter, outputFormat, }: UseXmlStorageOptions): {
139
+ text: string;
140
+ value: string;
142
141
  isLoading: boolean;
143
142
  error: Error | undefined;
144
143
  isXml: boolean;
package/dist/index.js CHANGED
@@ -747,10 +747,10 @@ function useStorage({
747
747
  const outputAsString = outputFormat === "string";
748
748
  const storageKeyBytes = key ? getStorageKeyBytes(key, keyFormat) : void 0;
749
749
  const formatData = (text, dataHex) => {
750
- if (outputAsString) {
751
- return [text, viem.hexToString(dataHex)];
752
- }
753
- return [text, dataHex];
750
+ return {
751
+ text,
752
+ value: outputAsString ? viem.hexToString(dataHex) : dataHex
753
+ };
754
754
  };
755
755
  const [routerData, setRouterData] = react.useState();
756
756
  const [routerChunkLoading, setRouterChunkLoading] = react.useState(false);
@@ -772,6 +772,10 @@ function useStorage({
772
772
  }
773
773
  const [isChunkedStorage, text, data] = routerHook.data;
774
774
  if (!isChunkedStorage) {
775
+ if (!data || typeof data !== "string") {
776
+ setRouterData(void 0);
777
+ return;
778
+ }
775
779
  const formatted = formatData(text, data);
776
780
  setRouterData(formatted);
777
781
  return;
@@ -804,10 +808,10 @@ function useStorage({
804
808
  setRouterData(void 0);
805
809
  } else {
806
810
  if (outputAsString) {
807
- setRouterData([text, assembledString]);
811
+ setRouterData({ text, value: assembledString });
808
812
  } else {
809
813
  const hexData = viem.stringToHex(assembledString);
810
- setRouterData([text, hexData]);
814
+ setRouterData({ text, value: hexData });
811
815
  }
812
816
  }
813
817
  } catch (error) {
@@ -894,6 +898,11 @@ function useStorage({
894
898
  args: [storageKeyBytes2, operatorAddress, index]
895
899
  });
896
900
  const [text, data] = result;
901
+ if (!data || typeof data !== "string") {
902
+ setHistoricalData(void 0);
903
+ setHistoricalLoading(false);
904
+ return;
905
+ }
897
906
  setHistoricalData(formatData(text, data));
898
907
  } catch (error) {
899
908
  console.error(
@@ -906,7 +915,15 @@ function useStorage({
906
915
  }
907
916
  }
908
917
  fetchHistoricalVersion();
909
- }, [chainId, key, operatorAddress, index, enabled, isLatestVersion, outputAsString]);
918
+ }, [
919
+ chainId,
920
+ key,
921
+ operatorAddress,
922
+ index,
923
+ enabled,
924
+ isLatestVersion,
925
+ outputAsString
926
+ ]);
910
927
  if (!isLatestVersion) {
911
928
  return {
912
929
  data: historicalData,
@@ -921,7 +938,14 @@ function useStorage({
921
938
  error: routerHook.error || routerChunkError
922
939
  };
923
940
  }
924
- const formattedDirectData = latestData ? formatData(latestData[0], latestData[1]) : void 0;
941
+ const formattedDirectData = latestData ? (() => {
942
+ const result = latestData;
943
+ const [text, valueHex] = result;
944
+ if (!valueHex || typeof valueHex !== "string") {
945
+ return void 0;
946
+ }
947
+ return formatData(text, valueHex);
948
+ })() : void 0;
925
949
  return {
926
950
  data: formattedDirectData,
927
951
  isLoading: latestLoading,
@@ -963,9 +987,11 @@ function useStorageForOperatorAndKey({
963
987
  chainId,
964
988
  key,
965
989
  operatorAddress,
966
- keyFormat
990
+ keyFormat,
991
+ outputFormat = "hex"
967
992
  }) {
968
993
  const storageKeyBytes = key ? getStorageKeyBytes(key, keyFormat) : void 0;
994
+ const outputAsString = outputFormat === "string";
969
995
  const readContractArgs = {
970
996
  abi: STORAGE_CONTRACT.abi,
971
997
  address: STORAGE_CONTRACT.address,
@@ -978,7 +1004,13 @@ function useStorageForOperatorAndKey({
978
1004
  };
979
1005
  const { data, isLoading, error } = wagmi.useReadContract(readContractArgs);
980
1006
  return {
981
- data,
1007
+ data: data ? (() => {
1008
+ const [text, valueHex] = data;
1009
+ return {
1010
+ text,
1011
+ value: outputAsString ? viem.hexToString(valueHex) : valueHex
1012
+ };
1013
+ })() : void 0,
982
1014
  isLoading,
983
1015
  error
984
1016
  };
@@ -1188,11 +1220,9 @@ function useXmlStorage({
1188
1220
  index,
1189
1221
  keyFormat,
1190
1222
  useRouter,
1191
- returnFormat = "object",
1192
1223
  outputFormat = "hex"
1193
1224
  }) {
1194
1225
  const isPreviewMode = !!content;
1195
- const returnAsTuple = returnFormat === "tuple";
1196
1226
  const outputAsString = outputFormat === "string";
1197
1227
  const {
1198
1228
  data: metadata,
@@ -1215,8 +1245,8 @@ function useXmlStorage({
1215
1245
  const metadataString = react.useMemo(() => {
1216
1246
  if (skipXmlParsing) return "";
1217
1247
  if (isPreviewMode) return content || "";
1218
- if (!metadata?.[1]) return "";
1219
- return metadata[1];
1248
+ if (!metadata?.value) return "";
1249
+ return metadata.value;
1220
1250
  }, [skipXmlParsing, isPreviewMode, content, metadata]);
1221
1251
  react.useMemo(() => {
1222
1252
  if (!metadataString) return [];
@@ -1267,78 +1297,22 @@ function useXmlStorage({
1267
1297
  if (skipXmlParsing || !metadataString) return false;
1268
1298
  return containsXmlReferences(metadataString);
1269
1299
  }, [metadataString, skipXmlParsing]);
1270
- if (returnAsTuple) {
1271
- if (skipXmlParsing) {
1272
- if (isPreviewMode) {
1273
- const contentValue = content || "";
1274
- return {
1275
- data: contentValue ? outputAsString ? [metadata?.[0] || "", contentValue] : [
1276
- metadata?.[0] || "",
1277
- viem.stringToHex(contentValue)
1278
- ] : void 0,
1279
- isLoading: metadataLoading,
1280
- error: metadataError
1281
- };
1282
- } else {
1283
- const dataValue = metadata?.[1];
1284
- return {
1285
- data: dataValue ? outputAsString ? [metadata?.[0] || "", dataValue] : [
1286
- metadata?.[0] || "",
1287
- viem.stringToHex(dataValue)
1288
- ] : void 0,
1289
- isLoading: metadataLoading,
1290
- error: metadataError
1291
- };
1292
- }
1293
- }
1294
- if (isXml) {
1295
- if (!assembledData) {
1296
- return {
1297
- data: void 0,
1298
- isLoading: metadataLoading || chunksLoading,
1299
- error: metadataError || chunksError
1300
- };
1301
- }
1302
- const hexData = viem.stringToHex(assembledData);
1303
- return {
1304
- data: outputAsString ? [metadata?.[0] || "", assembledData] : [metadata?.[0] || "", hexData],
1305
- isLoading: metadataLoading || chunksLoading,
1306
- error: metadataError || chunksError
1307
- };
1308
- } else {
1309
- if (!metadata) {
1310
- return {
1311
- data: void 0,
1312
- isLoading: metadataLoading,
1313
- error: metadataError
1314
- };
1315
- }
1316
- const dataValue = metadata[1];
1317
- const returnValue = dataValue ? outputAsString ? [metadata[0], dataValue] : [
1318
- metadata[0],
1319
- viem.stringToHex(dataValue)
1320
- ] : void 0;
1321
- return {
1322
- data: returnValue,
1323
- isLoading: metadataLoading,
1324
- error: metadataError
1325
- };
1326
- }
1327
- }
1300
+ const formatValue = (value) => {
1301
+ if (!value) return "";
1302
+ return outputAsString ? value : viem.stringToHex(value);
1303
+ };
1328
1304
  if (skipXmlParsing) {
1329
1305
  return {
1330
- data: isPreviewMode ? content || "" : metadata?.[1] || "",
1331
- // metadata[1] is already a plain string
1332
- filename: metadata?.[0] || "",
1306
+ text: metadata?.text || "",
1307
+ value: isPreviewMode ? content || "" : formatValue(metadata?.value),
1333
1308
  isLoading: metadataLoading,
1334
1309
  error: metadataError,
1335
1310
  isXml: false
1336
1311
  };
1337
1312
  }
1338
1313
  return {
1339
- data: isXml ? assembledData : isPreviewMode ? content || "" : metadata?.[1] || "",
1340
- // metadata[1] is already a plain string
1341
- filename: metadata?.[0] || "",
1314
+ text: metadata?.text || "",
1315
+ value: isXml ? formatValue(assembledData) : isPreviewMode ? content || "" : formatValue(metadata?.value),
1342
1316
  isLoading: metadataLoading || isXml && chunksLoading,
1343
1317
  error: metadataError || chunksError,
1344
1318
  isXml
@@ -1375,16 +1349,13 @@ function useStorageFromRouter({
1375
1349
  }
1376
1350
  const [isChunkedStorage, text, data] = routerResult;
1377
1351
  if (!isChunkedStorage) {
1378
- setAssembledData([text, data]);
1352
+ setAssembledData({ text, value: data });
1379
1353
  return;
1380
1354
  }
1381
1355
  setIsChunkLoading(true);
1382
1356
  setChunkError(void 0);
1383
1357
  try {
1384
- const [chunkCount] = viem.decodeAbiParameters(
1385
- [{ type: "uint8" }],
1386
- data
1387
- );
1358
+ const [chunkCount] = viem.decodeAbiParameters([{ type: "uint8" }], data);
1388
1359
  if (chunkCount === 0) {
1389
1360
  setAssembledData(void 0);
1390
1361
  return;
@@ -1400,7 +1371,7 @@ function useStorageFromRouter({
1400
1371
  setAssembledData(void 0);
1401
1372
  } else {
1402
1373
  const hexData = viem.stringToHex(assembledString);
1403
- setAssembledData([text, hexData]);
1374
+ setAssembledData({ text, value: hexData });
1404
1375
  }
1405
1376
  } catch (error) {
1406
1377
  setChunkError(error);
@@ -1624,7 +1595,8 @@ var StorageClient = class {
1624
1595
  });
1625
1596
  try {
1626
1597
  const result = await actions.readContract(this.client, config);
1627
- return result;
1598
+ const [text, value] = result;
1599
+ return { text, value };
1628
1600
  } catch {
1629
1601
  return null;
1630
1602
  }
@@ -1642,7 +1614,8 @@ var StorageClient = class {
1642
1614
  });
1643
1615
  try {
1644
1616
  const result = await actions.readContract(this.client, config);
1645
- return result;
1617
+ const [text, value] = result;
1618
+ return { text, value };
1646
1619
  } catch {
1647
1620
  return null;
1648
1621
  }
@@ -1829,7 +1802,8 @@ var StorageClient = class {
1829
1802
  functionName: "getForOperatorAndKey",
1830
1803
  args: [params.operator, storageKeyBytes]
1831
1804
  });
1832
- return result;
1805
+ const [text, value] = result;
1806
+ return { text, value };
1833
1807
  } catch {
1834
1808
  return null;
1835
1809
  }
@@ -1869,8 +1843,9 @@ var StorageClient = class {
1869
1843
  if (!result) {
1870
1844
  throw new Error("StoredDataNotFound");
1871
1845
  }
1872
- [text, data] = result;
1873
- data = viem.hexToString(data);
1846
+ const resultObj = result;
1847
+ text = resultObj.text;
1848
+ data = viem.hexToString(resultObj.value);
1874
1849
  }
1875
1850
  } else {
1876
1851
  const result = await this.getViaRouter({
@@ -1940,7 +1915,9 @@ var StorageClient = class {
1940
1915
  throw new Error("Chunks array cannot be empty");
1941
1916
  }
1942
1917
  if (params.chunks && params.chunks.length > 255) {
1943
- throw new Error(`Too many chunks: ${params.chunks.length} exceeds maximum of 255`);
1918
+ throw new Error(
1919
+ `Too many chunks: ${params.chunks.length} exceeds maximum of 255`
1920
+ );
1944
1921
  }
1945
1922
  }
1946
1923
  /**
@@ -1952,7 +1929,9 @@ var StorageClient = class {
1952
1929
  const transactionConfigs = [];
1953
1930
  for (const xmlChunk of params.xmlChunks) {
1954
1931
  const chunks = chunkDataForStorage(xmlChunk);
1955
- const chunkedHash = core.keccak256HashString(xmlChunk + params.operatorAddress);
1932
+ const chunkedHash = core.keccak256HashString(
1933
+ xmlChunk + params.operatorAddress
1934
+ );
1956
1935
  chunkedStorageHashes.push(chunkedHash);
1957
1936
  const config = this.prepareChunkedPut({
1958
1937
  key: chunkedHash,
@@ -1977,7 +1956,10 @@ var StorageClient = class {
1977
1956
  */
1978
1957
  preparePut(params) {
1979
1958
  this.validateStorageParams({ key: params.key });
1980
- const keyBytes32 = getStorageKeyBytes(params.key, params.keyFormat);
1959
+ const keyBytes32 = getStorageKeyBytes(
1960
+ params.key,
1961
+ params.keyFormat
1962
+ );
1981
1963
  const valueHex = core.normalizeDataOrEmpty(params.value);
1982
1964
  return {
1983
1965
  to: STORAGE_CONTRACT.address,
@@ -1991,7 +1973,10 @@ var StorageClient = class {
1991
1973
  */
1992
1974
  prepareChunkedPut(params) {
1993
1975
  this.validateStorageParams({ key: params.key, chunks: params.chunks });
1994
- const keyBytes32 = getStorageKeyBytes(params.key, params.keyFormat);
1976
+ const keyBytes32 = getStorageKeyBytes(
1977
+ params.key,
1978
+ params.keyFormat
1979
+ );
1995
1980
  for (const chunk of params.chunks) {
1996
1981
  if (!chunk.startsWith("0x")) {
1997
1982
  throw new Error(`Invalid chunk format: ${chunk} must be a hex string`);
@@ -2013,7 +1998,10 @@ var StorageClient = class {
2013
1998
  }
2014
1999
  const bulkEntries = params.entries.map((entry) => {
2015
2000
  this.validateStorageParams({ key: entry.key });
2016
- const keyBytes32 = getStorageKeyBytes(entry.key, params.keyFormat);
2001
+ const keyBytes32 = getStorageKeyBytes(
2002
+ entry.key,
2003
+ params.keyFormat
2004
+ );
2017
2005
  const valueHex = core.normalizeDataOrEmpty(entry.value);
2018
2006
  return {
2019
2007
  key: keyBytes32,
@@ -2053,7 +2041,10 @@ var StorageClient = class {
2053
2041
  keyFormat: params.keyFormat
2054
2042
  });
2055
2043
  return {
2056
- transactionConfigs: [metadataConfig, ...chunkedResult.transactionConfigs],
2044
+ transactionConfigs: [
2045
+ metadataConfig,
2046
+ ...chunkedResult.transactionConfigs
2047
+ ],
2057
2048
  topLevelHash: result.topLevelHash,
2058
2049
  metadata: chunkedResult.xmlMetadata
2059
2050
  };