@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.
- package/README.md +431 -0
- package/dist/chunk/bmt.d.ts +17 -0
- package/dist/chunk/bmt.d.ts.map +1 -0
- package/dist/chunk/cac.d.ts +18 -0
- package/dist/chunk/cac.d.ts.map +1 -0
- package/dist/chunk/constants.d.ts +10 -0
- package/dist/chunk/constants.d.ts.map +1 -0
- package/dist/chunk/encrypted-cac.d.ts +48 -0
- package/dist/chunk/encrypted-cac.d.ts.map +1 -0
- package/dist/chunk/encryption.d.ts +86 -0
- package/dist/chunk/encryption.d.ts.map +1 -0
- package/dist/chunk/index.d.ts +6 -0
- package/dist/chunk/index.d.ts.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/proxy/act/act.d.ts +78 -0
- package/dist/proxy/act/act.d.ts.map +1 -0
- package/dist/proxy/act/crypto.d.ts +44 -0
- package/dist/proxy/act/crypto.d.ts.map +1 -0
- package/dist/proxy/act/grantee-list.d.ts +82 -0
- package/dist/proxy/act/grantee-list.d.ts.map +1 -0
- package/dist/proxy/act/history.d.ts +183 -0
- package/dist/proxy/act/history.d.ts.map +1 -0
- package/dist/proxy/act/index.d.ts +104 -0
- package/dist/proxy/act/index.d.ts.map +1 -0
- package/dist/proxy/chunking-encrypted.d.ts +14 -0
- package/dist/proxy/chunking-encrypted.d.ts.map +1 -0
- package/dist/proxy/chunking.d.ts +15 -0
- package/dist/proxy/chunking.d.ts.map +1 -0
- package/dist/proxy/download-data.d.ts +16 -0
- package/dist/proxy/download-data.d.ts.map +1 -0
- package/dist/proxy/feed-manifest.d.ts +62 -0
- package/dist/proxy/feed-manifest.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/async-finder.d.ts +77 -0
- package/dist/proxy/feeds/epochs/async-finder.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/epoch.d.ts +88 -0
- package/dist/proxy/feeds/epochs/epoch.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/finder.d.ts +67 -0
- package/dist/proxy/feeds/epochs/finder.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/index.d.ts +35 -0
- package/dist/proxy/feeds/epochs/index.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/test-utils.d.ts +93 -0
- package/dist/proxy/feeds/epochs/test-utils.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/types.d.ts +109 -0
- package/dist/proxy/feeds/epochs/types.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/updater.d.ts +68 -0
- package/dist/proxy/feeds/epochs/updater.d.ts.map +1 -0
- package/dist/proxy/feeds/epochs/utils.d.ts +22 -0
- package/dist/proxy/feeds/epochs/utils.d.ts.map +1 -0
- package/dist/proxy/feeds/index.d.ts +5 -0
- package/dist/proxy/feeds/index.d.ts.map +1 -0
- package/dist/proxy/feeds/sequence/async-finder.d.ts +14 -0
- package/dist/proxy/feeds/sequence/async-finder.d.ts.map +1 -0
- package/dist/proxy/feeds/sequence/finder.d.ts +17 -0
- package/dist/proxy/feeds/sequence/finder.d.ts.map +1 -0
- package/dist/proxy/feeds/sequence/index.d.ts +23 -0
- package/dist/proxy/feeds/sequence/index.d.ts.map +1 -0
- package/dist/proxy/feeds/sequence/types.d.ts +80 -0
- package/dist/proxy/feeds/sequence/types.d.ts.map +1 -0
- package/dist/proxy/feeds/sequence/updater.d.ts +26 -0
- package/dist/proxy/feeds/sequence/updater.d.ts.map +1 -0
- package/dist/proxy/index.d.ts +6 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/manifest-builder.d.ts +183 -0
- package/dist/proxy/manifest-builder.d.ts.map +1 -0
- package/dist/proxy/mantaray-encrypted.d.ts +27 -0
- package/dist/proxy/mantaray-encrypted.d.ts.map +1 -0
- package/dist/proxy/mantaray.d.ts +26 -0
- package/dist/proxy/mantaray.d.ts.map +1 -0
- package/dist/proxy/types.d.ts +29 -0
- package/dist/proxy/types.d.ts.map +1 -0
- package/dist/proxy/upload-data.d.ts +17 -0
- package/dist/proxy/upload-data.d.ts.map +1 -0
- package/dist/proxy/upload-encrypted-data.d.ts +103 -0
- package/dist/proxy/upload-encrypted-data.d.ts.map +1 -0
- package/dist/schemas.d.ts +240 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/storage/debounced-uploader.d.ts +62 -0
- package/dist/storage/debounced-uploader.d.ts.map +1 -0
- package/dist/storage/utilization-store.d.ts +108 -0
- package/dist/storage/utilization-store.d.ts.map +1 -0
- package/dist/swarm-id-auth.d.ts +74 -0
- package/dist/swarm-id-auth.d.ts.map +1 -0
- package/dist/swarm-id-auth.js +2 -0
- package/dist/swarm-id-auth.js.map +1 -0
- package/dist/swarm-id-client.d.ts +878 -0
- package/dist/swarm-id-client.d.ts.map +1 -0
- package/dist/swarm-id-client.js +2 -0
- package/dist/swarm-id-client.js.map +1 -0
- package/dist/swarm-id-proxy.d.ts +236 -0
- package/dist/swarm-id-proxy.d.ts.map +1 -0
- package/dist/swarm-id-proxy.js +2 -0
- package/dist/swarm-id-proxy.js.map +1 -0
- package/dist/swarm-id.esm.js +2 -0
- package/dist/swarm-id.esm.js.map +1 -0
- package/dist/swarm-id.umd.js +2 -0
- package/dist/swarm-id.umd.js.map +1 -0
- package/dist/sync/index.d.ts +9 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/key-derivation.d.ts +25 -0
- package/dist/sync/key-derivation.d.ts.map +1 -0
- package/dist/sync/restore-account.d.ts +28 -0
- package/dist/sync/restore-account.d.ts.map +1 -0
- package/dist/sync/serialization.d.ts +16 -0
- package/dist/sync/serialization.d.ts.map +1 -0
- package/dist/sync/store-interfaces.d.ts +53 -0
- package/dist/sync/store-interfaces.d.ts.map +1 -0
- package/dist/sync/sync-account.d.ts +44 -0
- package/dist/sync/sync-account.d.ts.map +1 -0
- package/dist/sync/types.d.ts +13 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/test-fixtures.d.ts +17 -0
- package/dist/test-fixtures.d.ts.map +1 -0
- package/dist/types-BD_VkNn0.js +2 -0
- package/dist/types-BD_VkNn0.js.map +1 -0
- package/dist/types-lJCaT-50.js +2 -0
- package/dist/types-lJCaT-50.js.map +1 -0
- package/dist/types.d.ts +2157 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/account-payload.d.ts +94 -0
- package/dist/utils/account-payload.d.ts.map +1 -0
- package/dist/utils/account-state-snapshot.d.ts +38 -0
- package/dist/utils/account-state-snapshot.d.ts.map +1 -0
- package/dist/utils/backup-encryption.d.ts +127 -0
- package/dist/utils/backup-encryption.d.ts.map +1 -0
- package/dist/utils/batch-utilization.d.ts +432 -0
- package/dist/utils/batch-utilization.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +11 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/hex.d.ts +17 -0
- package/dist/utils/hex.d.ts.map +1 -0
- package/dist/utils/key-derivation.d.ts +92 -0
- package/dist/utils/key-derivation.d.ts.map +1 -0
- package/dist/utils/storage-managers.d.ts +65 -0
- package/dist/utils/storage-managers.d.ts.map +1 -0
- package/dist/utils/swarm-id-export.d.ts +24 -0
- package/dist/utils/swarm-id-export.d.ts.map +1 -0
- package/dist/utils/ttl.d.ts +49 -0
- package/dist/utils/ttl.d.ts.map +1 -0
- package/dist/utils/url.d.ts +41 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/versioned-storage.d.ts +131 -0
- package/dist/utils/versioned-storage.d.ts.map +1 -0
- package/package.json +78 -0
- package/src/chunk/bmt.test.ts +217 -0
- package/src/chunk/bmt.ts +57 -0
- package/src/chunk/cac.test.ts +214 -0
- package/src/chunk/cac.ts +65 -0
- package/src/chunk/constants.ts +18 -0
- package/src/chunk/encrypted-cac.test.ts +385 -0
- package/src/chunk/encrypted-cac.ts +131 -0
- package/src/chunk/encryption.test.ts +352 -0
- package/src/chunk/encryption.ts +300 -0
- package/src/chunk/index.ts +47 -0
- package/src/index.ts +430 -0
- package/src/proxy/act/act.test.ts +278 -0
- package/src/proxy/act/act.ts +158 -0
- package/src/proxy/act/bee-compat.test.ts +948 -0
- package/src/proxy/act/crypto.test.ts +436 -0
- package/src/proxy/act/crypto.ts +376 -0
- package/src/proxy/act/grantee-list.test.ts +393 -0
- package/src/proxy/act/grantee-list.ts +239 -0
- package/src/proxy/act/history.test.ts +360 -0
- package/src/proxy/act/history.ts +413 -0
- package/src/proxy/act/index.test.ts +748 -0
- package/src/proxy/act/index.ts +853 -0
- package/src/proxy/chunking-encrypted.ts +95 -0
- package/src/proxy/chunking.ts +65 -0
- package/src/proxy/download-data.ts +448 -0
- package/src/proxy/feed-manifest.ts +174 -0
- package/src/proxy/feeds/epochs/async-finder.ts +372 -0
- package/src/proxy/feeds/epochs/epoch.test.ts +249 -0
- package/src/proxy/feeds/epochs/epoch.ts +181 -0
- package/src/proxy/feeds/epochs/finder.ts +282 -0
- package/src/proxy/feeds/epochs/index.ts +73 -0
- package/src/proxy/feeds/epochs/integration.test.ts +1336 -0
- package/src/proxy/feeds/epochs/test-utils.ts +274 -0
- package/src/proxy/feeds/epochs/types.ts +128 -0
- package/src/proxy/feeds/epochs/updater.ts +192 -0
- package/src/proxy/feeds/epochs/utils.ts +62 -0
- package/src/proxy/feeds/index.ts +5 -0
- package/src/proxy/feeds/sequence/async-finder.ts +31 -0
- package/src/proxy/feeds/sequence/finder.ts +73 -0
- package/src/proxy/feeds/sequence/index.ts +54 -0
- package/src/proxy/feeds/sequence/integration.test.ts +966 -0
- package/src/proxy/feeds/sequence/types.ts +103 -0
- package/src/proxy/feeds/sequence/updater.ts +71 -0
- package/src/proxy/index.ts +5 -0
- package/src/proxy/manifest-builder.test.ts +427 -0
- package/src/proxy/manifest-builder.ts +679 -0
- package/src/proxy/mantaray-encrypted.ts +78 -0
- package/src/proxy/mantaray.ts +104 -0
- package/src/proxy/types.ts +32 -0
- package/src/proxy/upload-data.ts +189 -0
- package/src/proxy/upload-encrypted-data.ts +658 -0
- package/src/schemas.ts +299 -0
- package/src/storage/debounced-uploader.ts +192 -0
- package/src/storage/utilization-store.ts +397 -0
- package/src/swarm-id-client.test.ts +99 -0
- package/src/swarm-id-client.ts +3095 -0
- package/src/swarm-id-proxy.ts +3891 -0
- package/src/sync/index.ts +28 -0
- package/src/sync/restore-account.ts +90 -0
- package/src/sync/serialization.ts +39 -0
- package/src/sync/store-interfaces.ts +62 -0
- package/src/sync/sync-account.test.ts +302 -0
- package/src/sync/sync-account.ts +396 -0
- package/src/sync/types.ts +11 -0
- package/src/test-fixtures.ts +109 -0
- package/src/types.ts +1651 -0
- package/src/utils/account-state-snapshot.test.ts +595 -0
- package/src/utils/account-state-snapshot.ts +94 -0
- package/src/utils/backup-encryption.test.ts +442 -0
- package/src/utils/backup-encryption.ts +352 -0
- package/src/utils/batch-utilization.ts +1309 -0
- package/src/utils/constants.ts +20 -0
- package/src/utils/hex.ts +27 -0
- package/src/utils/key-derivation.ts +197 -0
- package/src/utils/storage-managers.ts +365 -0
- package/src/utils/ttl.ts +129 -0
- package/src/utils/url.test.ts +136 -0
- package/src/utils/url.ts +71 -0
- 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
|
+
}
|