@snaha/swarm-id 0.0.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 (223) hide show
  1. package/README.md +431 -0
  2. package/dist/chunk/bmt.d.ts +17 -0
  3. package/dist/chunk/bmt.d.ts.map +1 -0
  4. package/dist/chunk/cac.d.ts +18 -0
  5. package/dist/chunk/cac.d.ts.map +1 -0
  6. package/dist/chunk/constants.d.ts +10 -0
  7. package/dist/chunk/constants.d.ts.map +1 -0
  8. package/dist/chunk/encrypted-cac.d.ts +48 -0
  9. package/dist/chunk/encrypted-cac.d.ts.map +1 -0
  10. package/dist/chunk/encryption.d.ts +86 -0
  11. package/dist/chunk/encryption.d.ts.map +1 -0
  12. package/dist/chunk/index.d.ts +6 -0
  13. package/dist/chunk/index.d.ts.map +1 -0
  14. package/dist/index.d.ts +46 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/proxy/act/act.d.ts +78 -0
  17. package/dist/proxy/act/act.d.ts.map +1 -0
  18. package/dist/proxy/act/crypto.d.ts +44 -0
  19. package/dist/proxy/act/crypto.d.ts.map +1 -0
  20. package/dist/proxy/act/grantee-list.d.ts +82 -0
  21. package/dist/proxy/act/grantee-list.d.ts.map +1 -0
  22. package/dist/proxy/act/history.d.ts +183 -0
  23. package/dist/proxy/act/history.d.ts.map +1 -0
  24. package/dist/proxy/act/index.d.ts +104 -0
  25. package/dist/proxy/act/index.d.ts.map +1 -0
  26. package/dist/proxy/chunking-encrypted.d.ts +14 -0
  27. package/dist/proxy/chunking-encrypted.d.ts.map +1 -0
  28. package/dist/proxy/chunking.d.ts +15 -0
  29. package/dist/proxy/chunking.d.ts.map +1 -0
  30. package/dist/proxy/download-data.d.ts +16 -0
  31. package/dist/proxy/download-data.d.ts.map +1 -0
  32. package/dist/proxy/feed-manifest.d.ts +62 -0
  33. package/dist/proxy/feed-manifest.d.ts.map +1 -0
  34. package/dist/proxy/feeds/epochs/async-finder.d.ts +77 -0
  35. package/dist/proxy/feeds/epochs/async-finder.d.ts.map +1 -0
  36. package/dist/proxy/feeds/epochs/epoch.d.ts +88 -0
  37. package/dist/proxy/feeds/epochs/epoch.d.ts.map +1 -0
  38. package/dist/proxy/feeds/epochs/finder.d.ts +67 -0
  39. package/dist/proxy/feeds/epochs/finder.d.ts.map +1 -0
  40. package/dist/proxy/feeds/epochs/index.d.ts +35 -0
  41. package/dist/proxy/feeds/epochs/index.d.ts.map +1 -0
  42. package/dist/proxy/feeds/epochs/test-utils.d.ts +93 -0
  43. package/dist/proxy/feeds/epochs/test-utils.d.ts.map +1 -0
  44. package/dist/proxy/feeds/epochs/types.d.ts +109 -0
  45. package/dist/proxy/feeds/epochs/types.d.ts.map +1 -0
  46. package/dist/proxy/feeds/epochs/updater.d.ts +68 -0
  47. package/dist/proxy/feeds/epochs/updater.d.ts.map +1 -0
  48. package/dist/proxy/feeds/epochs/utils.d.ts +22 -0
  49. package/dist/proxy/feeds/epochs/utils.d.ts.map +1 -0
  50. package/dist/proxy/feeds/index.d.ts +5 -0
  51. package/dist/proxy/feeds/index.d.ts.map +1 -0
  52. package/dist/proxy/feeds/sequence/async-finder.d.ts +14 -0
  53. package/dist/proxy/feeds/sequence/async-finder.d.ts.map +1 -0
  54. package/dist/proxy/feeds/sequence/finder.d.ts +17 -0
  55. package/dist/proxy/feeds/sequence/finder.d.ts.map +1 -0
  56. package/dist/proxy/feeds/sequence/index.d.ts +23 -0
  57. package/dist/proxy/feeds/sequence/index.d.ts.map +1 -0
  58. package/dist/proxy/feeds/sequence/types.d.ts +80 -0
  59. package/dist/proxy/feeds/sequence/types.d.ts.map +1 -0
  60. package/dist/proxy/feeds/sequence/updater.d.ts +26 -0
  61. package/dist/proxy/feeds/sequence/updater.d.ts.map +1 -0
  62. package/dist/proxy/index.d.ts +6 -0
  63. package/dist/proxy/index.d.ts.map +1 -0
  64. package/dist/proxy/manifest-builder.d.ts +183 -0
  65. package/dist/proxy/manifest-builder.d.ts.map +1 -0
  66. package/dist/proxy/mantaray-encrypted.d.ts +27 -0
  67. package/dist/proxy/mantaray-encrypted.d.ts.map +1 -0
  68. package/dist/proxy/mantaray.d.ts +26 -0
  69. package/dist/proxy/mantaray.d.ts.map +1 -0
  70. package/dist/proxy/types.d.ts +29 -0
  71. package/dist/proxy/types.d.ts.map +1 -0
  72. package/dist/proxy/upload-data.d.ts +17 -0
  73. package/dist/proxy/upload-data.d.ts.map +1 -0
  74. package/dist/proxy/upload-encrypted-data.d.ts +103 -0
  75. package/dist/proxy/upload-encrypted-data.d.ts.map +1 -0
  76. package/dist/schemas.d.ts +240 -0
  77. package/dist/schemas.d.ts.map +1 -0
  78. package/dist/storage/debounced-uploader.d.ts +62 -0
  79. package/dist/storage/debounced-uploader.d.ts.map +1 -0
  80. package/dist/storage/utilization-store.d.ts +108 -0
  81. package/dist/storage/utilization-store.d.ts.map +1 -0
  82. package/dist/swarm-id-auth.d.ts +74 -0
  83. package/dist/swarm-id-auth.d.ts.map +1 -0
  84. package/dist/swarm-id-auth.js +2 -0
  85. package/dist/swarm-id-auth.js.map +1 -0
  86. package/dist/swarm-id-client.d.ts +878 -0
  87. package/dist/swarm-id-client.d.ts.map +1 -0
  88. package/dist/swarm-id-client.js +2 -0
  89. package/dist/swarm-id-client.js.map +1 -0
  90. package/dist/swarm-id-proxy.d.ts +236 -0
  91. package/dist/swarm-id-proxy.d.ts.map +1 -0
  92. package/dist/swarm-id-proxy.js +2 -0
  93. package/dist/swarm-id-proxy.js.map +1 -0
  94. package/dist/swarm-id.esm.js +2 -0
  95. package/dist/swarm-id.esm.js.map +1 -0
  96. package/dist/swarm-id.umd.js +2 -0
  97. package/dist/swarm-id.umd.js.map +1 -0
  98. package/dist/sync/index.d.ts +9 -0
  99. package/dist/sync/index.d.ts.map +1 -0
  100. package/dist/sync/key-derivation.d.ts +25 -0
  101. package/dist/sync/key-derivation.d.ts.map +1 -0
  102. package/dist/sync/restore-account.d.ts +28 -0
  103. package/dist/sync/restore-account.d.ts.map +1 -0
  104. package/dist/sync/serialization.d.ts +16 -0
  105. package/dist/sync/serialization.d.ts.map +1 -0
  106. package/dist/sync/store-interfaces.d.ts +53 -0
  107. package/dist/sync/store-interfaces.d.ts.map +1 -0
  108. package/dist/sync/sync-account.d.ts +44 -0
  109. package/dist/sync/sync-account.d.ts.map +1 -0
  110. package/dist/sync/types.d.ts +13 -0
  111. package/dist/sync/types.d.ts.map +1 -0
  112. package/dist/test-fixtures.d.ts +17 -0
  113. package/dist/test-fixtures.d.ts.map +1 -0
  114. package/dist/types-BD_VkNn0.js +2 -0
  115. package/dist/types-BD_VkNn0.js.map +1 -0
  116. package/dist/types-lJCaT-50.js +2 -0
  117. package/dist/types-lJCaT-50.js.map +1 -0
  118. package/dist/types.d.ts +2157 -0
  119. package/dist/types.d.ts.map +1 -0
  120. package/dist/utils/account-payload.d.ts +94 -0
  121. package/dist/utils/account-payload.d.ts.map +1 -0
  122. package/dist/utils/account-state-snapshot.d.ts +38 -0
  123. package/dist/utils/account-state-snapshot.d.ts.map +1 -0
  124. package/dist/utils/backup-encryption.d.ts +127 -0
  125. package/dist/utils/backup-encryption.d.ts.map +1 -0
  126. package/dist/utils/batch-utilization.d.ts +432 -0
  127. package/dist/utils/batch-utilization.d.ts.map +1 -0
  128. package/dist/utils/constants.d.ts +11 -0
  129. package/dist/utils/constants.d.ts.map +1 -0
  130. package/dist/utils/hex.d.ts +17 -0
  131. package/dist/utils/hex.d.ts.map +1 -0
  132. package/dist/utils/key-derivation.d.ts +92 -0
  133. package/dist/utils/key-derivation.d.ts.map +1 -0
  134. package/dist/utils/storage-managers.d.ts +65 -0
  135. package/dist/utils/storage-managers.d.ts.map +1 -0
  136. package/dist/utils/swarm-id-export.d.ts +24 -0
  137. package/dist/utils/swarm-id-export.d.ts.map +1 -0
  138. package/dist/utils/ttl.d.ts +49 -0
  139. package/dist/utils/ttl.d.ts.map +1 -0
  140. package/dist/utils/url.d.ts +41 -0
  141. package/dist/utils/url.d.ts.map +1 -0
  142. package/dist/utils/versioned-storage.d.ts +131 -0
  143. package/dist/utils/versioned-storage.d.ts.map +1 -0
  144. package/package.json +78 -0
  145. package/src/chunk/bmt.test.ts +217 -0
  146. package/src/chunk/bmt.ts +57 -0
  147. package/src/chunk/cac.test.ts +214 -0
  148. package/src/chunk/cac.ts +65 -0
  149. package/src/chunk/constants.ts +18 -0
  150. package/src/chunk/encrypted-cac.test.ts +385 -0
  151. package/src/chunk/encrypted-cac.ts +131 -0
  152. package/src/chunk/encryption.test.ts +352 -0
  153. package/src/chunk/encryption.ts +300 -0
  154. package/src/chunk/index.ts +47 -0
  155. package/src/index.ts +430 -0
  156. package/src/proxy/act/act.test.ts +278 -0
  157. package/src/proxy/act/act.ts +158 -0
  158. package/src/proxy/act/bee-compat.test.ts +948 -0
  159. package/src/proxy/act/crypto.test.ts +436 -0
  160. package/src/proxy/act/crypto.ts +376 -0
  161. package/src/proxy/act/grantee-list.test.ts +393 -0
  162. package/src/proxy/act/grantee-list.ts +239 -0
  163. package/src/proxy/act/history.test.ts +360 -0
  164. package/src/proxy/act/history.ts +413 -0
  165. package/src/proxy/act/index.test.ts +748 -0
  166. package/src/proxy/act/index.ts +853 -0
  167. package/src/proxy/chunking-encrypted.ts +95 -0
  168. package/src/proxy/chunking.ts +65 -0
  169. package/src/proxy/download-data.ts +448 -0
  170. package/src/proxy/feed-manifest.ts +174 -0
  171. package/src/proxy/feeds/epochs/async-finder.ts +372 -0
  172. package/src/proxy/feeds/epochs/epoch.test.ts +249 -0
  173. package/src/proxy/feeds/epochs/epoch.ts +181 -0
  174. package/src/proxy/feeds/epochs/finder.ts +282 -0
  175. package/src/proxy/feeds/epochs/index.ts +73 -0
  176. package/src/proxy/feeds/epochs/integration.test.ts +1336 -0
  177. package/src/proxy/feeds/epochs/test-utils.ts +274 -0
  178. package/src/proxy/feeds/epochs/types.ts +128 -0
  179. package/src/proxy/feeds/epochs/updater.ts +192 -0
  180. package/src/proxy/feeds/epochs/utils.ts +62 -0
  181. package/src/proxy/feeds/index.ts +5 -0
  182. package/src/proxy/feeds/sequence/async-finder.ts +31 -0
  183. package/src/proxy/feeds/sequence/finder.ts +73 -0
  184. package/src/proxy/feeds/sequence/index.ts +54 -0
  185. package/src/proxy/feeds/sequence/integration.test.ts +966 -0
  186. package/src/proxy/feeds/sequence/types.ts +103 -0
  187. package/src/proxy/feeds/sequence/updater.ts +71 -0
  188. package/src/proxy/index.ts +5 -0
  189. package/src/proxy/manifest-builder.test.ts +427 -0
  190. package/src/proxy/manifest-builder.ts +679 -0
  191. package/src/proxy/mantaray-encrypted.ts +78 -0
  192. package/src/proxy/mantaray.ts +104 -0
  193. package/src/proxy/types.ts +32 -0
  194. package/src/proxy/upload-data.ts +189 -0
  195. package/src/proxy/upload-encrypted-data.ts +658 -0
  196. package/src/schemas.ts +299 -0
  197. package/src/storage/debounced-uploader.ts +192 -0
  198. package/src/storage/utilization-store.ts +397 -0
  199. package/src/swarm-id-client.test.ts +99 -0
  200. package/src/swarm-id-client.ts +3095 -0
  201. package/src/swarm-id-proxy.ts +3891 -0
  202. package/src/sync/index.ts +28 -0
  203. package/src/sync/restore-account.ts +90 -0
  204. package/src/sync/serialization.ts +39 -0
  205. package/src/sync/store-interfaces.ts +62 -0
  206. package/src/sync/sync-account.test.ts +302 -0
  207. package/src/sync/sync-account.ts +396 -0
  208. package/src/sync/types.ts +11 -0
  209. package/src/test-fixtures.ts +109 -0
  210. package/src/types.ts +1651 -0
  211. package/src/utils/account-state-snapshot.test.ts +595 -0
  212. package/src/utils/account-state-snapshot.ts +94 -0
  213. package/src/utils/backup-encryption.test.ts +442 -0
  214. package/src/utils/backup-encryption.ts +352 -0
  215. package/src/utils/batch-utilization.ts +1309 -0
  216. package/src/utils/constants.ts +20 -0
  217. package/src/utils/hex.ts +27 -0
  218. package/src/utils/key-derivation.ts +197 -0
  219. package/src/utils/storage-managers.ts +365 -0
  220. package/src/utils/ttl.ts +129 -0
  221. package/src/utils/url.test.ts +136 -0
  222. package/src/utils/url.ts +71 -0
  223. package/src/utils/versioned-storage.ts +323 -0
@@ -0,0 +1,78 @@
1
+ import type { MantarayNode } from "@ethersphere/bee-js"
2
+ import {
3
+ makeEncryptedContentAddressedChunk,
4
+ type EncryptedChunk,
5
+ } from "../chunk"
6
+ import { uint8ArrayToHex } from "../utils/hex"
7
+
8
+ /**
9
+ * Upload callback type for saveMantarayTreeRecursivelyEncrypted
10
+ *
11
+ * @param encryptedData - The encrypted chunk data to upload
12
+ * @param address - The 32-byte address of the encrypted chunk
13
+ * @param isRoot - Whether this is the root node
14
+ * @returns Upload result with optional tag UID
15
+ */
16
+ export type EncryptedUploadCallback = (
17
+ encryptedData: Uint8Array,
18
+ address: Uint8Array,
19
+ isRoot: boolean,
20
+ ) => Promise<{ tagUid?: number }>
21
+
22
+ /**
23
+ * Save a Mantaray tree with encryption by uploading bottom-up
24
+ *
25
+ * This mirrors saveMantarayTreeRecursively but encrypts each manifest node
26
+ * and creates 64-byte encrypted references (address + encryption key).
27
+ *
28
+ * @param node - Root Mantaray node to save
29
+ * @param uploadFn - Callback to upload each encrypted chunk
30
+ * @returns Root reference (128 hex chars = 64 bytes) and optional tag UID
31
+ */
32
+ export async function saveMantarayTreeRecursivelyEncrypted(
33
+ node: MantarayNode,
34
+ uploadFn: EncryptedUploadCallback,
35
+ ): Promise<{ rootReference: string; tagUid?: number }> {
36
+ async function saveRecursively(
37
+ current: MantarayNode,
38
+ isRoot: boolean,
39
+ ): Promise<{ tagUid?: number }> {
40
+ // Process children first (bottom-up)
41
+ for (const fork of current.forks.values()) {
42
+ await saveRecursively(fork.node, false)
43
+ }
44
+
45
+ // Marshal the current node
46
+ const data = await current.marshal()
47
+
48
+ // Encrypt the manifest chunk
49
+ const encryptedChunk: EncryptedChunk =
50
+ makeEncryptedContentAddressedChunk(data)
51
+
52
+ // DEBUG: Trace encryption key presence
53
+
54
+ // Upload the encrypted chunk data
55
+ const result = await uploadFn(
56
+ encryptedChunk.data,
57
+ encryptedChunk.address.toUint8Array(),
58
+ isRoot,
59
+ )
60
+
61
+ // Create 64-byte reference: address + encryption key
62
+ const encryptedRef = new Uint8Array(64)
63
+ encryptedRef.set(encryptedChunk.address.toUint8Array(), 0)
64
+ encryptedRef.set(encryptedChunk.encryptionKey, 32)
65
+
66
+ // Set the node's self address to the full 64-byte encrypted reference
67
+ current.selfAddress = encryptedRef
68
+
69
+ return result
70
+ }
71
+
72
+ const result = await saveRecursively(node, true)
73
+
74
+ return {
75
+ rootReference: uint8ArrayToHex(node.selfAddress!),
76
+ tagUid: result.tagUid,
77
+ }
78
+ }
@@ -0,0 +1,104 @@
1
+ import { MantarayNode } from "@ethersphere/bee-js"
2
+ import type { Bee, BeeRequestOptions } from "@ethersphere/bee-js"
3
+ import { hexToUint8Array, uint8ArrayToHex } from "../utils/hex"
4
+ import { downloadDataWithChunkAPI } from "./download-data"
5
+
6
+ /**
7
+ * Upload callback type for saveMantarayTreeRecursively
8
+ */
9
+ export type UploadCallback = (
10
+ data: Uint8Array,
11
+ isRoot: boolean,
12
+ ) => Promise<{ reference: string; tagUid?: number }>
13
+
14
+ /**
15
+ * Save a Mantaray tree by uploading bottom-up
16
+ *
17
+ * This mirrors MantarayNode.saveRecursively() but allows custom upload logic
18
+ * and uses Bee's returned references to avoid address mismatches.
19
+ */
20
+ export async function saveMantarayTreeRecursively(
21
+ node: MantarayNode,
22
+ uploadFn: UploadCallback,
23
+ ): Promise<{ rootReference: string; tagUid?: number }> {
24
+ async function saveRecursively(
25
+ current: MantarayNode,
26
+ isRoot: boolean,
27
+ ): Promise<{ reference: string; tagUid?: number }> {
28
+ for (const fork of current.forks.values()) {
29
+ await saveRecursively(fork.node, false)
30
+ }
31
+
32
+ const data = await current.marshal()
33
+ const result = await uploadFn(data, isRoot)
34
+ current.selfAddress = hexToUint8Array(result.reference)
35
+
36
+ return result
37
+ }
38
+
39
+ const result = await saveRecursively(node, true)
40
+
41
+ return {
42
+ rootReference: result.reference,
43
+ tagUid: result.tagUid,
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Load a Mantaray tree using only the chunk API.
49
+ *
50
+ * This avoids /bytes and supports encrypted references.
51
+ */
52
+ export async function loadMantarayTreeWithChunkAPI(
53
+ bee: Bee,
54
+ rootReference: string,
55
+ requestOptions?: BeeRequestOptions,
56
+ ): Promise<MantarayNode> {
57
+ const rootData = await downloadDataWithChunkAPI(
58
+ bee,
59
+ rootReference,
60
+ undefined,
61
+ undefined,
62
+ requestOptions,
63
+ )
64
+ const root = MantarayNode.unmarshalFromData(
65
+ rootData,
66
+ hexToUint8Array(rootReference),
67
+ )
68
+
69
+ async function loadRecursively(node: MantarayNode): Promise<void> {
70
+ for (const fork of node.forks.values()) {
71
+ if (!fork.node.selfAddress) {
72
+ throw new Error("Fork node selfAddress is not set")
73
+ }
74
+
75
+ const childRef = uint8ArrayToHex(fork.node.selfAddress)
76
+ const childData = await downloadDataWithChunkAPI(
77
+ bee,
78
+ childRef,
79
+ undefined,
80
+ undefined,
81
+ requestOptions,
82
+ )
83
+ const childNode = MantarayNode.unmarshalFromData(
84
+ childData,
85
+ fork.node.selfAddress,
86
+ )
87
+
88
+ fork.node.targetAddress = childNode.targetAddress
89
+ fork.node.forks = childNode.forks
90
+ fork.node.obfuscationKey = childNode.obfuscationKey
91
+ fork.node.path = fork.prefix
92
+ fork.node.parent = node
93
+
94
+ for (const nestedFork of fork.node.forks.values()) {
95
+ nestedFork.node.parent = fork.node
96
+ }
97
+
98
+ await loadRecursively(fork.node)
99
+ }
100
+ }
101
+
102
+ await loadRecursively(root)
103
+ return root
104
+ }
@@ -0,0 +1,32 @@
1
+ import type { Bee, Stamper } from "@ethersphere/bee-js"
2
+
3
+ /**
4
+ * Upload context shared across handlers
5
+ */
6
+ export interface UploadContext {
7
+ bee: Bee
8
+ stamper: Stamper
9
+ }
10
+
11
+ /**
12
+ * Upload progress information
13
+ */
14
+ export interface UploadProgress {
15
+ total: number // Total chunks to upload
16
+ processed: number // Chunks uploaded so far
17
+ }
18
+
19
+ /**
20
+ * Chunk reference (32-byte address)
21
+ */
22
+ export interface ChunkReference {
23
+ address: Uint8Array // 32-byte chunk address
24
+ }
25
+
26
+ /**
27
+ * Encrypted chunk reference (64-byte reference: address + encryption key)
28
+ */
29
+ export interface EncryptedChunkReference {
30
+ address: Uint8Array // 32-byte chunk address
31
+ key: Uint8Array // 32-byte encryption key
32
+ }
@@ -0,0 +1,189 @@
1
+ import { Reference } from "@ethersphere/bee-js"
2
+ import type {
3
+ Bee,
4
+ BeeRequestOptions,
5
+ Stamper,
6
+ UploadOptions,
7
+ UploadResult,
8
+ } from "@ethersphere/bee-js"
9
+ import { makeContentAddressedChunk, type ContentAddressedChunk } from "../chunk"
10
+ import { splitDataIntoChunks, buildMerkleTree } from "./chunking"
11
+ import type { UploadContext, UploadProgress, ChunkReference } from "./types"
12
+
13
+ /**
14
+ * Simple Uint8ArrayWriter implementation for ChunkAdapter
15
+ */
16
+ class SimpleUint8ArrayWriter {
17
+ cursor: number = 0
18
+ buffer: Uint8Array
19
+
20
+ constructor(buffer: Uint8Array) {
21
+ this.buffer = buffer
22
+ }
23
+
24
+ write(_reader: unknown): number {
25
+ throw new Error("SimpleUint8ArrayWriter.write() not implemented")
26
+ }
27
+
28
+ max(): number {
29
+ return this.buffer.length
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Adapter to convert bee-js Chunk to cafe-utility Chunk interface
35
+ * This allows the Stamper to work with content-addressed chunks
36
+ */
37
+ class ChunkAdapter {
38
+ span: bigint
39
+ writer: SimpleUint8ArrayWriter
40
+
41
+ constructor(private chunk: ContentAddressedChunk) {
42
+ this.span = chunk.span.toBigInt()
43
+ this.writer = new SimpleUint8ArrayWriter(chunk.data)
44
+ }
45
+
46
+ hash(): Uint8Array {
47
+ return this.chunk.address.toUint8Array()
48
+ }
49
+
50
+ build(): Uint8Array {
51
+ return this.chunk.data
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Upload data with client-side signing
57
+ * Handles chunking, merkle tree building, and progress reporting
58
+ */
59
+ export async function uploadDataWithSigning(
60
+ context: UploadContext,
61
+ data: Uint8Array,
62
+ options?: UploadOptions,
63
+ onProgress?: (progress: UploadProgress) => void,
64
+ requestOptions?: BeeRequestOptions,
65
+ ): Promise<{ reference: string; tagUid?: number }> {
66
+ const { bee, stamper } = context
67
+
68
+ // Create a tag for tracking upload progress (required for fast deferred uploads)
69
+ let tag: number | undefined = options?.tag
70
+ if (!tag) {
71
+ const tagResponse = await bee.createTag()
72
+ tag = tagResponse.uid
73
+ }
74
+
75
+ // Step 1: Split data into chunks
76
+ const chunkPayloads = splitDataIntoChunks(data)
77
+ let totalChunks = chunkPayloads.length
78
+ let processedChunks = 0
79
+
80
+ // Progress callback helper
81
+ const reportProgress = () => {
82
+ if (onProgress) {
83
+ onProgress({ total: totalChunks, processed: processedChunks })
84
+ }
85
+ }
86
+
87
+ // Step 2: Process leaf chunks
88
+ const chunkRefs: ChunkReference[] = []
89
+
90
+ // Merge tag into options for all chunk uploads
91
+ const uploadOptionsWithTag = { ...options, tag }
92
+
93
+ for (const payload of chunkPayloads) {
94
+ // Create content-addressed chunk
95
+ const chunk = makeContentAddressedChunk(payload)
96
+
97
+ // Store reference
98
+ chunkRefs.push({
99
+ address: chunk.address.toUint8Array(),
100
+ })
101
+
102
+ // Upload chunk with signing
103
+ await uploadSingleChunk(
104
+ bee,
105
+ stamper,
106
+ chunk,
107
+ uploadOptionsWithTag,
108
+ requestOptions,
109
+ )
110
+
111
+ processedChunks++
112
+ reportProgress()
113
+ }
114
+
115
+ // Step 3: Build merkle tree (if multiple chunks)
116
+ let rootReference: Reference
117
+
118
+ if (chunkRefs.length === 1) {
119
+ // Single chunk - use direct reference
120
+ rootReference = new Reference(chunkRefs[0].address)
121
+ } else {
122
+ // Multiple chunks - build tree
123
+
124
+ rootReference = await buildMerkleTree(
125
+ chunkRefs,
126
+ async (intermediateChunk) => {
127
+ await uploadSingleChunk(
128
+ bee,
129
+ stamper,
130
+ intermediateChunk,
131
+ uploadOptionsWithTag,
132
+ requestOptions,
133
+ )
134
+
135
+ // Count intermediate chunks in progress
136
+ totalChunks++
137
+ processedChunks++
138
+ reportProgress()
139
+ },
140
+ )
141
+ }
142
+
143
+ // Return result
144
+ return {
145
+ reference: rootReference.toHex(),
146
+ tagUid: tag,
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Upload a single chunk with optional signing
152
+ * Returns UploadResult with Bee's actual stored reference for verification
153
+ */
154
+ export async function uploadSingleChunk(
155
+ bee: Bee,
156
+ stamper: Stamper | undefined,
157
+ chunk: ContentAddressedChunk,
158
+ options?: UploadOptions,
159
+ requestOptions?: BeeRequestOptions,
160
+ ): Promise<UploadResult> {
161
+ // Use non-deferred mode for faster uploads (returns immediately)
162
+ // Note: pinning is incompatible with deferred mode, so disable it
163
+ const uploadOptions = { deferred: false, pin: false, ...options }
164
+
165
+ if (stamper) {
166
+ // Client-side signing - use adapter for cafe-utility Chunk interface
167
+ const chunkAdapter = new ChunkAdapter(chunk)
168
+ const envelope = stamper.stamp(chunkAdapter)
169
+ const result = await bee.uploadChunk(
170
+ envelope,
171
+ chunk.data,
172
+ uploadOptions,
173
+ requestOptions,
174
+ )
175
+
176
+ // Verify address match between locally computed and Bee's response
177
+ const localAddress = chunk.address.toHex()
178
+ const beeAddress = result.reference.toHex()
179
+ if (localAddress !== beeAddress) {
180
+ console.error(
181
+ `[ADDRESS MISMATCH] local=${localAddress} bee=${beeAddress}`,
182
+ )
183
+ }
184
+
185
+ return result
186
+ } else {
187
+ throw new Error("No stamper or batch ID available")
188
+ }
189
+ }