@storagehub-sdk/msp-client 0.1.0 → 0.1.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.
@@ -1,6 +1,6 @@
1
- import type { Bucket, DownloadOptions, DownloadResult, FileInfo, FileListResponse, GetFilesOptions, HealthStatus, InfoResponse, NonceResponse, StatsResponse, UploadOptions, UploadReceipt, ValueProp, VerifyResponse } from './types.js';
2
- import type { HttpClientConfig } from '@storagehub-sdk/core';
3
- import { FileMetadata } from '@storagehub-sdk/core';
1
+ import type { Bucket, DownloadOptions, DownloadResult, FileInfo, FileListResponse, GetFilesOptions, HealthStatus, InfoResponse, NonceResponse, PaymentStreamsResponse, StatsResponse, UploadOptions, UploadReceipt, ValueProp, VerifyResponse } from "./types.js";
2
+ import type { HttpClientConfig } from "@storagehub-sdk/core";
3
+ import { FileMetadata } from "@storagehub-sdk/core";
4
4
  export declare class MspClient {
5
5
  readonly config: HttpClientConfig;
6
6
  private readonly http;
@@ -22,6 +22,10 @@ export declare class MspClient {
22
22
  getValuePropositions(options?: {
23
23
  signal?: AbortSignal;
24
24
  }): Promise<ValueProp[]>;
25
+ /** Get payment streams for current authenticated user */
26
+ getPaymentStreams(options?: {
27
+ signal?: AbortSignal;
28
+ }): Promise<PaymentStreamsResponse>;
25
29
  /** Request a SIWE-style nonce message for the given address and chainId */
26
30
  getNonce(address: string, chainId: number, options?: {
27
31
  signal?: AbortSignal;
@@ -1,2 +1,2 @@
1
- import{FileMetadata as B,FileTrie as F,HttpClient as U,initWasm as m}from"@storagehub-sdk/core";var b=class w{config;http;token;constructor(e,t){this.config=e,this.http=t}static async connect(e){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let t=new U({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}});return new w(e,t)}getHealth(e){return this.http.get("/health",{...e?.signal!==void 0&&{signal:e.signal}})}getInfo(e){return this.http.get("/info",{...e?.signal!==void 0&&{signal:e.signal}})}getStats(e){return this.http.get("/stats",{...e?.signal!==void 0&&{signal:e.signal}})}getValuePropositions(e){return this.http.get("/value-props",{...e?.signal!==void 0&&{signal:e.signal}})}getNonce(e,t,n){return this.http.post("/auth/nonce",{body:{address:e,chainId:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}verify(e,t,n){return this.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}setToken(e){this.token=e}withAuth(e){return this.token?{...e??{},Authorization:`Bearer ${this.token}`}:e}listBuckets(e){let t=this.withAuth();return this.http.get("/buckets",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getBucket(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{}})}getFiles(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}/files`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:t.path.replace(/^\/+/,"")}}:{}})}getFileInfo(e,t,n){let a=this.withAuth(),o=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`;return this.http.get(o,{...a?{headers:a}:{},...n?.signal?{signal:n.signal}:{}}).then(s=>({...s,uploadedAt:new Date(s.uploadedAt)}))}async uploadFile(e,t,n,a,o,s){await m();let r=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,i=this.withAuth(),l=await this.coerceToFormPart(n),d=l.size,u=await this.computeFileFingerprint(l),p=await this.formFileMetadata(a,e,o,u,BigInt(d)),c=await this.computeFileKey(p),g=this.hexToBytes(t);if(c.length!==g.length||!c.every((R,A)=>R===g[A]))throw new Error(`Computed file key ${c.toString()} does not match provided file key ${g.toString()}`);let f=p.encode(),h=new FormData,y=new Blob([new Uint8Array(f)],{type:"application/octet-stream"});return h.append("file_metadata",y,"file_metadata"),h.append("file",l,"file"),await this.http.put(r,i?{body:h,headers:i}:{body:h})}async coerceToFormPart(e){if(typeof Blob<"u"&&e instanceof Blob)return e;if(e instanceof Uint8Array)return new Blob([e.buffer]);if(typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer)return new Blob([e]);if(e instanceof ReadableStream){let t=e.getReader(),n=[],a=0;try{for(;;){let{done:r,value:i}=await t.read();if(r)break;i&&(n.push(i),a+=i.length)}}finally{t.releaseLock()}let o=new Uint8Array(a),s=0;for(let r of n)o.set(r,s),s+=r.length;return new Blob([o],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async computeFileFingerprint(e){let t=new F,n=new Uint8Array(await e.arrayBuffer()),a=1024,o=0;for(;o<n.length;){let s=Math.min(o+a,n.length),r=n.slice(o,s);t.push_chunk(r),o=s}return t.get_root()}async formFileMetadata(e,t,n,a,o){let s=this.hexToBytes(e),r=this.hexToBytes(t),i=new TextEncoder().encode(n);return await m(),new B(s,r,i,o,a)}hexToBytes(e){if(!e)throw new Error("hex string cannot be empty");let t=e.startsWith("0x")?e.slice(2):e;if(t.length%2!==0)throw new Error("hex string must have an even number of characters");if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("hex string contains invalid characters");return new Uint8Array(t.match(/.{2}/g)?.map(n=>Number.parseInt(n,16))||[])}async computeFileKey(e){return await m(),e.getFileKey()}async downloadByKey(e,t){let n=`/download/${encodeURIComponent(e)}`,a={Accept:"*/*"};if(t?.range){let{start:p,end:c}=t.range,g=`bytes=${p}-${c??""}`;a.Range=g}let o=this.withAuth(a),s=await this.http.getRaw(n,{...o?{headers:o}:{},...t?.signal?{signal:t.signal}:{}});if(!s.body)throw new Error("Response body is null - unable to create stream");let r=s.headers.get("content-type"),i=s.headers.get("content-range"),l=s.headers.get("content-length"),d=l!==null?Number(l):void 0,u=typeof d=="number"&&Number.isFinite(d)?d:null;return{stream:s.body,status:s.status,contentType:r,contentRange:i,contentLength:u}}async downloadByLocation(e,t,n){let o=t.replace(/^\/+/,"").split("/").map(encodeURIComponent).join("/"),s=`/buckets/${encodeURIComponent(e)}/download/path/${o}`,r={Accept:"*/*"};if(n?.range){let{start:f,end:h}=n.range,y=`bytes=${f}-${h??""}`;r.Range=y}let i=this.withAuth(r),l=await this.http.getRaw(s,{...i?{headers:i}:{},...n?.signal?{signal:n.signal}:{}});if(!l.body)throw new Error("Response body is null - unable to create stream");let d=l.headers.get("content-type"),u=l.headers.get("content-range"),p=l.headers.get("content-length"),c=p!==null?Number(p):void 0,g=typeof c=="number"&&Number.isFinite(c)?c:null;return{stream:l.body,status:l.status,contentType:d,contentRange:u,contentLength:g}}};export{b as MspClient};
1
+ import{FileMetadata as B,FileTrie as F,HttpClient as P,initWasm as f}from"@storagehub-sdk/core";var b=class w{config;http;token;constructor(e,t){this.config=e,this.http=t}static async connect(e){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let t=new P({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}});return new w(e,t)}getHealth(e){return this.http.get("/health",{...e?.signal!==void 0&&{signal:e.signal}})}getInfo(e){return this.http.get("/info",{...e?.signal!==void 0&&{signal:e.signal}})}getStats(e){return this.http.get("/stats",{...e?.signal!==void 0&&{signal:e.signal}})}getValuePropositions(e){return this.http.get("/value-props",{...e?.signal!==void 0&&{signal:e.signal}})}getPaymentStreams(e){let t=this.withAuth();return this.http.get("/payment_streams",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getNonce(e,t,n){return this.http.post("/auth/nonce",{body:{address:e,chainId:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}verify(e,t,n){return this.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}setToken(e){this.token=e}withAuth(e){return this.token?{...e??{},Authorization:`Bearer ${this.token}`}:e}listBuckets(e){let t=this.withAuth();return this.http.get("/buckets",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getBucket(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{}})}getFiles(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}/files`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:t.path.replace(/^\/+/,"")}}:{}})}getFileInfo(e,t,n){let a=this.withAuth(),r=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`;return this.http.get(r,{...a?{headers:a}:{},...n?.signal?{signal:n.signal}:{}}).then(s=>({...s,uploadedAt:new Date(s.uploadedAt)}))}async uploadFile(e,t,n,a,r,s){await f();let o=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,i=this.withAuth(),l=await this.coerceToFormPart(n),p=l.size,u=await this.computeFileFingerprint(l),d=await this.formFileMetadata(a,e,r,u,BigInt(p)),c=await this.computeFileKey(d),g=this.hexToBytes(t);if(c.length!==g.length||!c.every((R,A)=>R===g[A]))throw new Error(`Computed file key ${c.toString()} does not match provided file key ${g.toString()}`);let m=d.encode(),h=new FormData,y=new Blob([new Uint8Array(m)],{type:"application/octet-stream"});return h.append("file_metadata",y,"file_metadata"),h.append("file",l,"file"),await this.http.put(o,i?{body:h,headers:i}:{body:h})}async coerceToFormPart(e){if(typeof Blob<"u"&&e instanceof Blob)return e;if(e instanceof Uint8Array)return new Blob([e.buffer]);if(typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer)return new Blob([e]);if(e instanceof ReadableStream){let t=e.getReader(),n=[],a=0;try{for(;;){let{done:o,value:i}=await t.read();if(o)break;i&&(n.push(i),a+=i.length)}}finally{t.releaseLock()}let r=new Uint8Array(a),s=0;for(let o of n)r.set(o,s),s+=o.length;return new Blob([r],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async computeFileFingerprint(e){let t=new F,n=new Uint8Array(await e.arrayBuffer()),a=1024,r=0;for(;r<n.length;){let s=Math.min(r+a,n.length),o=n.slice(r,s);t.push_chunk(o),r=s}return t.get_root()}async formFileMetadata(e,t,n,a,r){let s=this.hexToBytes(e),o=this.hexToBytes(t),i=new TextEncoder().encode(n);return await f(),new B(s,o,i,r,a)}hexToBytes(e){if(!e)throw new Error("hex string cannot be empty");let t=e.startsWith("0x")?e.slice(2):e;if(t.length%2!==0)throw new Error("hex string must have an even number of characters");if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("hex string contains invalid characters");return new Uint8Array(t.match(/.{2}/g)?.map(n=>Number.parseInt(n,16))||[])}async computeFileKey(e){return await f(),e.getFileKey()}async downloadByKey(e,t){let n=`/download/${encodeURIComponent(e)}`,a={Accept:"*/*"};if(t?.range){let{start:d,end:c}=t.range,g=`bytes=${d}-${c??""}`;a.Range=g}let r=this.withAuth(a),s=await this.http.getRaw(n,{...r?{headers:r}:{},...t?.signal?{signal:t.signal}:{}});if(!s.body)throw new Error("Response body is null - unable to create stream");let o=s.headers.get("content-type"),i=s.headers.get("content-range"),l=s.headers.get("content-length"),p=l!==null?Number(l):void 0,u=typeof p=="number"&&Number.isFinite(p)?p:null;return{stream:s.body,status:s.status,contentType:o,contentRange:i,contentLength:u}}async downloadByLocation(e,t,n){let r=t.replace(/^\/+/,"").split("/").map(encodeURIComponent).join("/"),s=`/buckets/${encodeURIComponent(e)}/download/path/${r}`,o={Accept:"*/*"};if(n?.range){let{start:m,end:h}=n.range,y=`bytes=${m}-${h??""}`;o.Range=y}let i=this.withAuth(o),l=await this.http.getRaw(s,{...i?{headers:i}:{},...n?.signal?{signal:n.signal}:{}});if(!l.body)throw new Error("Response body is null - unable to create stream");let p=l.headers.get("content-type"),u=l.headers.get("content-range"),d=l.headers.get("content-length"),c=d!==null?Number(d):void 0,g=typeof c=="number"&&Number.isFinite(c)?c:null;return{stream:l.body,status:l.status,contentType:p,contentRange:u,contentLength:g}}};export{b as MspClient};
2
2
  //# sourceMappingURL=index.browser.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/MspClient.ts"],
4
- "sourcesContent": ["import type {\n Bucket,\n DownloadOptions,\n DownloadResult,\n FileInfo,\n FileListResponse,\n GetFilesOptions,\n HealthStatus,\n InfoResponse,\n NonceResponse,\n StatsResponse,\n UploadOptions,\n UploadReceipt,\n ValueProp,\n VerifyResponse,\n} from './types.js';\nimport type { HttpClientConfig } from '@storagehub-sdk/core';\nimport { FileMetadata, FileTrie, HttpClient, initWasm } from '@storagehub-sdk/core';\n\nexport class MspClient {\n public readonly config: HttpClientConfig;\n private readonly http: HttpClient;\n public token?: string;\n\n private constructor(config: HttpClientConfig, http: HttpClient) {\n this.config = config;\n this.http = http;\n }\n\n static async connect(config: HttpClientConfig): Promise<MspClient> {\n if (!config?.baseUrl) throw new Error('MspClient.connect: baseUrl is required');\n\n const http = new HttpClient({\n baseUrl: config.baseUrl,\n ...(config.timeoutMs !== undefined && { timeoutMs: config.timeoutMs }),\n ...(config.defaultHeaders !== undefined && { defaultHeaders: config.defaultHeaders }),\n ...(config.fetchImpl !== undefined && { fetchImpl: config.fetchImpl }),\n });\n\n return new MspClient(config, http);\n }\n\n getHealth(options?: { signal?: AbortSignal }): Promise<HealthStatus> {\n return this.http.get<HealthStatus>('/health', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get general MSP information */\n getInfo(options?: { signal?: AbortSignal }): Promise<InfoResponse> {\n return this.http.get<InfoResponse>('/info', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get MSP statistics */\n getStats(options?: { signal?: AbortSignal }): Promise<StatsResponse> {\n return this.http.get<StatsResponse>('/stats', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(options?: { signal?: AbortSignal }): Promise<ValueProp[]> {\n return this.http.get<ValueProp[]>('/value-props', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n // Auth endpoints:\n\n /** Request a SIWE-style nonce message for the given address and chainId */\n getNonce(\n address: string,\n chainId: number,\n options?: { signal?: AbortSignal },\n ): Promise<NonceResponse> {\n return this.http.post<NonceResponse>('/auth/nonce', {\n body: { address, chainId },\n headers: { 'Content-Type': 'application/json' },\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Verify signed message and receive JWT token */\n verify(\n message: string,\n signature: string,\n options?: { signal?: AbortSignal },\n ): Promise<VerifyResponse> {\n return this.http.post<VerifyResponse>('/auth/verify', {\n body: { message, signature },\n headers: { 'Content-Type': 'application/json' },\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Store token to be sent on subsequent protected requests */\n setToken(token: string): void {\n this.token = token;\n }\n\n /** Merge Authorization header when token is present */\n private withAuth(headers?: Record<string, string>): Record<string, string> | undefined {\n if (!this.token) return headers;\n return { ...(headers ?? {}), Authorization: `Bearer ${this.token}` };\n }\n\n // Bucket endpoints:\n\n /** List all buckets for the current authenticateduser */\n listBuckets(options?: { signal?: AbortSignal }): Promise<Bucket[]> {\n const headers = this.withAuth();\n return this.http.get<Bucket[]>('/buckets', {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n getBucket(bucketId: string, options?: { signal?: AbortSignal }): Promise<Bucket> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n return this.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Gets the list of files and folders under the specified path for a bucket. If no path is provided, it returns the files and folders found at root. */\n getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n return this.http.get<FileListResponse>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: options.path.replace(/^\\/+/, '') } } : {}),\n });\n }\n\n /** Get metadata for a file in a bucket by fileKey */\n getFileInfo(\n bucketId: string,\n fileKey: string,\n options?: { signal?: AbortSignal },\n ): Promise<FileInfo> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n type FileInfoWire = Omit<FileInfo, 'uploadedAt'> & { uploadedAt: string };\n return this.http\n .get<FileInfoWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n })\n .then((wire): FileInfo => ({ ...wire, uploadedAt: new Date(wire.uploadedAt) }));\n }\n\n // File endpoints:\n\n /**\n * Upload a file to a bucket with a specific key.\n *\n * Always uses multipart/form-data upload with both file data and encoded FileMetadata.\n * The file data is loaded into memory to create the multipart request.\n *\n */\n async uploadFile(\n bucketId: string,\n fileKey: string,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n owner: string,\n location: string,\n _options?: UploadOptions,\n ): Promise<UploadReceipt> {\n void _options;\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = this.withAuth();\n\n // Convert the file to a blob and get its size\n const fileBlob = await this.coerceToFormPart(file);\n const fileSize = fileBlob.size;\n\n // Compute the fingerprint first\n // TODO: We should instead use FileManager here and use its `getFingerprint` method.\n // This would allow us to remove the `initWasm` call at the top and to stream the file\n // instead of loading it into memory as a blob.\n const fingerprint = await this.computeFileFingerprint(fileBlob);\n\n // Create the FileMetadata instance\n const metadata = await this.formFileMetadata(\n owner,\n bucketId,\n location,\n fingerprint,\n BigInt(fileSize),\n );\n\n // Compute the file key and ensure it matches the provided file key\n const computedFileKey = await this.computeFileKey(metadata);\n const expectedFileKeyBytes = this.hexToBytes(fileKey);\n if (\n computedFileKey.length !== expectedFileKeyBytes.length ||\n !computedFileKey.every((byte, index) => byte === expectedFileKeyBytes[index])\n ) {\n throw new Error(\n `Computed file key ${computedFileKey.toString()} does not match provided file key ${expectedFileKeyBytes.toString()}`,\n );\n }\n\n // Encode the file metadata\n const encodedMetadata = metadata.encode();\n\n // Create the multipart form with both the file and its metadata\n const form = new FormData();\n const fileMetadataBlob = new Blob([new Uint8Array(encodedMetadata)], {\n type: 'application/octet-stream',\n });\n form.append('file_metadata', fileMetadataBlob, 'file_metadata');\n form.append('file', fileBlob, 'file');\n\n const res = await this.http.put<UploadReceipt>(\n backendPath,\n authHeaders\n ? { body: form as unknown as BodyInit, headers: authHeaders }\n : { body: form as unknown as BodyInit },\n );\n return res;\n }\n\n private async coerceToFormPart(\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n ): Promise<Blob> {\n if (typeof Blob !== 'undefined' && file instanceof Blob) return file;\n if (file instanceof Uint8Array) return new Blob([file.buffer as ArrayBuffer]);\n if (typeof ArrayBuffer !== 'undefined' && file instanceof ArrayBuffer) return new Blob([file]);\n\n // Handle ReadableStream by reading it into memory\n if (file instanceof ReadableStream) {\n const reader = file.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n chunks.push(value);\n totalLength += value.length;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine all chunks into a single Uint8Array\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return new Blob([combined], { type: 'application/octet-stream' });\n }\n\n return new Blob([file as BlobPart], { type: 'application/octet-stream' });\n }\n\n private async computeFileFingerprint(fileBlob: Blob): Promise<Uint8Array> {\n const trie = new FileTrie();\n const fileBytes = new Uint8Array(await fileBlob.arrayBuffer());\n\n // Process the file in 1KB chunks (matching CHUNK_SIZE from constants)\n const CHUNK_SIZE = 1024;\n let offset = 0;\n\n while (offset < fileBytes.length) {\n const end = Math.min(offset + CHUNK_SIZE, fileBytes.length);\n const chunk = fileBytes.slice(offset, end);\n trie.push_chunk(chunk);\n offset = end;\n }\n\n return trie.get_root();\n }\n\n async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint,\n ): Promise<FileMetadata> {\n const ownerBytes = this.hexToBytes(owner);\n const bucketIdBytes = this.hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n hexToBytes(hex: string): Uint8Array {\n if (!hex) {\n throw new Error('hex string cannot be empty');\n }\n\n const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error('hex string must have an even number of characters');\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('hex string contains invalid characters');\n }\n\n return new Uint8Array(cleanHex.match(/.{2}/g)?.map((byte) => Number.parseInt(byte, 16)) || []);\n }\n\n async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n\n /** Download a file by key. */\n async downloadByKey(fileKey: string, options?: DownloadOptions): Promise<DownloadResult> {\n const path = `/download/${encodeURIComponent(fileKey)}`;\n const baseHeaders: Record<string, string> = { Accept: '*/*' };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? ''}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n\n if (!res.body) {\n throw new Error('Response body is null - unable to create stream');\n }\n\n const contentType = res.headers.get('content-type');\n const contentRange = res.headers.get('content-range');\n const contentLengthHeader = res.headers.get('content-length');\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === 'number' && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength,\n };\n }\n\n /** Download a file by its location path under a bucket. */\n async downloadByLocation(\n bucketId: string,\n filePath: string,\n options?: DownloadOptions,\n ): Promise<DownloadResult> {\n const normalized = filePath.replace(/^\\/+/, '');\n const encodedPath = normalized.split('/').map(encodeURIComponent).join('/');\n const path = `/buckets/${encodeURIComponent(bucketId)}/download/path/${encodedPath}`;\n const baseHeaders: Record<string, string> = { Accept: '*/*' };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? ''}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n\n if (!res.body) {\n throw new Error('Response body is null - unable to create stream');\n }\n\n const contentType = res.headers.get('content-type');\n const contentRange = res.headers.get('content-range');\n const contentLengthHeader = res.headers.get('content-length');\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === 'number' && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength,\n };\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["FileMetadata", "FileTrie", "HttpClient", "initWasm", "MspClient", "_MspClient", "config", "http", "options", "address", "chainId", "message", "signature", "token", "headers", "bucketId", "path", "fileKey", "wire", "file", "owner", "location", "_options", "backendPath", "authHeaders", "fileBlob", "fileSize", "fingerprint", "metadata", "computedFileKey", "expectedFileKeyBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "trie", "fileBytes", "CHUNK_SIZE", "end", "size", "ownerBytes", "bucketIdBytes", "locationBytes", "hex", "cleanHex", "fileMetadata", "baseHeaders", "start", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "filePath", "encodedPath"]
4
+ "sourcesContent": ["import type {\n Bucket,\n DownloadOptions,\n DownloadResult,\n FileInfo,\n FileListResponse,\n GetFilesOptions,\n HealthStatus,\n InfoResponse,\n NonceResponse,\n PaymentStreamsResponse,\n StatsResponse,\n UploadOptions,\n UploadReceipt,\n ValueProp,\n VerifyResponse\n} from \"./types.js\";\nimport type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { FileMetadata, FileTrie, HttpClient, initWasm } from \"@storagehub-sdk/core\";\n\nexport class MspClient {\n public readonly config: HttpClientConfig;\n private readonly http: HttpClient;\n public token?: string;\n\n private constructor(config: HttpClientConfig, http: HttpClient) {\n this.config = config;\n this.http = http;\n }\n\n static async connect(config: HttpClientConfig): Promise<MspClient> {\n if (!config?.baseUrl) throw new Error(\"MspClient.connect: baseUrl is required\");\n\n const http = new HttpClient({\n baseUrl: config.baseUrl,\n ...(config.timeoutMs !== undefined && { timeoutMs: config.timeoutMs }),\n ...(config.defaultHeaders !== undefined && {\n defaultHeaders: config.defaultHeaders\n }),\n ...(config.fetchImpl !== undefined && { fetchImpl: config.fetchImpl })\n });\n\n return new MspClient(config, http);\n }\n\n getHealth(options?: { signal?: AbortSignal }): Promise<HealthStatus> {\n return this.http.get<HealthStatus>(\"/health\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get general MSP information */\n getInfo(options?: { signal?: AbortSignal }): Promise<InfoResponse> {\n return this.http.get<InfoResponse>(\"/info\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get MSP statistics */\n getStats(options?: { signal?: AbortSignal }): Promise<StatsResponse> {\n return this.http.get<StatsResponse>(\"/stats\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(options?: { signal?: AbortSignal }): Promise<ValueProp[]> {\n return this.http.get<ValueProp[]>(\"/value-props\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get payment streams for current authenticated user */\n getPaymentStreams(options?: { signal?: AbortSignal }): Promise<PaymentStreamsResponse> {\n const headers = this.withAuth();\n return this.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n // Auth endpoints:\n /** Request a SIWE-style nonce message for the given address and chainId */\n getNonce(\n address: string,\n chainId: number,\n options?: { signal?: AbortSignal }\n ): Promise<NonceResponse> {\n return this.http.post<NonceResponse>(\"/auth/nonce\", {\n body: { address, chainId },\n headers: { \"Content-Type\": \"application/json\" },\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Verify signed message and receive JWT token */\n verify(\n message: string,\n signature: string,\n options?: { signal?: AbortSignal }\n ): Promise<VerifyResponse> {\n return this.http.post<VerifyResponse>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Store token to be sent on subsequent protected requests */\n setToken(token: string): void {\n this.token = token;\n }\n\n /** Merge Authorization header when token is present */\n private withAuth(headers?: Record<string, string>): Record<string, string> | undefined {\n if (!this.token) return headers;\n return { ...(headers ?? {}), Authorization: `Bearer ${this.token}` };\n }\n\n // Bucket endpoints:\n /** List all buckets for the current authenticateduser */\n listBuckets(options?: { signal?: AbortSignal }): Promise<Bucket[]> {\n const headers = this.withAuth();\n return this.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n getBucket(bucketId: string, options?: { signal?: AbortSignal }): Promise<Bucket> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n return this.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n /** Gets the list of files and folders under the specified path for a bucket. If no path is provided, it returns the files and folders found at root. */\n getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n return this.http.get<FileListResponse>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: options.path.replace(/^\\/+/, \"\") } } : {})\n });\n }\n\n /** Get metadata for a file in a bucket by fileKey */\n getFileInfo(\n bucketId: string,\n fileKey: string,\n options?: { signal?: AbortSignal }\n ): Promise<FileInfo> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n type FileInfoWire = Omit<FileInfo, \"uploadedAt\"> & { uploadedAt: string };\n return this.http\n .get<FileInfoWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n })\n .then(\n (wire): FileInfo => ({\n ...wire,\n uploadedAt: new Date(wire.uploadedAt)\n })\n );\n }\n\n // File endpoints:\n /**\n * Upload a file to a bucket with a specific key.\n *\n * Always uses multipart/form-data upload with both file data and encoded FileMetadata.\n * The file data is loaded into memory to create the multipart request.\n *\n */\n async uploadFile(\n bucketId: string,\n fileKey: string,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n owner: string,\n location: string,\n _options?: UploadOptions\n ): Promise<UploadReceipt> {\n void _options;\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = this.withAuth();\n\n // Convert the file to a blob and get its size\n const fileBlob = await this.coerceToFormPart(file);\n const fileSize = fileBlob.size;\n\n // Compute the fingerprint first\n // TODO: We should instead use FileManager here and use its `getFingerprint` method.\n // This would allow us to remove the `initWasm` call at the top and to stream the file\n // instead of loading it into memory as a blob.\n const fingerprint = await this.computeFileFingerprint(fileBlob);\n\n // Create the FileMetadata instance\n const metadata = await this.formFileMetadata(\n owner,\n bucketId,\n location,\n fingerprint,\n BigInt(fileSize)\n );\n\n // Compute the file key and ensure it matches the provided file key\n const computedFileKey = await this.computeFileKey(metadata);\n const expectedFileKeyBytes = this.hexToBytes(fileKey);\n if (\n computedFileKey.length !== expectedFileKeyBytes.length ||\n !computedFileKey.every((byte, index) => byte === expectedFileKeyBytes[index])\n ) {\n throw new Error(\n `Computed file key ${computedFileKey.toString()} does not match provided file key ${expectedFileKeyBytes.toString()}`\n );\n }\n\n // Encode the file metadata\n const encodedMetadata = metadata.encode();\n\n // Create the multipart form with both the file and its metadata\n const form = new FormData();\n const fileMetadataBlob = new Blob([new Uint8Array(encodedMetadata)], {\n type: \"application/octet-stream\"\n });\n form.append(\"file_metadata\", fileMetadataBlob, \"file_metadata\");\n form.append(\"file\", fileBlob, \"file\");\n\n const res = await this.http.put<UploadReceipt>(\n backendPath,\n authHeaders\n ? { body: form as unknown as BodyInit, headers: authHeaders }\n : { body: form as unknown as BodyInit }\n );\n return res;\n }\n\n private async coerceToFormPart(\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown\n ): Promise<Blob> {\n if (typeof Blob !== \"undefined\" && file instanceof Blob) return file;\n if (file instanceof Uint8Array) return new Blob([file.buffer as ArrayBuffer]);\n if (typeof ArrayBuffer !== \"undefined\" && file instanceof ArrayBuffer) return new Blob([file]);\n\n // Handle ReadableStream by reading it into memory\n if (file instanceof ReadableStream) {\n const reader = file.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n chunks.push(value);\n totalLength += value.length;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine all chunks into a single Uint8Array\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return new Blob([combined], { type: \"application/octet-stream\" });\n }\n\n return new Blob([file as BlobPart], { type: \"application/octet-stream\" });\n }\n\n private async computeFileFingerprint(fileBlob: Blob): Promise<Uint8Array> {\n const trie = new FileTrie();\n const fileBytes = new Uint8Array(await fileBlob.arrayBuffer());\n\n // Process the file in 1KB chunks (matching CHUNK_SIZE from constants)\n const CHUNK_SIZE = 1024;\n let offset = 0;\n\n while (offset < fileBytes.length) {\n const end = Math.min(offset + CHUNK_SIZE, fileBytes.length);\n const chunk = fileBytes.slice(offset, end);\n trie.push_chunk(chunk);\n offset = end;\n }\n\n return trie.get_root();\n }\n\n async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = this.hexToBytes(owner);\n const bucketIdBytes = this.hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n hexToBytes(hex: string): Uint8Array {\n if (!hex) {\n throw new Error(\"hex string cannot be empty\");\n }\n\n const cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error(\"hex string must have an even number of characters\");\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error(\"hex string contains invalid characters\");\n }\n\n return new Uint8Array(cleanHex.match(/.{2}/g)?.map((byte) => Number.parseInt(byte, 16)) || []);\n }\n\n async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n\n /** Download a file by key. */\n async downloadByKey(fileKey: string, options?: DownloadOptions): Promise<DownloadResult> {\n const path = `/download/${encodeURIComponent(fileKey)}`;\n const baseHeaders: Record<string, string> = { Accept: \"*/*\" };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? \"\"}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n\n if (!res.body) {\n throw new Error(\"Response body is null - unable to create stream\");\n }\n\n const contentType = res.headers.get(\"content-type\");\n const contentRange = res.headers.get(\"content-range\");\n const contentLengthHeader = res.headers.get(\"content-length\");\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === \"number\" && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength\n };\n }\n\n /** Download a file by its location path under a bucket. */\n async downloadByLocation(\n bucketId: string,\n filePath: string,\n options?: DownloadOptions\n ): Promise<DownloadResult> {\n const normalized = filePath.replace(/^\\/+/, \"\");\n const encodedPath = normalized.split(\"/\").map(encodeURIComponent).join(\"/\");\n const path = `/buckets/${encodeURIComponent(bucketId)}/download/path/${encodedPath}`;\n const baseHeaders: Record<string, string> = { Accept: \"*/*\" };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? \"\"}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n\n if (!res.body) {\n throw new Error(\"Response body is null - unable to create stream\");\n }\n\n const contentType = res.headers.get(\"content-type\");\n const contentRange = res.headers.get(\"content-range\");\n const contentLengthHeader = res.headers.get(\"content-length\");\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === \"number\" && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["FileMetadata", "FileTrie", "HttpClient", "initWasm", "MspClient", "_MspClient", "config", "http", "options", "headers", "address", "chainId", "message", "signature", "token", "bucketId", "path", "fileKey", "wire", "file", "owner", "location", "_options", "backendPath", "authHeaders", "fileBlob", "fileSize", "fingerprint", "metadata", "computedFileKey", "expectedFileKeyBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "trie", "fileBytes", "CHUNK_SIZE", "end", "size", "ownerBytes", "bucketIdBytes", "locationBytes", "hex", "cleanHex", "fileMetadata", "baseHeaders", "start", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "filePath", "encodedPath"]
7
7
  }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { MspClient } from './MspClient.js';
2
- export type { Bucket, Capacity, DownloadOptions, DownloadResult, FileEntry, FileInfo, FileListResponse, HealthStatus, InfoResponse, NonceResponse, StatsResponse, UploadOptions, UploadReceipt, ValueProp, VerifyResponse, } from './types.js';
1
+ export { MspClient } from "./MspClient.js";
2
+ export type { Bucket, Capacity, DownloadOptions, DownloadResult, FileTree, FileInfo, FileListResponse, HealthStatus, InfoResponse, NonceResponse, PaymentStreamInfo, PaymentStreamsResponse, StatsResponse, UploadOptions, UploadReceipt, ValueProp, VerifyResponse } from "./types.js";
@@ -1,2 +1,2 @@
1
- import{FileMetadata as B,FileTrie as F,HttpClient as U,initWasm as m}from"@storagehub-sdk/core";var b=class w{config;http;token;constructor(e,t){this.config=e,this.http=t}static async connect(e){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let t=new U({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}});return new w(e,t)}getHealth(e){return this.http.get("/health",{...e?.signal!==void 0&&{signal:e.signal}})}getInfo(e){return this.http.get("/info",{...e?.signal!==void 0&&{signal:e.signal}})}getStats(e){return this.http.get("/stats",{...e?.signal!==void 0&&{signal:e.signal}})}getValuePropositions(e){return this.http.get("/value-props",{...e?.signal!==void 0&&{signal:e.signal}})}getNonce(e,t,n){return this.http.post("/auth/nonce",{body:{address:e,chainId:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}verify(e,t,n){return this.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}setToken(e){this.token=e}withAuth(e){return this.token?{...e??{},Authorization:`Bearer ${this.token}`}:e}listBuckets(e){let t=this.withAuth();return this.http.get("/buckets",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getBucket(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{}})}getFiles(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}/files`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:t.path.replace(/^\/+/,"")}}:{}})}getFileInfo(e,t,n){let a=this.withAuth(),o=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`;return this.http.get(o,{...a?{headers:a}:{},...n?.signal?{signal:n.signal}:{}}).then(s=>({...s,uploadedAt:new Date(s.uploadedAt)}))}async uploadFile(e,t,n,a,o,s){await m();let r=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,i=this.withAuth(),l=await this.coerceToFormPart(n),d=l.size,u=await this.computeFileFingerprint(l),p=await this.formFileMetadata(a,e,o,u,BigInt(d)),c=await this.computeFileKey(p),g=this.hexToBytes(t);if(c.length!==g.length||!c.every((R,A)=>R===g[A]))throw new Error(`Computed file key ${c.toString()} does not match provided file key ${g.toString()}`);let f=p.encode(),h=new FormData,y=new Blob([new Uint8Array(f)],{type:"application/octet-stream"});return h.append("file_metadata",y,"file_metadata"),h.append("file",l,"file"),await this.http.put(r,i?{body:h,headers:i}:{body:h})}async coerceToFormPart(e){if(typeof Blob<"u"&&e instanceof Blob)return e;if(e instanceof Uint8Array)return new Blob([e.buffer]);if(typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer)return new Blob([e]);if(e instanceof ReadableStream){let t=e.getReader(),n=[],a=0;try{for(;;){let{done:r,value:i}=await t.read();if(r)break;i&&(n.push(i),a+=i.length)}}finally{t.releaseLock()}let o=new Uint8Array(a),s=0;for(let r of n)o.set(r,s),s+=r.length;return new Blob([o],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async computeFileFingerprint(e){let t=new F,n=new Uint8Array(await e.arrayBuffer()),a=1024,o=0;for(;o<n.length;){let s=Math.min(o+a,n.length),r=n.slice(o,s);t.push_chunk(r),o=s}return t.get_root()}async formFileMetadata(e,t,n,a,o){let s=this.hexToBytes(e),r=this.hexToBytes(t),i=new TextEncoder().encode(n);return await m(),new B(s,r,i,o,a)}hexToBytes(e){if(!e)throw new Error("hex string cannot be empty");let t=e.startsWith("0x")?e.slice(2):e;if(t.length%2!==0)throw new Error("hex string must have an even number of characters");if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("hex string contains invalid characters");return new Uint8Array(t.match(/.{2}/g)?.map(n=>Number.parseInt(n,16))||[])}async computeFileKey(e){return await m(),e.getFileKey()}async downloadByKey(e,t){let n=`/download/${encodeURIComponent(e)}`,a={Accept:"*/*"};if(t?.range){let{start:p,end:c}=t.range,g=`bytes=${p}-${c??""}`;a.Range=g}let o=this.withAuth(a),s=await this.http.getRaw(n,{...o?{headers:o}:{},...t?.signal?{signal:t.signal}:{}});if(!s.body)throw new Error("Response body is null - unable to create stream");let r=s.headers.get("content-type"),i=s.headers.get("content-range"),l=s.headers.get("content-length"),d=l!==null?Number(l):void 0,u=typeof d=="number"&&Number.isFinite(d)?d:null;return{stream:s.body,status:s.status,contentType:r,contentRange:i,contentLength:u}}async downloadByLocation(e,t,n){let o=t.replace(/^\/+/,"").split("/").map(encodeURIComponent).join("/"),s=`/buckets/${encodeURIComponent(e)}/download/path/${o}`,r={Accept:"*/*"};if(n?.range){let{start:f,end:h}=n.range,y=`bytes=${f}-${h??""}`;r.Range=y}let i=this.withAuth(r),l=await this.http.getRaw(s,{...i?{headers:i}:{},...n?.signal?{signal:n.signal}:{}});if(!l.body)throw new Error("Response body is null - unable to create stream");let d=l.headers.get("content-type"),u=l.headers.get("content-range"),p=l.headers.get("content-length"),c=p!==null?Number(p):void 0,g=typeof c=="number"&&Number.isFinite(c)?c:null;return{stream:l.body,status:l.status,contentType:d,contentRange:u,contentLength:g}}};export{b as MspClient};
1
+ import{FileMetadata as B,FileTrie as F,HttpClient as P,initWasm as f}from"@storagehub-sdk/core";var b=class w{config;http;token;constructor(e,t){this.config=e,this.http=t}static async connect(e){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let t=new P({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}});return new w(e,t)}getHealth(e){return this.http.get("/health",{...e?.signal!==void 0&&{signal:e.signal}})}getInfo(e){return this.http.get("/info",{...e?.signal!==void 0&&{signal:e.signal}})}getStats(e){return this.http.get("/stats",{...e?.signal!==void 0&&{signal:e.signal}})}getValuePropositions(e){return this.http.get("/value-props",{...e?.signal!==void 0&&{signal:e.signal}})}getPaymentStreams(e){let t=this.withAuth();return this.http.get("/payment_streams",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getNonce(e,t,n){return this.http.post("/auth/nonce",{body:{address:e,chainId:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}verify(e,t,n){return this.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?.signal!==void 0&&{signal:n.signal}})}setToken(e){this.token=e}withAuth(e){return this.token?{...e??{},Authorization:`Bearer ${this.token}`}:e}listBuckets(e){let t=this.withAuth();return this.http.get("/buckets",{...t?{headers:t}:{},...e?.signal?{signal:e.signal}:{}})}getBucket(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{}})}getFiles(e,t){let n=this.withAuth(),a=`/buckets/${encodeURIComponent(e)}/files`;return this.http.get(a,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:t.path.replace(/^\/+/,"")}}:{}})}getFileInfo(e,t,n){let a=this.withAuth(),r=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`;return this.http.get(r,{...a?{headers:a}:{},...n?.signal?{signal:n.signal}:{}}).then(s=>({...s,uploadedAt:new Date(s.uploadedAt)}))}async uploadFile(e,t,n,a,r,s){await f();let o=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,i=this.withAuth(),l=await this.coerceToFormPart(n),p=l.size,u=await this.computeFileFingerprint(l),d=await this.formFileMetadata(a,e,r,u,BigInt(p)),c=await this.computeFileKey(d),g=this.hexToBytes(t);if(c.length!==g.length||!c.every((R,A)=>R===g[A]))throw new Error(`Computed file key ${c.toString()} does not match provided file key ${g.toString()}`);let m=d.encode(),h=new FormData,y=new Blob([new Uint8Array(m)],{type:"application/octet-stream"});return h.append("file_metadata",y,"file_metadata"),h.append("file",l,"file"),await this.http.put(o,i?{body:h,headers:i}:{body:h})}async coerceToFormPart(e){if(typeof Blob<"u"&&e instanceof Blob)return e;if(e instanceof Uint8Array)return new Blob([e.buffer]);if(typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer)return new Blob([e]);if(e instanceof ReadableStream){let t=e.getReader(),n=[],a=0;try{for(;;){let{done:o,value:i}=await t.read();if(o)break;i&&(n.push(i),a+=i.length)}}finally{t.releaseLock()}let r=new Uint8Array(a),s=0;for(let o of n)r.set(o,s),s+=o.length;return new Blob([r],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async computeFileFingerprint(e){let t=new F,n=new Uint8Array(await e.arrayBuffer()),a=1024,r=0;for(;r<n.length;){let s=Math.min(r+a,n.length),o=n.slice(r,s);t.push_chunk(o),r=s}return t.get_root()}async formFileMetadata(e,t,n,a,r){let s=this.hexToBytes(e),o=this.hexToBytes(t),i=new TextEncoder().encode(n);return await f(),new B(s,o,i,r,a)}hexToBytes(e){if(!e)throw new Error("hex string cannot be empty");let t=e.startsWith("0x")?e.slice(2):e;if(t.length%2!==0)throw new Error("hex string must have an even number of characters");if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("hex string contains invalid characters");return new Uint8Array(t.match(/.{2}/g)?.map(n=>Number.parseInt(n,16))||[])}async computeFileKey(e){return await f(),e.getFileKey()}async downloadByKey(e,t){let n=`/download/${encodeURIComponent(e)}`,a={Accept:"*/*"};if(t?.range){let{start:d,end:c}=t.range,g=`bytes=${d}-${c??""}`;a.Range=g}let r=this.withAuth(a),s=await this.http.getRaw(n,{...r?{headers:r}:{},...t?.signal?{signal:t.signal}:{}});if(!s.body)throw new Error("Response body is null - unable to create stream");let o=s.headers.get("content-type"),i=s.headers.get("content-range"),l=s.headers.get("content-length"),p=l!==null?Number(l):void 0,u=typeof p=="number"&&Number.isFinite(p)?p:null;return{stream:s.body,status:s.status,contentType:o,contentRange:i,contentLength:u}}async downloadByLocation(e,t,n){let r=t.replace(/^\/+/,"").split("/").map(encodeURIComponent).join("/"),s=`/buckets/${encodeURIComponent(e)}/download/path/${r}`,o={Accept:"*/*"};if(n?.range){let{start:m,end:h}=n.range,y=`bytes=${m}-${h??""}`;o.Range=y}let i=this.withAuth(o),l=await this.http.getRaw(s,{...i?{headers:i}:{},...n?.signal?{signal:n.signal}:{}});if(!l.body)throw new Error("Response body is null - unable to create stream");let p=l.headers.get("content-type"),u=l.headers.get("content-range"),d=l.headers.get("content-length"),c=d!==null?Number(d):void 0,g=typeof c=="number"&&Number.isFinite(c)?c:null;return{stream:l.body,status:l.status,contentType:p,contentRange:u,contentLength:g}}};export{b as MspClient};
2
2
  //# sourceMappingURL=index.node.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/MspClient.ts"],
4
- "sourcesContent": ["import type {\n Bucket,\n DownloadOptions,\n DownloadResult,\n FileInfo,\n FileListResponse,\n GetFilesOptions,\n HealthStatus,\n InfoResponse,\n NonceResponse,\n StatsResponse,\n UploadOptions,\n UploadReceipt,\n ValueProp,\n VerifyResponse,\n} from './types.js';\nimport type { HttpClientConfig } from '@storagehub-sdk/core';\nimport { FileMetadata, FileTrie, HttpClient, initWasm } from '@storagehub-sdk/core';\n\nexport class MspClient {\n public readonly config: HttpClientConfig;\n private readonly http: HttpClient;\n public token?: string;\n\n private constructor(config: HttpClientConfig, http: HttpClient) {\n this.config = config;\n this.http = http;\n }\n\n static async connect(config: HttpClientConfig): Promise<MspClient> {\n if (!config?.baseUrl) throw new Error('MspClient.connect: baseUrl is required');\n\n const http = new HttpClient({\n baseUrl: config.baseUrl,\n ...(config.timeoutMs !== undefined && { timeoutMs: config.timeoutMs }),\n ...(config.defaultHeaders !== undefined && { defaultHeaders: config.defaultHeaders }),\n ...(config.fetchImpl !== undefined && { fetchImpl: config.fetchImpl }),\n });\n\n return new MspClient(config, http);\n }\n\n getHealth(options?: { signal?: AbortSignal }): Promise<HealthStatus> {\n return this.http.get<HealthStatus>('/health', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get general MSP information */\n getInfo(options?: { signal?: AbortSignal }): Promise<InfoResponse> {\n return this.http.get<InfoResponse>('/info', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get MSP statistics */\n getStats(options?: { signal?: AbortSignal }): Promise<StatsResponse> {\n return this.http.get<StatsResponse>('/stats', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(options?: { signal?: AbortSignal }): Promise<ValueProp[]> {\n return this.http.get<ValueProp[]>('/value-props', {\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n // Auth endpoints:\n\n /** Request a SIWE-style nonce message for the given address and chainId */\n getNonce(\n address: string,\n chainId: number,\n options?: { signal?: AbortSignal },\n ): Promise<NonceResponse> {\n return this.http.post<NonceResponse>('/auth/nonce', {\n body: { address, chainId },\n headers: { 'Content-Type': 'application/json' },\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Verify signed message and receive JWT token */\n verify(\n message: string,\n signature: string,\n options?: { signal?: AbortSignal },\n ): Promise<VerifyResponse> {\n return this.http.post<VerifyResponse>('/auth/verify', {\n body: { message, signature },\n headers: { 'Content-Type': 'application/json' },\n ...(options?.signal !== undefined && { signal: options.signal }),\n });\n }\n\n /** Store token to be sent on subsequent protected requests */\n setToken(token: string): void {\n this.token = token;\n }\n\n /** Merge Authorization header when token is present */\n private withAuth(headers?: Record<string, string>): Record<string, string> | undefined {\n if (!this.token) return headers;\n return { ...(headers ?? {}), Authorization: `Bearer ${this.token}` };\n }\n\n // Bucket endpoints:\n\n /** List all buckets for the current authenticateduser */\n listBuckets(options?: { signal?: AbortSignal }): Promise<Bucket[]> {\n const headers = this.withAuth();\n return this.http.get<Bucket[]>('/buckets', {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n getBucket(bucketId: string, options?: { signal?: AbortSignal }): Promise<Bucket> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n return this.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n }\n\n /** Gets the list of files and folders under the specified path for a bucket. If no path is provided, it returns the files and folders found at root. */\n getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n return this.http.get<FileListResponse>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: options.path.replace(/^\\/+/, '') } } : {}),\n });\n }\n\n /** Get metadata for a file in a bucket by fileKey */\n getFileInfo(\n bucketId: string,\n fileKey: string,\n options?: { signal?: AbortSignal },\n ): Promise<FileInfo> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n type FileInfoWire = Omit<FileInfo, 'uploadedAt'> & { uploadedAt: string };\n return this.http\n .get<FileInfoWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n })\n .then((wire): FileInfo => ({ ...wire, uploadedAt: new Date(wire.uploadedAt) }));\n }\n\n // File endpoints:\n\n /**\n * Upload a file to a bucket with a specific key.\n *\n * Always uses multipart/form-data upload with both file data and encoded FileMetadata.\n * The file data is loaded into memory to create the multipart request.\n *\n */\n async uploadFile(\n bucketId: string,\n fileKey: string,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n owner: string,\n location: string,\n _options?: UploadOptions,\n ): Promise<UploadReceipt> {\n void _options;\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = this.withAuth();\n\n // Convert the file to a blob and get its size\n const fileBlob = await this.coerceToFormPart(file);\n const fileSize = fileBlob.size;\n\n // Compute the fingerprint first\n // TODO: We should instead use FileManager here and use its `getFingerprint` method.\n // This would allow us to remove the `initWasm` call at the top and to stream the file\n // instead of loading it into memory as a blob.\n const fingerprint = await this.computeFileFingerprint(fileBlob);\n\n // Create the FileMetadata instance\n const metadata = await this.formFileMetadata(\n owner,\n bucketId,\n location,\n fingerprint,\n BigInt(fileSize),\n );\n\n // Compute the file key and ensure it matches the provided file key\n const computedFileKey = await this.computeFileKey(metadata);\n const expectedFileKeyBytes = this.hexToBytes(fileKey);\n if (\n computedFileKey.length !== expectedFileKeyBytes.length ||\n !computedFileKey.every((byte, index) => byte === expectedFileKeyBytes[index])\n ) {\n throw new Error(\n `Computed file key ${computedFileKey.toString()} does not match provided file key ${expectedFileKeyBytes.toString()}`,\n );\n }\n\n // Encode the file metadata\n const encodedMetadata = metadata.encode();\n\n // Create the multipart form with both the file and its metadata\n const form = new FormData();\n const fileMetadataBlob = new Blob([new Uint8Array(encodedMetadata)], {\n type: 'application/octet-stream',\n });\n form.append('file_metadata', fileMetadataBlob, 'file_metadata');\n form.append('file', fileBlob, 'file');\n\n const res = await this.http.put<UploadReceipt>(\n backendPath,\n authHeaders\n ? { body: form as unknown as BodyInit, headers: authHeaders }\n : { body: form as unknown as BodyInit },\n );\n return res;\n }\n\n private async coerceToFormPart(\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n ): Promise<Blob> {\n if (typeof Blob !== 'undefined' && file instanceof Blob) return file;\n if (file instanceof Uint8Array) return new Blob([file.buffer as ArrayBuffer]);\n if (typeof ArrayBuffer !== 'undefined' && file instanceof ArrayBuffer) return new Blob([file]);\n\n // Handle ReadableStream by reading it into memory\n if (file instanceof ReadableStream) {\n const reader = file.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n chunks.push(value);\n totalLength += value.length;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine all chunks into a single Uint8Array\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return new Blob([combined], { type: 'application/octet-stream' });\n }\n\n return new Blob([file as BlobPart], { type: 'application/octet-stream' });\n }\n\n private async computeFileFingerprint(fileBlob: Blob): Promise<Uint8Array> {\n const trie = new FileTrie();\n const fileBytes = new Uint8Array(await fileBlob.arrayBuffer());\n\n // Process the file in 1KB chunks (matching CHUNK_SIZE from constants)\n const CHUNK_SIZE = 1024;\n let offset = 0;\n\n while (offset < fileBytes.length) {\n const end = Math.min(offset + CHUNK_SIZE, fileBytes.length);\n const chunk = fileBytes.slice(offset, end);\n trie.push_chunk(chunk);\n offset = end;\n }\n\n return trie.get_root();\n }\n\n async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint,\n ): Promise<FileMetadata> {\n const ownerBytes = this.hexToBytes(owner);\n const bucketIdBytes = this.hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n hexToBytes(hex: string): Uint8Array {\n if (!hex) {\n throw new Error('hex string cannot be empty');\n }\n\n const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error('hex string must have an even number of characters');\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('hex string contains invalid characters');\n }\n\n return new Uint8Array(cleanHex.match(/.{2}/g)?.map((byte) => Number.parseInt(byte, 16)) || []);\n }\n\n async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n\n /** Download a file by key. */\n async downloadByKey(fileKey: string, options?: DownloadOptions): Promise<DownloadResult> {\n const path = `/download/${encodeURIComponent(fileKey)}`;\n const baseHeaders: Record<string, string> = { Accept: '*/*' };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? ''}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n\n if (!res.body) {\n throw new Error('Response body is null - unable to create stream');\n }\n\n const contentType = res.headers.get('content-type');\n const contentRange = res.headers.get('content-range');\n const contentLengthHeader = res.headers.get('content-length');\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === 'number' && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength,\n };\n }\n\n /** Download a file by its location path under a bucket. */\n async downloadByLocation(\n bucketId: string,\n filePath: string,\n options?: DownloadOptions,\n ): Promise<DownloadResult> {\n const normalized = filePath.replace(/^\\/+/, '');\n const encodedPath = normalized.split('/').map(encodeURIComponent).join('/');\n const path = `/buckets/${encodeURIComponent(bucketId)}/download/path/${encodedPath}`;\n const baseHeaders: Record<string, string> = { Accept: '*/*' };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? ''}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n\n if (!res.body) {\n throw new Error('Response body is null - unable to create stream');\n }\n\n const contentType = res.headers.get('content-type');\n const contentRange = res.headers.get('content-range');\n const contentLengthHeader = res.headers.get('content-length');\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === 'number' && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength,\n };\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["FileMetadata", "FileTrie", "HttpClient", "initWasm", "MspClient", "_MspClient", "config", "http", "options", "address", "chainId", "message", "signature", "token", "headers", "bucketId", "path", "fileKey", "wire", "file", "owner", "location", "_options", "backendPath", "authHeaders", "fileBlob", "fileSize", "fingerprint", "metadata", "computedFileKey", "expectedFileKeyBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "trie", "fileBytes", "CHUNK_SIZE", "end", "size", "ownerBytes", "bucketIdBytes", "locationBytes", "hex", "cleanHex", "fileMetadata", "baseHeaders", "start", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "filePath", "encodedPath"]
4
+ "sourcesContent": ["import type {\n Bucket,\n DownloadOptions,\n DownloadResult,\n FileInfo,\n FileListResponse,\n GetFilesOptions,\n HealthStatus,\n InfoResponse,\n NonceResponse,\n PaymentStreamsResponse,\n StatsResponse,\n UploadOptions,\n UploadReceipt,\n ValueProp,\n VerifyResponse\n} from \"./types.js\";\nimport type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { FileMetadata, FileTrie, HttpClient, initWasm } from \"@storagehub-sdk/core\";\n\nexport class MspClient {\n public readonly config: HttpClientConfig;\n private readonly http: HttpClient;\n public token?: string;\n\n private constructor(config: HttpClientConfig, http: HttpClient) {\n this.config = config;\n this.http = http;\n }\n\n static async connect(config: HttpClientConfig): Promise<MspClient> {\n if (!config?.baseUrl) throw new Error(\"MspClient.connect: baseUrl is required\");\n\n const http = new HttpClient({\n baseUrl: config.baseUrl,\n ...(config.timeoutMs !== undefined && { timeoutMs: config.timeoutMs }),\n ...(config.defaultHeaders !== undefined && {\n defaultHeaders: config.defaultHeaders\n }),\n ...(config.fetchImpl !== undefined && { fetchImpl: config.fetchImpl })\n });\n\n return new MspClient(config, http);\n }\n\n getHealth(options?: { signal?: AbortSignal }): Promise<HealthStatus> {\n return this.http.get<HealthStatus>(\"/health\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get general MSP information */\n getInfo(options?: { signal?: AbortSignal }): Promise<InfoResponse> {\n return this.http.get<InfoResponse>(\"/info\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get MSP statistics */\n getStats(options?: { signal?: AbortSignal }): Promise<StatsResponse> {\n return this.http.get<StatsResponse>(\"/stats\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(options?: { signal?: AbortSignal }): Promise<ValueProp[]> {\n return this.http.get<ValueProp[]>(\"/value-props\", {\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Get payment streams for current authenticated user */\n getPaymentStreams(options?: { signal?: AbortSignal }): Promise<PaymentStreamsResponse> {\n const headers = this.withAuth();\n return this.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n // Auth endpoints:\n /** Request a SIWE-style nonce message for the given address and chainId */\n getNonce(\n address: string,\n chainId: number,\n options?: { signal?: AbortSignal }\n ): Promise<NonceResponse> {\n return this.http.post<NonceResponse>(\"/auth/nonce\", {\n body: { address, chainId },\n headers: { \"Content-Type\": \"application/json\" },\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Verify signed message and receive JWT token */\n verify(\n message: string,\n signature: string,\n options?: { signal?: AbortSignal }\n ): Promise<VerifyResponse> {\n return this.http.post<VerifyResponse>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(options?.signal !== undefined && { signal: options.signal })\n });\n }\n\n /** Store token to be sent on subsequent protected requests */\n setToken(token: string): void {\n this.token = token;\n }\n\n /** Merge Authorization header when token is present */\n private withAuth(headers?: Record<string, string>): Record<string, string> | undefined {\n if (!this.token) return headers;\n return { ...(headers ?? {}), Authorization: `Bearer ${this.token}` };\n }\n\n // Bucket endpoints:\n /** List all buckets for the current authenticateduser */\n listBuckets(options?: { signal?: AbortSignal }): Promise<Bucket[]> {\n const headers = this.withAuth();\n return this.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n getBucket(bucketId: string, options?: { signal?: AbortSignal }): Promise<Bucket> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n return this.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n }\n\n /** Gets the list of files and folders under the specified path for a bucket. If no path is provided, it returns the files and folders found at root. */\n getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n return this.http.get<FileListResponse>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: options.path.replace(/^\\/+/, \"\") } } : {})\n });\n }\n\n /** Get metadata for a file in a bucket by fileKey */\n getFileInfo(\n bucketId: string,\n fileKey: string,\n options?: { signal?: AbortSignal }\n ): Promise<FileInfo> {\n const headers = this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n type FileInfoWire = Omit<FileInfo, \"uploadedAt\"> & { uploadedAt: string };\n return this.http\n .get<FileInfoWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n })\n .then(\n (wire): FileInfo => ({\n ...wire,\n uploadedAt: new Date(wire.uploadedAt)\n })\n );\n }\n\n // File endpoints:\n /**\n * Upload a file to a bucket with a specific key.\n *\n * Always uses multipart/form-data upload with both file data and encoded FileMetadata.\n * The file data is loaded into memory to create the multipart request.\n *\n */\n async uploadFile(\n bucketId: string,\n fileKey: string,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n owner: string,\n location: string,\n _options?: UploadOptions\n ): Promise<UploadReceipt> {\n void _options;\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = this.withAuth();\n\n // Convert the file to a blob and get its size\n const fileBlob = await this.coerceToFormPart(file);\n const fileSize = fileBlob.size;\n\n // Compute the fingerprint first\n // TODO: We should instead use FileManager here and use its `getFingerprint` method.\n // This would allow us to remove the `initWasm` call at the top and to stream the file\n // instead of loading it into memory as a blob.\n const fingerprint = await this.computeFileFingerprint(fileBlob);\n\n // Create the FileMetadata instance\n const metadata = await this.formFileMetadata(\n owner,\n bucketId,\n location,\n fingerprint,\n BigInt(fileSize)\n );\n\n // Compute the file key and ensure it matches the provided file key\n const computedFileKey = await this.computeFileKey(metadata);\n const expectedFileKeyBytes = this.hexToBytes(fileKey);\n if (\n computedFileKey.length !== expectedFileKeyBytes.length ||\n !computedFileKey.every((byte, index) => byte === expectedFileKeyBytes[index])\n ) {\n throw new Error(\n `Computed file key ${computedFileKey.toString()} does not match provided file key ${expectedFileKeyBytes.toString()}`\n );\n }\n\n // Encode the file metadata\n const encodedMetadata = metadata.encode();\n\n // Create the multipart form with both the file and its metadata\n const form = new FormData();\n const fileMetadataBlob = new Blob([new Uint8Array(encodedMetadata)], {\n type: \"application/octet-stream\"\n });\n form.append(\"file_metadata\", fileMetadataBlob, \"file_metadata\");\n form.append(\"file\", fileBlob, \"file\");\n\n const res = await this.http.put<UploadReceipt>(\n backendPath,\n authHeaders\n ? { body: form as unknown as BodyInit, headers: authHeaders }\n : { body: form as unknown as BodyInit }\n );\n return res;\n }\n\n private async coerceToFormPart(\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown\n ): Promise<Blob> {\n if (typeof Blob !== \"undefined\" && file instanceof Blob) return file;\n if (file instanceof Uint8Array) return new Blob([file.buffer as ArrayBuffer]);\n if (typeof ArrayBuffer !== \"undefined\" && file instanceof ArrayBuffer) return new Blob([file]);\n\n // Handle ReadableStream by reading it into memory\n if (file instanceof ReadableStream) {\n const reader = file.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n chunks.push(value);\n totalLength += value.length;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine all chunks into a single Uint8Array\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return new Blob([combined], { type: \"application/octet-stream\" });\n }\n\n return new Blob([file as BlobPart], { type: \"application/octet-stream\" });\n }\n\n private async computeFileFingerprint(fileBlob: Blob): Promise<Uint8Array> {\n const trie = new FileTrie();\n const fileBytes = new Uint8Array(await fileBlob.arrayBuffer());\n\n // Process the file in 1KB chunks (matching CHUNK_SIZE from constants)\n const CHUNK_SIZE = 1024;\n let offset = 0;\n\n while (offset < fileBytes.length) {\n const end = Math.min(offset + CHUNK_SIZE, fileBytes.length);\n const chunk = fileBytes.slice(offset, end);\n trie.push_chunk(chunk);\n offset = end;\n }\n\n return trie.get_root();\n }\n\n async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = this.hexToBytes(owner);\n const bucketIdBytes = this.hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n hexToBytes(hex: string): Uint8Array {\n if (!hex) {\n throw new Error(\"hex string cannot be empty\");\n }\n\n const cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\n if (cleanHex.length % 2 !== 0) {\n throw new Error(\"hex string must have an even number of characters\");\n }\n\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error(\"hex string contains invalid characters\");\n }\n\n return new Uint8Array(cleanHex.match(/.{2}/g)?.map((byte) => Number.parseInt(byte, 16)) || []);\n }\n\n async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n\n /** Download a file by key. */\n async downloadByKey(fileKey: string, options?: DownloadOptions): Promise<DownloadResult> {\n const path = `/download/${encodeURIComponent(fileKey)}`;\n const baseHeaders: Record<string, string> = { Accept: \"*/*\" };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? \"\"}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n\n if (!res.body) {\n throw new Error(\"Response body is null - unable to create stream\");\n }\n\n const contentType = res.headers.get(\"content-type\");\n const contentRange = res.headers.get(\"content-range\");\n const contentLengthHeader = res.headers.get(\"content-length\");\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === \"number\" && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength\n };\n }\n\n /** Download a file by its location path under a bucket. */\n async downloadByLocation(\n bucketId: string,\n filePath: string,\n options?: DownloadOptions\n ): Promise<DownloadResult> {\n const normalized = filePath.replace(/^\\/+/, \"\");\n const encodedPath = normalized.split(\"/\").map(encodeURIComponent).join(\"/\");\n const path = `/buckets/${encodeURIComponent(bucketId)}/download/path/${encodedPath}`;\n const baseHeaders: Record<string, string> = { Accept: \"*/*\" };\n if (options?.range) {\n const { start, end } = options.range;\n const rangeValue = `bytes=${start}-${end ?? \"\"}`;\n baseHeaders.Range = rangeValue;\n }\n const headers = this.withAuth(baseHeaders);\n const res = await this.http.getRaw(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {})\n });\n\n if (!res.body) {\n throw new Error(\"Response body is null - unable to create stream\");\n }\n\n const contentType = res.headers.get(\"content-type\");\n const contentRange = res.headers.get(\"content-range\");\n const contentLengthHeader = res.headers.get(\"content-length\");\n const parsedLength = contentLengthHeader !== null ? Number(contentLengthHeader) : undefined;\n const contentLength =\n typeof parsedLength === \"number\" && Number.isFinite(parsedLength) ? parsedLength : null;\n\n return {\n stream: res.body,\n status: res.status,\n contentType,\n contentRange,\n contentLength\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["FileMetadata", "FileTrie", "HttpClient", "initWasm", "MspClient", "_MspClient", "config", "http", "options", "headers", "address", "chainId", "message", "signature", "token", "bucketId", "path", "fileKey", "wire", "file", "owner", "location", "_options", "backendPath", "authHeaders", "fileBlob", "fileSize", "fingerprint", "metadata", "computedFileKey", "expectedFileKeyBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "trie", "fileBytes", "CHUNK_SIZE", "end", "size", "ownerBytes", "bucketIdBytes", "locationBytes", "hex", "cleanHex", "fileMetadata", "baseHeaders", "start", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "filePath", "encodedPath"]
7
7
  }
package/dist/types.d.ts CHANGED
@@ -33,7 +33,7 @@ export interface UploadProgress {
33
33
  speed: number;
34
34
  eta: number;
35
35
  }
36
- export type UploadState = 'staged' | 'committed';
36
+ export type UploadState = "staged" | "committed";
37
37
  export interface UploadOptions {
38
38
  bucketId?: Hash;
39
39
  replicationFactor?: number;
@@ -57,7 +57,6 @@ export interface UploadReceipt {
57
57
  }
58
58
  export interface NonceResponse {
59
59
  message: string;
60
- nonce: string;
61
60
  }
62
61
  export interface VerifyResponse {
63
62
  token: string;
@@ -90,16 +89,19 @@ export interface Bucket {
90
89
  valuePropId: string;
91
90
  fileCount: number;
92
91
  }
93
- export type FileEntryType = 'file' | 'folder' | string;
94
- export interface FileEntry {
92
+ export type FileTree = {
95
93
  name: string;
96
- type: FileEntryType;
97
- sizeBytes?: number;
98
- fileKey?: string;
99
- }
94
+ } & ({
95
+ type: "file";
96
+ sizeBytes: number;
97
+ fileKey: string;
98
+ } | {
99
+ type: "folder";
100
+ children: FileTree[];
101
+ });
100
102
  export interface FileListResponse {
101
103
  bucketId: string;
102
- files: FileEntry[];
104
+ files: FileTree[];
103
105
  }
104
106
  export interface GetFilesOptions {
105
107
  path?: string;
@@ -144,3 +146,13 @@ export interface FileInfo {
144
146
  isPublic: boolean;
145
147
  uploadedAt: Date;
146
148
  }
149
+ export type PaymentProviderType = "msp" | "bsp";
150
+ export interface PaymentStreamInfo {
151
+ provider: string;
152
+ providerType: PaymentProviderType;
153
+ totalAmountPaid: string;
154
+ costPerTick: string;
155
+ }
156
+ export interface PaymentStreamsResponse {
157
+ streams: PaymentStreamInfo[];
158
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storagehub-sdk/msp-client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "High-level TypeScript client for StorageHub MSP: simple file upload/download, SIWE-style auth, health checks, and bucket browsing built on top of @storagehub-sdk/core.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.node.js",
@@ -26,14 +26,7 @@
26
26
  "@storagehub-sdk/core": ">=0.0.5"
27
27
  },
28
28
  "devDependencies": {
29
- "@eslint/eslintrc": "3.3.1",
30
- "@typescript-eslint/eslint-plugin": "^8.37.0",
31
- "@typescript-eslint/parser": "^8.37.0",
32
- "eslint": "^9.31.0",
33
- "eslint-config-prettier": "^10.1.5",
34
- "eslint-plugin-simple-import-sort": "^12.1.1",
35
- "prettier": "^3.6.2",
36
- "@storagehub-sdk/core": "0.1.0"
29
+ "@storagehub-sdk/core": "0.1.1"
37
30
  },
38
31
  "engines": {
39
32
  "node": ">=22"
@@ -44,10 +37,10 @@
44
37
  "clean": "rm -rf dist node_modules",
45
38
  "coverage": "vitest run --coverage",
46
39
  "dev": "node ./build.js --watch",
47
- "format": "prettier --write \"{src/**/*.ts,src/**/*.tsx}\"",
48
- "format:check": "prettier --check \"{src/**/*.ts,src/**/*.tsx}\"",
49
- "lint": "eslint \"{src/**/*.ts,src/**/*.tsx}\"",
50
- "lint:fix": "eslint \"{src/**/*.ts,src/**/*.tsx}\" --fix",
40
+ "fmt": "biome format .",
41
+ "fmt:fix": "biome format . --write",
42
+ "lint": "biome lint .",
43
+ "lint:fix": "biome lint . --write",
51
44
  "test": "vitest",
52
45
  "typecheck": "tsc --noEmit"
53
46
  }