@storagehub-sdk/msp-client 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +3 -3
- package/dist/index.node.js +1 -1
- package/dist/index.node.js.map +3 -3
- package/dist/modules/files.d.ts +10 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -77,11 +77,19 @@ sessionRef = session;
|
|
|
77
77
|
// 4. Upload a file
|
|
78
78
|
const bucketId = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; // StorageHub bucket identifier
|
|
79
79
|
const fileKey = '0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890'; // Unique file identifier
|
|
80
|
+
const fingerprint = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; // Precomputed fingerprint
|
|
80
81
|
const filePath = './myfile.txt';
|
|
81
82
|
const owner = walletAddress; // File owner
|
|
82
83
|
const location = 'myfile.txt'; // File location/path within the bucket
|
|
83
84
|
|
|
84
|
-
const receipt = await client.files.uploadFile(
|
|
85
|
+
const receipt = await client.files.uploadFile(
|
|
86
|
+
bucketId,
|
|
87
|
+
fileKey,
|
|
88
|
+
createReadStream(filePath),
|
|
89
|
+
fingerprint,
|
|
90
|
+
owner,
|
|
91
|
+
location
|
|
92
|
+
);
|
|
85
93
|
console.log('File uploaded successfully:', receipt);
|
|
86
94
|
|
|
87
95
|
// 5. Download the file
|
|
@@ -143,7 +151,7 @@ console.log('Folder files:', folderFiles);
|
|
|
143
151
|
- `getFiles(bucketId, { path?, signal? })` – returns the file tree at root or at a subpath
|
|
144
152
|
- **`files`**: File metadata, upload and download
|
|
145
153
|
- `getFileInfo(bucketId, fileKey, signal?)` – returns metadata for a specific file
|
|
146
|
-
- `uploadFile(
|
|
154
|
+
- `uploadFile(bucketId, fileKey, file, fingerprint, owner, location, options?)` – uploads a file to the MSP using a precomputed `0x` fingerprint
|
|
147
155
|
- `downloadFile(fileKey, options?)` – downloads a file by key (supports range)
|
|
148
156
|
|
|
149
157
|
### Utilities available via `files`
|
package/dist/index.browser.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{HttpClient as
|
|
1
|
+
import{HttpClient as L}from"@storagehub-sdk/core";import{getAddress as M}from"viem";var p=class{ctx;sessionProviderRef;constructor(e,t){this.ctx=e,this.sessionProviderRef=t}async withAuth(e){let n=(await this.sessionProviderRef.current())?.token;return n?e?{...e,Authorization:`Bearer ${n}`}:{Authorization:`Bearer ${n}`}:e}normalizePath(e){return e.replace(/^\/+|\/{2,}/g,(t,n)=>n===0?"":"/")}};var B=10,T=100,y=class extends p{getNonce(e,t,n,s,i){return this.ctx.http.post("/auth/nonce",{body:{address:e,chainId:t,domain:n,uri:s},headers:{"Content-Type":"application/json"},...i?{signal:i}:{}})}getMessage(e,t,n,s){return this.ctx.http.post("/auth/message",{body:{address:e,chainId:t,uri:n},headers:{"Content-Type":"application/json"},...s?{signal:s}:{}})}async verify(e,t,n){return await this.ctx.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?{signal:n}:{}})}async SIWE(e,t,n,s=B,i){let{account:r,address:a,chainId:o}=await this.resolveAccount(e,"SIWE"),{message:l}=await this.getNonce(a,o,t,n,i);return this.signAndVerifyWithRetry(e,r,l,s,i,"SIWE")}async SIWX(e,t,n=B,s){let{account:i,address:r,chainId:a}=await this.resolveAccount(e,"SIWX"),{message:o}=await this.getMessage(r,a,t,s);return this.signAndVerifyWithRetry(e,i,o,n,s,"SIWX")}async resolveAccount(e,t){let n=e.account,s=typeof n=="string"?n:n?.address;if(!s||!n)throw new Error(`Wallet client has no active account; set wallet.account before calling ${t}`);let i=M(s),r=await e.getChainId();return{account:n,address:i,chainId:r}}async signAndVerifyWithRetry(e,t,n,s,i,r){let a=await e.signMessage({account:t,message:n}),o;for(let l=0;l<s;l++)try{return await this.verify(n,a,i)}catch(u){o=u,await this.delay(T)}throw o instanceof Error?o:new Error(`${r} verification failed`)}async delay(e){await new Promise(t=>setTimeout(t,e))}async getProfile(e){let t=await this.withAuth();return this.ctx.http.get("/auth/profile",{...t?{headers:t}:{},...e?{signal:e}:{}})}};import{ensure0xPrefix as d,parseDate as H}from"@storagehub-sdk/core";function C(c){return c.type==="file"?{name:c.name,type:c.type,sizeBytes:c.sizeBytes,fileKey:d(c.fileKey),status:c.status,uploadedAt:H(c.uploadedAt)}:{name:c.name,type:c.type,children:(c.children??[]).map(C)}}var f=class extends p{async listBuckets(e){let t=await this.withAuth();return(await this.ctx.http.get("/buckets",{...t?{headers:t}:{},...e?{signal:e}:{}})).map(s=>({bucketId:d(s.bucketId),name:s.name,root:d(s.root),isPublic:s.isPublic,sizeBytes:s.sizeBytes,valuePropId:d(s.valuePropId),fileCount:s.fileCount}))}async getBucket(e,t){let n=await this.withAuth(),s=`/buckets/${encodeURIComponent(e)}`,i=await this.ctx.http.get(s,{...n?{headers:n}:{},...t?{signal:t}:{}});return{bucketId:d(i.bucketId),name:i.name,root:d(i.root),isPublic:i.isPublic,sizeBytes:i.sizeBytes,valuePropId:d(i.valuePropId),fileCount:i.fileCount}}async getFiles(e,t){let n=await this.withAuth(),s=`/buckets/${encodeURIComponent(e)}/files`,i=await this.ctx.http.get(s,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:this.normalizePath(t.path)}}:{}}),a=("files"in i?i.files:[i.tree]).map(C),o=a[0];return{bucketId:d(i.bucketId),files:a,...o?{tree:o}:{}}}};import{assert0xString as A,ensure0xPrefix as h,FileMetadata as E,hexToBytes as g,initWasm as I,parseDate as z}from"@storagehub-sdk/core";var b=class extends p{async getFileInfo(e,t,n){let s=await this.withAuth(),i=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`,r=await this.ctx.http.get(i,{...s?{headers:s}:{},...n?{signal:n}:{}});return{fileKey:h(r.fileKey),fingerprint:h(r.fingerprint),bucketId:h(r.bucketId),location:r.location,size:BigInt(r.size),isPublic:r.isPublic,uploadedAt:z(r.uploadedAt),status:r.status,blockHash:h(r.blockHash),...r.txHash?{txHash:h(r.txHash)}:{}}}async uploadFile(e,t,n,s,i,r,a){A(e,32,"Invalid bucketId: expected 0x-prefixed 32-byte hex"),A(s,32,"Invalid fingerprint: expected 0x-prefixed 32-byte hex"),A(i,20,"Invalid owner: expected 0x-prefixed 20-byte hex"),await I();let o=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,l=await this.withAuth(),u=await this.coerceToFormPart(n),x=u.size,v=await this.formFileMetadata(i,e,r,s,BigInt(x)),S=await this.computeFileKey(v),P=g(t);if(S.length!==P.length||!S.every((W,$)=>W===P[$]))throw new Error(`Computed file key ${S.toString()} does not match provided file key ${P.toString()}`);let k=v.encode(),m=new FormData,U=new Blob([new Uint8Array(k)],{type:"application/octet-stream"});return m.append("file_metadata",U,"file_metadata"),m.append("file",u,"file"),await this.ctx.http.put(o,l?{body:m,headers:l}:{body:m})}async downloadFile(e,t){let n=`/download/${encodeURIComponent(e)}`,s={Accept:"*/*"};if(t?.range){let{start:r,end:a}=t.range,o=`bytes=${r}-${a??""}`;s.Range=o}let i=await this.withAuth(s);try{let r=await this.ctx.http.getRaw(n,{...i?{headers:i}:{},...t?.signal?{signal:t.signal}:{}});if(!r.body)throw new Error("Response body is null - unable to create stream");let a=r.headers.get("content-type"),o=r.headers.get("content-range"),l=r.headers.get("content-length"),u=l!==null?Number(l):void 0,x=typeof u=="number"&&Number.isFinite(u)?u:null;return{stream:r.body,status:r.status,contentType:a,contentRange:o,contentLength:x}}catch(r){if(this.isHttpError(r))return{stream:this.createEmptyStream(),status:r.status,contentType:null,contentRange:null,contentLength:null};throw r}}async getDownloadUrl(e,t,n){let s=h(e),i=h(t),r;try{r=await this.getFileInfo(s,i,n)}catch(l){throw this.isHttpError(l)&&l.status===404?new Error(`File not found: ${i}`):l}if(!r.isPublic)throw new Error(`File is private: ${i}. Direct download URL for private files is not supported yet.`);if(r.status!=="ready")throw new Error(`File is not Ready (status=${r.status}): ${i}`);let a=this.ctx.config.baseUrl.replace(/\/$/,""),o=`/download/${encodeURIComponent(i)}`;return new URL(a+o).toString()}isHttpError(e){return e!==null&&typeof e=="object"&&"status"in e&&typeof e.status=="number"}createEmptyStream(){return new ReadableStream({start(e){e.close()}})}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=[],s=0;try{for(;;){let{done:a,value:o}=await t.read();if(a)break;o&&(n.push(o),s+=o.length)}}finally{t.releaseLock()}let i=new Uint8Array(s),r=0;for(let a of n)i.set(a,r),r+=a.length;return new Blob([i],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async formFileMetadata(e,t,n,s,i){let r=g(e),a=g(t),o=g(s),l=new TextEncoder().encode(n);return await I(),new E(r,a,l,i,o)}async computeFileKey(e){return await I(),e.getFileKey()}};import{ensure0xPrefix as R}from"@storagehub-sdk/core";var w=class extends p{getHealth(e){return this.ctx.http.get("/health",{...e?{signal:e}:{}})}async getInfo(e){let t=await this.ctx.http.get("/info",{...e?{signal:e}:{}});return{client:t.client,version:t.version,mspId:R(t.mspId),multiaddresses:t.multiaddresses,ownerAccount:R(t.ownerAccount),paymentAccount:R(t.paymentAccount),status:t.status,activeSince:t.activeSince,uptime:t.uptime}}getStats(e){return this.ctx.http.get("/stats",{...e?{signal:e}:{}})}getValuePropositions(e){return this.ctx.http.get("/value-props",{...e?{signal:e}:{}})}async getPaymentStreams(e){let t=await this.withAuth();return this.ctx.http.get("/payment_streams",{...t?{headers:t}:{},...e?{signal:e}:{}})}};var F=class c extends p{config;context;auth;buckets;files;info;constructor(e,t,n){let s={config:e,http:t};super(s,n),this.config=e,this.context=s,this.auth=new y(this.context,n),this.buckets=new f(this.context,n),this.files=new b(this.context,n),this.info=new w(this.context,n)}static async connect(e,t=async()=>{}){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let n=new L({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}}),s={current:t};return new c(e,n,s)}setSessionProvider(e){this.sessionProviderRef.current=e}};export{F 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", "../src/modules/auth.ts", "../src/base.ts", "../src/modules/buckets.ts", "../src/modules/files.ts", "../src/modules/info.ts"],
|
|
4
|
-
"sourcesContent": ["import type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { HttpClient } from \"@storagehub-sdk/core\";\nimport type { MspClientContext } from \"./context.js\";\nimport { AuthModule } from \"./modules/auth.js\";\nimport { BucketsModule } from \"./modules/buckets.js\";\nimport { ModuleBase } from \"./base.js\";\nimport { FilesModule } from \"./modules/files.js\";\nimport { InfoModule } from \"./modules/info.js\";\nimport type { SessionProvider } from \"./types.js\";\n\nexport class MspClient extends ModuleBase {\n public readonly config: HttpClientConfig;\n private readonly context: MspClientContext;\n public readonly auth: AuthModule;\n public readonly buckets: BucketsModule;\n public readonly files: FilesModule;\n public readonly info: InfoModule;\n\n private constructor(\n config: HttpClientConfig,\n http: HttpClient,\n sessionProviderRef: { current: SessionProvider }\n ) {\n const context: MspClientContext = { config, http };\n super(context, sessionProviderRef);\n this.config = config;\n this.context = context;\n this.auth = new AuthModule(this.context, sessionProviderRef);\n this.buckets = new BucketsModule(this.context, sessionProviderRef);\n this.files = new FilesModule(this.context, sessionProviderRef);\n this.info = new InfoModule(this.context, sessionProviderRef);\n }\n\n static async connect(\n config: HttpClientConfig,\n sessionProvider: SessionProvider = async () => undefined\n ): 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 // Create a shared reference object\n const sessionProviderRef = { current: sessionProvider };\n return new MspClient(config, http, sessionProviderRef);\n }\n\n /**\n * Updates the session provider for this client and all its modules.\n * This allows updating authentication after the client has been created.\n *\n * @param sessionProvider - The new session provider function.\n */\n setSessionProvider(sessionProvider: SessionProvider): void {\n this.sessionProviderRef.current = sessionProvider;\n }\n}\n", "import type { NonceResponse, Session, UserInfo } from \"../types.js\";\nimport { getAddress, type WalletClient } from \"viem\";\nimport { ModuleBase } from \"../base.js\";\n\nconst DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS = 10;\nconst DEFAULT_SIWE_VERIFY_BACKOFF_MS = 100;\n\nexport class AuthModule extends ModuleBase {\n /**\n * Request a nonce (challenge message) for Sign-In with Ethereum (SIWE).\n *\n * **Advanced use only:** Most users should use the `SIWE()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes). You must call `verify()` with a valid signature before expiration.\n *\n * @param address - The Ethereum address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the SIWE challenge message to be signed.\n */\n public getNonce(\n address: string,\n chainId: number,\n domain: string,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/nonce\", {\n body: {\n address,\n chainId,\n domain,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Request a message (challenge) for Sign-In with X (SIWX) using CAIP-122 standard.\n *\n * **Advanced use only:** Most users should use the `SIWX()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * This method follows the CAIP-122 standard for chain-agnostic authentication.\n * The message uses CAIP-10 format for addresses (e.g., `eip155:55931:0x...`).\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes).\n * You must call `verify()` with a valid signature before expiration.\n *\n * **Note:** According to CAIP-122, the domain is extracted from the URI automatically.\n * You do not need to provide the domain separately - it will be extracted from the URI.\n *\n * @param address - The blockchain address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the CAIP-122 challenge message to be signed.\n */\n public getMessage(\n address: string,\n chainId: number,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/message\", {\n body: {\n address,\n chainId,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Verify a Sign-In signature (works with both SIWE and SIWX/CAIP-122 messages).\n *\n * **Advanced use only:** Most users should use the `SIWE()` or `SIWX()` methods instead, which handle the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function passed to `MspClient.connect()`.\n * The session is not automatically persisted - you are responsible for managing session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * @param message - The challenge message received from `getNonce()` (SIWE) or `getMessage()` (CAIP-122).\n * @param signature - The signature of the message signed by the user's wallet.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n public async verify(message: string, signature: string, signal?: AbortSignal): Promise<Session> {\n const session = await this.ctx.http.post<Session>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n\n return session;\n }\n\n /**\n * Complete Sign-In with Ethereum (SIWE) authentication flow using a `WalletClient`.\n *\n * This is the recommended method for authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a nonce, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWE(\n wallet: WalletClient,\n domain: string,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWE\");\n const { message } = await this.getNonce(address, chainId, domain, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWE\");\n }\n\n /**\n * Complete Sign-In with X (SIWX) authentication flow using CAIP-122 standard and a `WalletClient`.\n *\n * This is the recommended method for CAIP-122 authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a CAIP-122 message, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * **CAIP-122:** Unlike SIWE, this method does not require a `domain` parameter. The domain is automatically extracted\n * from the `uri` parameter on the backend per CAIP-122 specification.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWX(\n wallet: WalletClient,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWX\");\n const { message } = await this.getMessage(address, chainId, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWX\");\n }\n\n /**\n * Resolves and validates the account from a WalletClient.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param methodName - The name of the calling method (for error messages).\n * @returns An object containing the account, checksummed address, and chainId.\n * @throws Error if the wallet has no active account.\n */\n private async resolveAccount(\n wallet: WalletClient,\n methodName: string\n ): Promise<{ account: NonNullable<WalletClient[\"account\"]>; address: string; chainId: number }> {\n const account = wallet.account;\n const resolvedAddress = typeof account === \"string\" ? account : account?.address;\n if (!resolvedAddress || !account) {\n throw new Error(\n `Wallet client has no active account; set wallet.account before calling ${methodName}`\n );\n }\n const address = getAddress(resolvedAddress);\n const chainId = await wallet.getChainId();\n return { account, address, chainId };\n }\n\n /**\n * Signs a message and verifies it with retry logic.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param account - The account to sign with.\n * @param message - The message to sign.\n * @param retry - Number of retry attempts for verification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @param methodName - The name of the calling method (for error messages).\n * @returns A promise resolving to a Session object.\n */\n private async signAndVerifyWithRetry(\n wallet: WalletClient,\n account: NonNullable<WalletClient[\"account\"]>,\n message: string,\n retry: number,\n signal: AbortSignal | undefined,\n methodName: string\n ): Promise<Session> {\n const signature = await wallet.signMessage({ account, message });\n\n // TODO: remove the retry logic once the backend is fixed.\n let lastError: unknown;\n for (let attemptIndex = 0; attemptIndex < retry; attemptIndex++) {\n try {\n return await this.verify(message, signature, signal);\n } catch (err) {\n lastError = err;\n await this.delay(DEFAULT_SIWE_VERIFY_BACKOFF_MS);\n }\n }\n throw lastError instanceof Error ? lastError : new Error(`${methodName} verification failed`);\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Fetch authenticated user's profile.\n * - Requires valid `session` (Authorization header added automatically).\n */\n async getProfile(signal?: AbortSignal): Promise<UserInfo> {\n const headers = await this.withAuth();\n return this.ctx.http.get<UserInfo>(\"/auth/profile\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n", "import type { MspClientContext } from \"./context.js\";\nimport type { SessionProvider } from \"./types.js\";\n\n/**\n * Shared reference to sessionProvider so all modules use the same instance.\n */\ntype SessionProviderRef = { current: SessionProvider };\n\nexport abstract class ModuleBase {\n protected readonly ctx: MspClientContext;\n protected readonly sessionProviderRef: SessionProviderRef;\n\n constructor(ctx: MspClientContext, sessionProviderRef: SessionProviderRef) {\n this.ctx = ctx;\n this.sessionProviderRef = sessionProviderRef;\n }\n\n protected async withAuth(\n headers?: Record<string, string>\n ): Promise<Record<string, string> | undefined> {\n const session = await this.sessionProviderRef.current();\n const token = session?.token;\n if (!token) return headers;\n return headers\n ? { ...headers, Authorization: `Bearer ${token}` }\n : { Authorization: `Bearer ${token}` };\n }\n\n /**\n * Normalize a user-provided path for HTTP query usage.\n * - Removes all leading '/' characters to avoid double slashes in URLs.\n * - Collapses any repeated slashes in the middle or at the end to a single '/'.\n * Examples:\n * \"/foo/bar\" -> \"foo/bar\"\n * \"///docs\" -> \"docs\"\n * \"foo//bar\" -> \"foo/bar\"\n * \"///a//b///\" -> \"a/b/\"\n * \"foo/bar\" -> \"foo/bar\" (unchanged)\n * \"/\" -> \"\"\n */\n protected normalizePath(path: string): string {\n // Drop leading slashes (offset === 0), collapse others to '/'\n return path.replace(/^\\/+|\\/{2,}/g, (_m, offset: number) => (offset === 0 ? \"\" : \"/\"));\n }\n}\n", "import type { Bucket, FileListResponse, GetFilesOptions, FileTree, FileStatus } from \"../types.js\";\nimport { ModuleBase } from \"../base.js\";\nimport { ensure0xPrefix, parseDate } from \"@storagehub-sdk/core\";\n\n// Wire types received from backend JSON responses\ntype FileTreeWireFile = {\n name: string;\n type: \"file\";\n sizeBytes: number;\n fileKey: string; // may lack 0x\n status: FileStatus;\n uploadedAt: string; // ISO timestamp\n};\n\ntype FileTreeWireFolder = {\n name: string;\n type: \"folder\";\n children?: readonly FileTreeWire[];\n};\n\ntype FileTreeWire = FileTreeWireFile | FileTreeWireFolder;\n\ntype FileListResponseWire =\n | { bucketId: string; files: readonly FileTreeWire[] }\n | { bucketId: string; tree: FileTreeWireFolder };\n\n/** Recursively fix hex prefixes in FileTree structures */\nfunction fixFileTree(item: FileTreeWire): FileTree {\n if (item.type === \"file\") {\n return {\n name: item.name,\n type: item.type,\n sizeBytes: item.sizeBytes,\n fileKey: ensure0xPrefix(item.fileKey),\n status: item.status,\n uploadedAt: parseDate(item.uploadedAt)\n };\n }\n return {\n name: item.name,\n type: item.type,\n children: (item.children ?? []).map(fixFileTree)\n };\n}\n\nexport class BucketsModule extends ModuleBase {\n /** List all buckets for the current authenticated user */\n async listBuckets(signal?: AbortSignal): Promise<Bucket[]> {\n const headers = await this.withAuth();\n const wire = await this.ctx.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return wire.map((bucket: Bucket) => ({\n bucketId: ensure0xPrefix(bucket.bucketId),\n name: bucket.name,\n root: ensure0xPrefix(bucket.root),\n isPublic: bucket.isPublic,\n sizeBytes: bucket.sizeBytes,\n valuePropId: ensure0xPrefix(bucket.valuePropId),\n fileCount: bucket.fileCount\n }));\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n async getBucket(bucketId: string, signal?: AbortSignal): Promise<Bucket> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n\n const wire = await this.ctx.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n name: wire.name,\n root: ensure0xPrefix(wire.root),\n isPublic: wire.isPublic,\n sizeBytes: wire.sizeBytes,\n valuePropId: ensure0xPrefix(wire.valuePropId),\n fileCount: wire.fileCount\n };\n }\n\n /** List files/folders under a path for a bucket (root if no path) */\n async getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n\n const wire = await this.ctx.http.get<FileListResponseWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: this.normalizePath(options.path) } } : {})\n });\n\n const filesWire: readonly FileTreeWire[] = \"files\" in wire ? wire.files : [wire.tree];\n const files: FileTree[] = filesWire.map(fixFileTree);\n const tree = files[0];\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n files,\n ...(tree ? { tree } : {})\n } as unknown as FileListResponse;\n }\n}\n", "import {\n ensure0xPrefix,\n FileMetadata,\n FileTrie,\n hexToBytes,\n initWasm,\n parseDate\n} from \"@storagehub-sdk/core\";\nimport { ModuleBase } from \"../base.js\";\nimport type {\n DownloadOptions,\n DownloadResult,\n FileStatus,\n StorageFileInfo,\n UploadOptions,\n UploadReceipt\n} from \"../types.js\";\n\nexport class FilesModule extends ModuleBase {\n /** Get metadata for a file in a bucket by fileKey */\n async getFileInfo(\n bucketId: string,\n fileKey: string,\n signal?: AbortSignal\n ): Promise<StorageFileInfo> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n\n const wire = await this.ctx.http.get<{\n fileKey: string;\n fingerprint: string;\n bucketId: string;\n location: string;\n size: string; // Backend sends as string to avoid precision loss\n isPublic: boolean;\n uploadedAt: string; // ISO string, not Date object\n status: string;\n blockHash: string; // Block hash where file was created\n txHash?: string; // Optional EVM transaction hash\n }>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n fileKey: ensure0xPrefix(wire.fileKey),\n fingerprint: ensure0xPrefix(wire.fingerprint),\n bucketId: ensure0xPrefix(wire.bucketId),\n location: wire.location,\n size: BigInt(wire.size),\n isPublic: wire.isPublic,\n uploadedAt: parseDate(wire.uploadedAt),\n status: wire.status as FileStatus,\n blockHash: ensure0xPrefix(wire.blockHash),\n ...(wire.txHash ? { txHash: ensure0xPrefix(wire.txHash) } : {})\n };\n }\n\n /** Upload a file to a bucket with a specific key */\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 = await 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 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 = 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.ctx.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 /** Download a file by key */\n async downloadFile(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\n const headers = await this.withAuth(baseHeaders);\n\n try {\n const res = await this.ctx.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 } catch (error) {\n // Handle HTTP errors by returning them as a DownloadResult with the error status\n if (this.isHttpError(error)) {\n return {\n stream: this.createEmptyStream(),\n status: error.status,\n contentType: null,\n contentRange: null,\n contentLength: null\n };\n }\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n\n // Helpers\n private isHttpError(error: unknown): error is { status: number } {\n return (\n error !== null &&\n typeof error === \"object\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n }\n\n private createEmptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n }\n });\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 private async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = hexToBytes(owner);\n const bucketIdBytes = hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n private async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n}\n", "import { ModuleBase } from \"../base.js\";\nimport type {\n HealthStatus,\n InfoResponse,\n PaymentStreamsResponse,\n StatsResponse,\n ValueProp\n} from \"../types.js\";\nimport { ensure0xPrefix } from \"@storagehub-sdk/core\";\n\nexport class InfoModule extends ModuleBase {\n getHealth(signal?: AbortSignal): Promise<HealthStatus> {\n return this.ctx.http.get<HealthStatus>(\"/health\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get general MSP information */\n async getInfo(signal?: AbortSignal): Promise<InfoResponse> {\n const wire = await this.ctx.http.get<{\n client: string;\n version: string;\n mspId: string;\n multiaddresses: string[];\n ownerAccount: string;\n paymentAccount: string;\n status: string;\n activeSince: number;\n uptime: string;\n }>(\"/info\", {\n ...(signal ? { signal } : {})\n });\n\n return {\n client: wire.client,\n version: wire.version,\n mspId: ensure0xPrefix(wire.mspId),\n multiaddresses: wire.multiaddresses,\n ownerAccount: ensure0xPrefix(wire.ownerAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n paymentAccount: ensure0xPrefix(wire.paymentAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n status: wire.status,\n activeSince: wire.activeSince,\n uptime: wire.uptime\n };\n }\n\n /** Get MSP statistics */\n getStats(signal?: AbortSignal): Promise<StatsResponse> {\n return this.ctx.http.get<StatsResponse>(\"/stats\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(signal?: AbortSignal): Promise<ValueProp[]> {\n return this.ctx.http.get<ValueProp[]>(\"/value-props\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get payment streams for current authenticated user */\n async getPaymentStreams(signal?: AbortSignal): Promise<PaymentStreamsResponse> {\n const headers = await this.withAuth();\n return this.ctx.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["HttpClient", "getAddress", "ModuleBase", "ctx", "sessionProviderRef", "headers", "token", "path", "_m", "offset", "DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS", "DEFAULT_SIWE_VERIFY_BACKOFF_MS", "AuthModule", "ModuleBase", "address", "chainId", "domain", "uri", "signal", "message", "signature", "wallet", "retry", "account", "methodName", "resolvedAddress", "getAddress", "lastError", "attemptIndex", "err", "ms", "resolve", "headers", "ensure0xPrefix", "parseDate", "fixFileTree", "item", "BucketsModule", "ModuleBase", "signal", "headers", "bucket", "bucketId", "path", "wire", "options", "files", "tree", "
|
|
4
|
+
"sourcesContent": ["import type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { HttpClient } from \"@storagehub-sdk/core\";\nimport type { MspClientContext } from \"./context.js\";\nimport { AuthModule } from \"./modules/auth.js\";\nimport { BucketsModule } from \"./modules/buckets.js\";\nimport { ModuleBase } from \"./base.js\";\nimport { FilesModule } from \"./modules/files.js\";\nimport { InfoModule } from \"./modules/info.js\";\nimport type { SessionProvider } from \"./types.js\";\n\nexport class MspClient extends ModuleBase {\n public readonly config: HttpClientConfig;\n private readonly context: MspClientContext;\n public readonly auth: AuthModule;\n public readonly buckets: BucketsModule;\n public readonly files: FilesModule;\n public readonly info: InfoModule;\n\n private constructor(\n config: HttpClientConfig,\n http: HttpClient,\n sessionProviderRef: { current: SessionProvider }\n ) {\n const context: MspClientContext = { config, http };\n super(context, sessionProviderRef);\n this.config = config;\n this.context = context;\n this.auth = new AuthModule(this.context, sessionProviderRef);\n this.buckets = new BucketsModule(this.context, sessionProviderRef);\n this.files = new FilesModule(this.context, sessionProviderRef);\n this.info = new InfoModule(this.context, sessionProviderRef);\n }\n\n static async connect(\n config: HttpClientConfig,\n sessionProvider: SessionProvider = async () => undefined\n ): 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 // Create a shared reference object\n const sessionProviderRef = { current: sessionProvider };\n return new MspClient(config, http, sessionProviderRef);\n }\n\n /**\n * Updates the session provider for this client and all its modules.\n * This allows updating authentication after the client has been created.\n *\n * @param sessionProvider - The new session provider function.\n */\n setSessionProvider(sessionProvider: SessionProvider): void {\n this.sessionProviderRef.current = sessionProvider;\n }\n}\n", "import type { NonceResponse, Session, UserInfo } from \"../types.js\";\nimport { getAddress, type WalletClient } from \"viem\";\nimport { ModuleBase } from \"../base.js\";\n\nconst DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS = 10;\nconst DEFAULT_SIWE_VERIFY_BACKOFF_MS = 100;\n\nexport class AuthModule extends ModuleBase {\n /**\n * Request a nonce (challenge message) for Sign-In with Ethereum (SIWE).\n *\n * **Advanced use only:** Most users should use the `SIWE()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes). You must call `verify()` with a valid signature before expiration.\n *\n * @param address - The Ethereum address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the SIWE challenge message to be signed.\n */\n public getNonce(\n address: string,\n chainId: number,\n domain: string,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/nonce\", {\n body: {\n address,\n chainId,\n domain,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Request a message (challenge) for Sign-In with X (SIWX) using CAIP-122 standard.\n *\n * **Advanced use only:** Most users should use the `SIWX()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * This method follows the CAIP-122 standard for chain-agnostic authentication.\n * The message uses CAIP-10 format for addresses (e.g., `eip155:55931:0x...`).\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes).\n * You must call `verify()` with a valid signature before expiration.\n *\n * **Note:** According to CAIP-122, the domain is extracted from the URI automatically.\n * You do not need to provide the domain separately - it will be extracted from the URI.\n *\n * @param address - The blockchain address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the CAIP-122 challenge message to be signed.\n */\n public getMessage(\n address: string,\n chainId: number,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/message\", {\n body: {\n address,\n chainId,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Verify a Sign-In signature (works with both SIWE and SIWX/CAIP-122 messages).\n *\n * **Advanced use only:** Most users should use the `SIWE()` or `SIWX()` methods instead, which handle the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function passed to `MspClient.connect()`.\n * The session is not automatically persisted - you are responsible for managing session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * @param message - The challenge message received from `getNonce()` (SIWE) or `getMessage()` (CAIP-122).\n * @param signature - The signature of the message signed by the user's wallet.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n public async verify(message: string, signature: string, signal?: AbortSignal): Promise<Session> {\n const session = await this.ctx.http.post<Session>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n\n return session;\n }\n\n /**\n * Complete Sign-In with Ethereum (SIWE) authentication flow using a `WalletClient`.\n *\n * This is the recommended method for authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a nonce, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWE(\n wallet: WalletClient,\n domain: string,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWE\");\n const { message } = await this.getNonce(address, chainId, domain, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWE\");\n }\n\n /**\n * Complete Sign-In with X (SIWX) authentication flow using CAIP-122 standard and a `WalletClient`.\n *\n * This is the recommended method for CAIP-122 authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a CAIP-122 message, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * **CAIP-122:** Unlike SIWE, this method does not require a `domain` parameter. The domain is automatically extracted\n * from the `uri` parameter on the backend per CAIP-122 specification.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWX(\n wallet: WalletClient,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWX\");\n const { message } = await this.getMessage(address, chainId, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWX\");\n }\n\n /**\n * Resolves and validates the account from a WalletClient.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param methodName - The name of the calling method (for error messages).\n * @returns An object containing the account, checksummed address, and chainId.\n * @throws Error if the wallet has no active account.\n */\n private async resolveAccount(\n wallet: WalletClient,\n methodName: string\n ): Promise<{ account: NonNullable<WalletClient[\"account\"]>; address: string; chainId: number }> {\n const account = wallet.account;\n const resolvedAddress = typeof account === \"string\" ? account : account?.address;\n if (!resolvedAddress || !account) {\n throw new Error(\n `Wallet client has no active account; set wallet.account before calling ${methodName}`\n );\n }\n const address = getAddress(resolvedAddress);\n const chainId = await wallet.getChainId();\n return { account, address, chainId };\n }\n\n /**\n * Signs a message and verifies it with retry logic.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param account - The account to sign with.\n * @param message - The message to sign.\n * @param retry - Number of retry attempts for verification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @param methodName - The name of the calling method (for error messages).\n * @returns A promise resolving to a Session object.\n */\n private async signAndVerifyWithRetry(\n wallet: WalletClient,\n account: NonNullable<WalletClient[\"account\"]>,\n message: string,\n retry: number,\n signal: AbortSignal | undefined,\n methodName: string\n ): Promise<Session> {\n const signature = await wallet.signMessage({ account, message });\n\n // TODO: remove the retry logic once the backend is fixed.\n let lastError: unknown;\n for (let attemptIndex = 0; attemptIndex < retry; attemptIndex++) {\n try {\n return await this.verify(message, signature, signal);\n } catch (err) {\n lastError = err;\n await this.delay(DEFAULT_SIWE_VERIFY_BACKOFF_MS);\n }\n }\n throw lastError instanceof Error ? lastError : new Error(`${methodName} verification failed`);\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Fetch authenticated user's profile.\n * - Requires valid `session` (Authorization header added automatically).\n */\n async getProfile(signal?: AbortSignal): Promise<UserInfo> {\n const headers = await this.withAuth();\n return this.ctx.http.get<UserInfo>(\"/auth/profile\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n", "import type { MspClientContext } from \"./context.js\";\nimport type { SessionProvider } from \"./types.js\";\n\n/**\n * Shared reference to sessionProvider so all modules use the same instance.\n */\ntype SessionProviderRef = { current: SessionProvider };\n\nexport abstract class ModuleBase {\n protected readonly ctx: MspClientContext;\n protected readonly sessionProviderRef: SessionProviderRef;\n\n constructor(ctx: MspClientContext, sessionProviderRef: SessionProviderRef) {\n this.ctx = ctx;\n this.sessionProviderRef = sessionProviderRef;\n }\n\n protected async withAuth(\n headers?: Record<string, string>\n ): Promise<Record<string, string> | undefined> {\n const session = await this.sessionProviderRef.current();\n const token = session?.token;\n if (!token) return headers;\n return headers\n ? { ...headers, Authorization: `Bearer ${token}` }\n : { Authorization: `Bearer ${token}` };\n }\n\n /**\n * Normalize a user-provided path for HTTP query usage.\n * - Removes all leading '/' characters to avoid double slashes in URLs.\n * - Collapses any repeated slashes in the middle or at the end to a single '/'.\n * Examples:\n * \"/foo/bar\" -> \"foo/bar\"\n * \"///docs\" -> \"docs\"\n * \"foo//bar\" -> \"foo/bar\"\n * \"///a//b///\" -> \"a/b/\"\n * \"foo/bar\" -> \"foo/bar\" (unchanged)\n * \"/\" -> \"\"\n */\n protected normalizePath(path: string): string {\n // Drop leading slashes (offset === 0), collapse others to '/'\n return path.replace(/^\\/+|\\/{2,}/g, (_m, offset: number) => (offset === 0 ? \"\" : \"/\"));\n }\n}\n", "import type { Bucket, FileListResponse, GetFilesOptions, FileTree, FileStatus } from \"../types.js\";\nimport { ModuleBase } from \"../base.js\";\nimport { ensure0xPrefix, parseDate } from \"@storagehub-sdk/core\";\n\n// Wire types received from backend JSON responses\ntype FileTreeWireFile = {\n name: string;\n type: \"file\";\n sizeBytes: number;\n fileKey: string; // may lack 0x\n status: FileStatus;\n uploadedAt: string; // ISO timestamp\n};\n\ntype FileTreeWireFolder = {\n name: string;\n type: \"folder\";\n children?: readonly FileTreeWire[];\n};\n\ntype FileTreeWire = FileTreeWireFile | FileTreeWireFolder;\n\ntype FileListResponseWire =\n | { bucketId: string; files: readonly FileTreeWire[] }\n | { bucketId: string; tree: FileTreeWireFolder };\n\n/** Recursively fix hex prefixes in FileTree structures */\nfunction fixFileTree(item: FileTreeWire): FileTree {\n if (item.type === \"file\") {\n return {\n name: item.name,\n type: item.type,\n sizeBytes: item.sizeBytes,\n fileKey: ensure0xPrefix(item.fileKey),\n status: item.status,\n uploadedAt: parseDate(item.uploadedAt)\n };\n }\n return {\n name: item.name,\n type: item.type,\n children: (item.children ?? []).map(fixFileTree)\n };\n}\n\nexport class BucketsModule extends ModuleBase {\n /** List all buckets for the current authenticated user */\n async listBuckets(signal?: AbortSignal): Promise<Bucket[]> {\n const headers = await this.withAuth();\n const wire = await this.ctx.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return wire.map((bucket: Bucket) => ({\n bucketId: ensure0xPrefix(bucket.bucketId),\n name: bucket.name,\n root: ensure0xPrefix(bucket.root),\n isPublic: bucket.isPublic,\n sizeBytes: bucket.sizeBytes,\n valuePropId: ensure0xPrefix(bucket.valuePropId),\n fileCount: bucket.fileCount\n }));\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n async getBucket(bucketId: string, signal?: AbortSignal): Promise<Bucket> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n\n const wire = await this.ctx.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n name: wire.name,\n root: ensure0xPrefix(wire.root),\n isPublic: wire.isPublic,\n sizeBytes: wire.sizeBytes,\n valuePropId: ensure0xPrefix(wire.valuePropId),\n fileCount: wire.fileCount\n };\n }\n\n /** List files/folders under a path for a bucket (root if no path) */\n async getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n\n const wire = await this.ctx.http.get<FileListResponseWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: this.normalizePath(options.path) } } : {})\n });\n\n const filesWire: readonly FileTreeWire[] = \"files\" in wire ? wire.files : [wire.tree];\n const files: FileTree[] = filesWire.map(fixFileTree);\n const tree = files[0];\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n files,\n ...(tree ? { tree } : {})\n } as unknown as FileListResponse;\n }\n}\n", "import {\n assert0xString,\n ensure0xPrefix,\n FileMetadata,\n hexToBytes,\n initWasm,\n parseDate\n} from \"@storagehub-sdk/core\";\nimport { ModuleBase } from \"../base.js\";\nimport type {\n DownloadOptions,\n DownloadResult,\n FileStatus,\n StorageFileInfo,\n UploadOptions,\n UploadReceipt\n} from \"../types.js\";\n\nexport class FilesModule extends ModuleBase {\n /** Get metadata for a file in a bucket by fileKey */\n async getFileInfo(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n signal?: AbortSignal\n ): Promise<StorageFileInfo> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n\n const wire = await this.ctx.http.get<{\n fileKey: string;\n fingerprint: string;\n bucketId: string;\n location: string;\n size: string; // Backend sends as string to avoid precision loss\n isPublic: boolean;\n uploadedAt: string; // ISO string, not Date object\n status: string;\n blockHash: string; // Block hash where file was created\n txHash?: string; // Optional EVM transaction hash\n }>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n fileKey: ensure0xPrefix(wire.fileKey),\n fingerprint: ensure0xPrefix(wire.fingerprint),\n bucketId: ensure0xPrefix(wire.bucketId),\n location: wire.location,\n size: BigInt(wire.size),\n isPublic: wire.isPublic,\n uploadedAt: parseDate(wire.uploadedAt),\n status: wire.status as FileStatus,\n blockHash: ensure0xPrefix(wire.blockHash),\n ...(wire.txHash ? { txHash: ensure0xPrefix(wire.txHash) } : {})\n };\n }\n\n /** Upload a file to a bucket with a specific key */\n async uploadFile(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n fingerprint: `0x${string}`,\n owner: `0x${string}`,\n location: string,\n _options?: UploadOptions\n ): Promise<UploadReceipt> {\n void _options;\n\n assert0xString(bucketId, 32, \"Invalid bucketId: expected 0x-prefixed 32-byte hex\");\n assert0xString(fingerprint, 32, \"Invalid fingerprint: expected 0x-prefixed 32-byte hex\");\n assert0xString(owner, 20, \"Invalid owner: expected 0x-prefixed 20-byte hex\");\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = await 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 // 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 = 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.ctx.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 /** Download a file by key */\n async downloadFile(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\n const headers = await this.withAuth(baseHeaders);\n\n try {\n const res = await this.ctx.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 } catch (error) {\n // Handle HTTP errors by returning them as a DownloadResult with the error status\n if (this.isHttpError(error)) {\n return {\n stream: this.createEmptyStream(),\n status: error.status,\n contentType: null,\n contentRange: null,\n contentLength: null\n };\n }\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n\n /**\n * Generate an absolute download URL\n *\n * @param bucketId - Bucket id (required to fetch metadata).\n * @param fileKey - File key to download.\n * @param signal - Optional AbortSignal for request cancellation.\n */\n async getDownloadUrl(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n signal?: AbortSignal\n ): Promise<string> {\n const bucketIdHex = ensure0xPrefix(bucketId);\n const fileKeyHex = ensure0xPrefix(fileKey);\n\n let info: StorageFileInfo;\n try {\n info = await this.getFileInfo(bucketIdHex, fileKeyHex, signal);\n } catch (error) {\n if (this.isHttpError(error) && error.status === 404) {\n throw new Error(`File not found: ${fileKeyHex}`);\n }\n throw error;\n }\n\n if (!info.isPublic) {\n throw new Error(\n `File is private: ${fileKeyHex}. Direct download URL for private files is not supported yet.`\n );\n }\n\n if (info.status !== \"ready\") {\n throw new Error(`File is not Ready (status=${info.status}): ${fileKeyHex}`);\n }\n\n // Construct the URL\n const baseUrl = this.ctx.config.baseUrl.replace(/\\/$/, \"\");\n const downloadPath = `/download/${encodeURIComponent(fileKeyHex)}`;\n return new URL(baseUrl + downloadPath).toString();\n }\n\n // Helpers\n private isHttpError(error: unknown): error is { status: number } {\n return (\n error !== null &&\n typeof error === \"object\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n }\n\n private createEmptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n }\n });\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 formFileMetadata(\n owner: `0x${string}`,\n bucketId: `0x${string}`,\n location: string,\n fingerprint: `0x${string}`,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = hexToBytes(owner);\n const bucketIdBytes = hexToBytes(bucketId);\n const fingerprintBytes = hexToBytes(fingerprint);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprintBytes);\n }\n\n private async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n}\n", "import { ModuleBase } from \"../base.js\";\nimport type {\n HealthStatus,\n InfoResponse,\n PaymentStreamsResponse,\n StatsResponse,\n ValueProp\n} from \"../types.js\";\nimport { ensure0xPrefix } from \"@storagehub-sdk/core\";\n\nexport class InfoModule extends ModuleBase {\n getHealth(signal?: AbortSignal): Promise<HealthStatus> {\n return this.ctx.http.get<HealthStatus>(\"/health\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get general MSP information */\n async getInfo(signal?: AbortSignal): Promise<InfoResponse> {\n const wire = await this.ctx.http.get<{\n client: string;\n version: string;\n mspId: string;\n multiaddresses: string[];\n ownerAccount: string;\n paymentAccount: string;\n status: string;\n activeSince: number;\n uptime: string;\n }>(\"/info\", {\n ...(signal ? { signal } : {})\n });\n\n return {\n client: wire.client,\n version: wire.version,\n mspId: ensure0xPrefix(wire.mspId),\n multiaddresses: wire.multiaddresses,\n ownerAccount: ensure0xPrefix(wire.ownerAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n paymentAccount: ensure0xPrefix(wire.paymentAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n status: wire.status,\n activeSince: wire.activeSince,\n uptime: wire.uptime\n };\n }\n\n /** Get MSP statistics */\n getStats(signal?: AbortSignal): Promise<StatsResponse> {\n return this.ctx.http.get<StatsResponse>(\"/stats\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(signal?: AbortSignal): Promise<ValueProp[]> {\n return this.ctx.http.get<ValueProp[]>(\"/value-props\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get payment streams for current authenticated user */\n async getPaymentStreams(signal?: AbortSignal): Promise<PaymentStreamsResponse> {\n const headers = await this.withAuth();\n return this.ctx.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["HttpClient", "getAddress", "ModuleBase", "ctx", "sessionProviderRef", "headers", "token", "path", "_m", "offset", "DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS", "DEFAULT_SIWE_VERIFY_BACKOFF_MS", "AuthModule", "ModuleBase", "address", "chainId", "domain", "uri", "signal", "message", "signature", "wallet", "retry", "account", "methodName", "resolvedAddress", "getAddress", "lastError", "attemptIndex", "err", "ms", "resolve", "headers", "ensure0xPrefix", "parseDate", "fixFileTree", "item", "BucketsModule", "ModuleBase", "signal", "headers", "bucket", "bucketId", "path", "wire", "options", "files", "tree", "assert0xString", "ensure0xPrefix", "FileMetadata", "hexToBytes", "initWasm", "parseDate", "FilesModule", "ModuleBase", "bucketId", "fileKey", "signal", "headers", "path", "wire", "ensure0xPrefix", "parseDate", "file", "fingerprint", "owner", "location", "_options", "assert0xString", "initWasm", "backendPath", "authHeaders", "fileBlob", "fileSize", "metadata", "computedFileKey", "expectedFileKeyBytes", "hexToBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "options", "baseHeaders", "start", "end", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "error", "bucketIdHex", "fileKeyHex", "info", "baseUrl", "downloadPath", "controller", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "size", "ownerBytes", "bucketIdBytes", "fingerprintBytes", "locationBytes", "FileMetadata", "fileMetadata", "ensure0xPrefix", "InfoModule", "ModuleBase", "signal", "wire", "headers", "MspClient", "_MspClient", "ModuleBase", "config", "http", "sessionProviderRef", "context", "AuthModule", "BucketsModule", "FilesModule", "InfoModule", "sessionProvider", "HttpClient"]
|
|
7
7
|
}
|
package/dist/index.node.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{HttpClient as
|
|
1
|
+
import{HttpClient as L}from"@storagehub-sdk/core";import{getAddress as M}from"viem";var p=class{ctx;sessionProviderRef;constructor(e,t){this.ctx=e,this.sessionProviderRef=t}async withAuth(e){let n=(await this.sessionProviderRef.current())?.token;return n?e?{...e,Authorization:`Bearer ${n}`}:{Authorization:`Bearer ${n}`}:e}normalizePath(e){return e.replace(/^\/+|\/{2,}/g,(t,n)=>n===0?"":"/")}};var B=10,T=100,y=class extends p{getNonce(e,t,n,s,i){return this.ctx.http.post("/auth/nonce",{body:{address:e,chainId:t,domain:n,uri:s},headers:{"Content-Type":"application/json"},...i?{signal:i}:{}})}getMessage(e,t,n,s){return this.ctx.http.post("/auth/message",{body:{address:e,chainId:t,uri:n},headers:{"Content-Type":"application/json"},...s?{signal:s}:{}})}async verify(e,t,n){return await this.ctx.http.post("/auth/verify",{body:{message:e,signature:t},headers:{"Content-Type":"application/json"},...n?{signal:n}:{}})}async SIWE(e,t,n,s=B,i){let{account:r,address:a,chainId:o}=await this.resolveAccount(e,"SIWE"),{message:l}=await this.getNonce(a,o,t,n,i);return this.signAndVerifyWithRetry(e,r,l,s,i,"SIWE")}async SIWX(e,t,n=B,s){let{account:i,address:r,chainId:a}=await this.resolveAccount(e,"SIWX"),{message:o}=await this.getMessage(r,a,t,s);return this.signAndVerifyWithRetry(e,i,o,n,s,"SIWX")}async resolveAccount(e,t){let n=e.account,s=typeof n=="string"?n:n?.address;if(!s||!n)throw new Error(`Wallet client has no active account; set wallet.account before calling ${t}`);let i=M(s),r=await e.getChainId();return{account:n,address:i,chainId:r}}async signAndVerifyWithRetry(e,t,n,s,i,r){let a=await e.signMessage({account:t,message:n}),o;for(let l=0;l<s;l++)try{return await this.verify(n,a,i)}catch(u){o=u,await this.delay(T)}throw o instanceof Error?o:new Error(`${r} verification failed`)}async delay(e){await new Promise(t=>setTimeout(t,e))}async getProfile(e){let t=await this.withAuth();return this.ctx.http.get("/auth/profile",{...t?{headers:t}:{},...e?{signal:e}:{}})}};import{ensure0xPrefix as d,parseDate as H}from"@storagehub-sdk/core";function C(c){return c.type==="file"?{name:c.name,type:c.type,sizeBytes:c.sizeBytes,fileKey:d(c.fileKey),status:c.status,uploadedAt:H(c.uploadedAt)}:{name:c.name,type:c.type,children:(c.children??[]).map(C)}}var f=class extends p{async listBuckets(e){let t=await this.withAuth();return(await this.ctx.http.get("/buckets",{...t?{headers:t}:{},...e?{signal:e}:{}})).map(s=>({bucketId:d(s.bucketId),name:s.name,root:d(s.root),isPublic:s.isPublic,sizeBytes:s.sizeBytes,valuePropId:d(s.valuePropId),fileCount:s.fileCount}))}async getBucket(e,t){let n=await this.withAuth(),s=`/buckets/${encodeURIComponent(e)}`,i=await this.ctx.http.get(s,{...n?{headers:n}:{},...t?{signal:t}:{}});return{bucketId:d(i.bucketId),name:i.name,root:d(i.root),isPublic:i.isPublic,sizeBytes:i.sizeBytes,valuePropId:d(i.valuePropId),fileCount:i.fileCount}}async getFiles(e,t){let n=await this.withAuth(),s=`/buckets/${encodeURIComponent(e)}/files`,i=await this.ctx.http.get(s,{...n?{headers:n}:{},...t?.signal?{signal:t.signal}:{},...t?.path?{query:{path:this.normalizePath(t.path)}}:{}}),a=("files"in i?i.files:[i.tree]).map(C),o=a[0];return{bucketId:d(i.bucketId),files:a,...o?{tree:o}:{}}}};import{assert0xString as A,ensure0xPrefix as h,FileMetadata as E,hexToBytes as g,initWasm as I,parseDate as z}from"@storagehub-sdk/core";var b=class extends p{async getFileInfo(e,t,n){let s=await this.withAuth(),i=`/buckets/${encodeURIComponent(e)}/info/${encodeURIComponent(t)}`,r=await this.ctx.http.get(i,{...s?{headers:s}:{},...n?{signal:n}:{}});return{fileKey:h(r.fileKey),fingerprint:h(r.fingerprint),bucketId:h(r.bucketId),location:r.location,size:BigInt(r.size),isPublic:r.isPublic,uploadedAt:z(r.uploadedAt),status:r.status,blockHash:h(r.blockHash),...r.txHash?{txHash:h(r.txHash)}:{}}}async uploadFile(e,t,n,s,i,r,a){A(e,32,"Invalid bucketId: expected 0x-prefixed 32-byte hex"),A(s,32,"Invalid fingerprint: expected 0x-prefixed 32-byte hex"),A(i,20,"Invalid owner: expected 0x-prefixed 20-byte hex"),await I();let o=`/buckets/${encodeURIComponent(e)}/upload/${encodeURIComponent(t)}`,l=await this.withAuth(),u=await this.coerceToFormPart(n),x=u.size,v=await this.formFileMetadata(i,e,r,s,BigInt(x)),S=await this.computeFileKey(v),P=g(t);if(S.length!==P.length||!S.every((W,$)=>W===P[$]))throw new Error(`Computed file key ${S.toString()} does not match provided file key ${P.toString()}`);let k=v.encode(),m=new FormData,U=new Blob([new Uint8Array(k)],{type:"application/octet-stream"});return m.append("file_metadata",U,"file_metadata"),m.append("file",u,"file"),await this.ctx.http.put(o,l?{body:m,headers:l}:{body:m})}async downloadFile(e,t){let n=`/download/${encodeURIComponent(e)}`,s={Accept:"*/*"};if(t?.range){let{start:r,end:a}=t.range,o=`bytes=${r}-${a??""}`;s.Range=o}let i=await this.withAuth(s);try{let r=await this.ctx.http.getRaw(n,{...i?{headers:i}:{},...t?.signal?{signal:t.signal}:{}});if(!r.body)throw new Error("Response body is null - unable to create stream");let a=r.headers.get("content-type"),o=r.headers.get("content-range"),l=r.headers.get("content-length"),u=l!==null?Number(l):void 0,x=typeof u=="number"&&Number.isFinite(u)?u:null;return{stream:r.body,status:r.status,contentType:a,contentRange:o,contentLength:x}}catch(r){if(this.isHttpError(r))return{stream:this.createEmptyStream(),status:r.status,contentType:null,contentRange:null,contentLength:null};throw r}}async getDownloadUrl(e,t,n){let s=h(e),i=h(t),r;try{r=await this.getFileInfo(s,i,n)}catch(l){throw this.isHttpError(l)&&l.status===404?new Error(`File not found: ${i}`):l}if(!r.isPublic)throw new Error(`File is private: ${i}. Direct download URL for private files is not supported yet.`);if(r.status!=="ready")throw new Error(`File is not Ready (status=${r.status}): ${i}`);let a=this.ctx.config.baseUrl.replace(/\/$/,""),o=`/download/${encodeURIComponent(i)}`;return new URL(a+o).toString()}isHttpError(e){return e!==null&&typeof e=="object"&&"status"in e&&typeof e.status=="number"}createEmptyStream(){return new ReadableStream({start(e){e.close()}})}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=[],s=0;try{for(;;){let{done:a,value:o}=await t.read();if(a)break;o&&(n.push(o),s+=o.length)}}finally{t.releaseLock()}let i=new Uint8Array(s),r=0;for(let a of n)i.set(a,r),r+=a.length;return new Blob([i],{type:"application/octet-stream"})}return new Blob([e],{type:"application/octet-stream"})}async formFileMetadata(e,t,n,s,i){let r=g(e),a=g(t),o=g(s),l=new TextEncoder().encode(n);return await I(),new E(r,a,l,i,o)}async computeFileKey(e){return await I(),e.getFileKey()}};import{ensure0xPrefix as R}from"@storagehub-sdk/core";var w=class extends p{getHealth(e){return this.ctx.http.get("/health",{...e?{signal:e}:{}})}async getInfo(e){let t=await this.ctx.http.get("/info",{...e?{signal:e}:{}});return{client:t.client,version:t.version,mspId:R(t.mspId),multiaddresses:t.multiaddresses,ownerAccount:R(t.ownerAccount),paymentAccount:R(t.paymentAccount),status:t.status,activeSince:t.activeSince,uptime:t.uptime}}getStats(e){return this.ctx.http.get("/stats",{...e?{signal:e}:{}})}getValuePropositions(e){return this.ctx.http.get("/value-props",{...e?{signal:e}:{}})}async getPaymentStreams(e){let t=await this.withAuth();return this.ctx.http.get("/payment_streams",{...t?{headers:t}:{},...e?{signal:e}:{}})}};var F=class c extends p{config;context;auth;buckets;files;info;constructor(e,t,n){let s={config:e,http:t};super(s,n),this.config=e,this.context=s,this.auth=new y(this.context,n),this.buckets=new f(this.context,n),this.files=new b(this.context,n),this.info=new w(this.context,n)}static async connect(e,t=async()=>{}){if(!e?.baseUrl)throw new Error("MspClient.connect: baseUrl is required");let n=new L({baseUrl:e.baseUrl,...e.timeoutMs!==void 0&&{timeoutMs:e.timeoutMs},...e.defaultHeaders!==void 0&&{defaultHeaders:e.defaultHeaders},...e.fetchImpl!==void 0&&{fetchImpl:e.fetchImpl}}),s={current:t};return new c(e,n,s)}setSessionProvider(e){this.sessionProviderRef.current=e}};export{F as MspClient};
|
|
2
2
|
//# sourceMappingURL=index.node.js.map
|
package/dist/index.node.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/MspClient.ts", "../src/modules/auth.ts", "../src/base.ts", "../src/modules/buckets.ts", "../src/modules/files.ts", "../src/modules/info.ts"],
|
|
4
|
-
"sourcesContent": ["import type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { HttpClient } from \"@storagehub-sdk/core\";\nimport type { MspClientContext } from \"./context.js\";\nimport { AuthModule } from \"./modules/auth.js\";\nimport { BucketsModule } from \"./modules/buckets.js\";\nimport { ModuleBase } from \"./base.js\";\nimport { FilesModule } from \"./modules/files.js\";\nimport { InfoModule } from \"./modules/info.js\";\nimport type { SessionProvider } from \"./types.js\";\n\nexport class MspClient extends ModuleBase {\n public readonly config: HttpClientConfig;\n private readonly context: MspClientContext;\n public readonly auth: AuthModule;\n public readonly buckets: BucketsModule;\n public readonly files: FilesModule;\n public readonly info: InfoModule;\n\n private constructor(\n config: HttpClientConfig,\n http: HttpClient,\n sessionProviderRef: { current: SessionProvider }\n ) {\n const context: MspClientContext = { config, http };\n super(context, sessionProviderRef);\n this.config = config;\n this.context = context;\n this.auth = new AuthModule(this.context, sessionProviderRef);\n this.buckets = new BucketsModule(this.context, sessionProviderRef);\n this.files = new FilesModule(this.context, sessionProviderRef);\n this.info = new InfoModule(this.context, sessionProviderRef);\n }\n\n static async connect(\n config: HttpClientConfig,\n sessionProvider: SessionProvider = async () => undefined\n ): 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 // Create a shared reference object\n const sessionProviderRef = { current: sessionProvider };\n return new MspClient(config, http, sessionProviderRef);\n }\n\n /**\n * Updates the session provider for this client and all its modules.\n * This allows updating authentication after the client has been created.\n *\n * @param sessionProvider - The new session provider function.\n */\n setSessionProvider(sessionProvider: SessionProvider): void {\n this.sessionProviderRef.current = sessionProvider;\n }\n}\n", "import type { NonceResponse, Session, UserInfo } from \"../types.js\";\nimport { getAddress, type WalletClient } from \"viem\";\nimport { ModuleBase } from \"../base.js\";\n\nconst DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS = 10;\nconst DEFAULT_SIWE_VERIFY_BACKOFF_MS = 100;\n\nexport class AuthModule extends ModuleBase {\n /**\n * Request a nonce (challenge message) for Sign-In with Ethereum (SIWE).\n *\n * **Advanced use only:** Most users should use the `SIWE()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes). You must call `verify()` with a valid signature before expiration.\n *\n * @param address - The Ethereum address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the SIWE challenge message to be signed.\n */\n public getNonce(\n address: string,\n chainId: number,\n domain: string,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/nonce\", {\n body: {\n address,\n chainId,\n domain,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Request a message (challenge) for Sign-In with X (SIWX) using CAIP-122 standard.\n *\n * **Advanced use only:** Most users should use the `SIWX()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * This method follows the CAIP-122 standard for chain-agnostic authentication.\n * The message uses CAIP-10 format for addresses (e.g., `eip155:55931:0x...`).\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes).\n * You must call `verify()` with a valid signature before expiration.\n *\n * **Note:** According to CAIP-122, the domain is extracted from the URI automatically.\n * You do not need to provide the domain separately - it will be extracted from the URI.\n *\n * @param address - The blockchain address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the CAIP-122 challenge message to be signed.\n */\n public getMessage(\n address: string,\n chainId: number,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/message\", {\n body: {\n address,\n chainId,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Verify a Sign-In signature (works with both SIWE and SIWX/CAIP-122 messages).\n *\n * **Advanced use only:** Most users should use the `SIWE()` or `SIWX()` methods instead, which handle the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function passed to `MspClient.connect()`.\n * The session is not automatically persisted - you are responsible for managing session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * @param message - The challenge message received from `getNonce()` (SIWE) or `getMessage()` (CAIP-122).\n * @param signature - The signature of the message signed by the user's wallet.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n public async verify(message: string, signature: string, signal?: AbortSignal): Promise<Session> {\n const session = await this.ctx.http.post<Session>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n\n return session;\n }\n\n /**\n * Complete Sign-In with Ethereum (SIWE) authentication flow using a `WalletClient`.\n *\n * This is the recommended method for authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a nonce, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWE(\n wallet: WalletClient,\n domain: string,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWE\");\n const { message } = await this.getNonce(address, chainId, domain, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWE\");\n }\n\n /**\n * Complete Sign-In with X (SIWX) authentication flow using CAIP-122 standard and a `WalletClient`.\n *\n * This is the recommended method for CAIP-122 authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a CAIP-122 message, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * **CAIP-122:** Unlike SIWE, this method does not require a `domain` parameter. The domain is automatically extracted\n * from the `uri` parameter on the backend per CAIP-122 specification.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWX(\n wallet: WalletClient,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWX\");\n const { message } = await this.getMessage(address, chainId, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWX\");\n }\n\n /**\n * Resolves and validates the account from a WalletClient.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param methodName - The name of the calling method (for error messages).\n * @returns An object containing the account, checksummed address, and chainId.\n * @throws Error if the wallet has no active account.\n */\n private async resolveAccount(\n wallet: WalletClient,\n methodName: string\n ): Promise<{ account: NonNullable<WalletClient[\"account\"]>; address: string; chainId: number }> {\n const account = wallet.account;\n const resolvedAddress = typeof account === \"string\" ? account : account?.address;\n if (!resolvedAddress || !account) {\n throw new Error(\n `Wallet client has no active account; set wallet.account before calling ${methodName}`\n );\n }\n const address = getAddress(resolvedAddress);\n const chainId = await wallet.getChainId();\n return { account, address, chainId };\n }\n\n /**\n * Signs a message and verifies it with retry logic.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param account - The account to sign with.\n * @param message - The message to sign.\n * @param retry - Number of retry attempts for verification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @param methodName - The name of the calling method (for error messages).\n * @returns A promise resolving to a Session object.\n */\n private async signAndVerifyWithRetry(\n wallet: WalletClient,\n account: NonNullable<WalletClient[\"account\"]>,\n message: string,\n retry: number,\n signal: AbortSignal | undefined,\n methodName: string\n ): Promise<Session> {\n const signature = await wallet.signMessage({ account, message });\n\n // TODO: remove the retry logic once the backend is fixed.\n let lastError: unknown;\n for (let attemptIndex = 0; attemptIndex < retry; attemptIndex++) {\n try {\n return await this.verify(message, signature, signal);\n } catch (err) {\n lastError = err;\n await this.delay(DEFAULT_SIWE_VERIFY_BACKOFF_MS);\n }\n }\n throw lastError instanceof Error ? lastError : new Error(`${methodName} verification failed`);\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Fetch authenticated user's profile.\n * - Requires valid `session` (Authorization header added automatically).\n */\n async getProfile(signal?: AbortSignal): Promise<UserInfo> {\n const headers = await this.withAuth();\n return this.ctx.http.get<UserInfo>(\"/auth/profile\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n", "import type { MspClientContext } from \"./context.js\";\nimport type { SessionProvider } from \"./types.js\";\n\n/**\n * Shared reference to sessionProvider so all modules use the same instance.\n */\ntype SessionProviderRef = { current: SessionProvider };\n\nexport abstract class ModuleBase {\n protected readonly ctx: MspClientContext;\n protected readonly sessionProviderRef: SessionProviderRef;\n\n constructor(ctx: MspClientContext, sessionProviderRef: SessionProviderRef) {\n this.ctx = ctx;\n this.sessionProviderRef = sessionProviderRef;\n }\n\n protected async withAuth(\n headers?: Record<string, string>\n ): Promise<Record<string, string> | undefined> {\n const session = await this.sessionProviderRef.current();\n const token = session?.token;\n if (!token) return headers;\n return headers\n ? { ...headers, Authorization: `Bearer ${token}` }\n : { Authorization: `Bearer ${token}` };\n }\n\n /**\n * Normalize a user-provided path for HTTP query usage.\n * - Removes all leading '/' characters to avoid double slashes in URLs.\n * - Collapses any repeated slashes in the middle or at the end to a single '/'.\n * Examples:\n * \"/foo/bar\" -> \"foo/bar\"\n * \"///docs\" -> \"docs\"\n * \"foo//bar\" -> \"foo/bar\"\n * \"///a//b///\" -> \"a/b/\"\n * \"foo/bar\" -> \"foo/bar\" (unchanged)\n * \"/\" -> \"\"\n */\n protected normalizePath(path: string): string {\n // Drop leading slashes (offset === 0), collapse others to '/'\n return path.replace(/^\\/+|\\/{2,}/g, (_m, offset: number) => (offset === 0 ? \"\" : \"/\"));\n }\n}\n", "import type { Bucket, FileListResponse, GetFilesOptions, FileTree, FileStatus } from \"../types.js\";\nimport { ModuleBase } from \"../base.js\";\nimport { ensure0xPrefix, parseDate } from \"@storagehub-sdk/core\";\n\n// Wire types received from backend JSON responses\ntype FileTreeWireFile = {\n name: string;\n type: \"file\";\n sizeBytes: number;\n fileKey: string; // may lack 0x\n status: FileStatus;\n uploadedAt: string; // ISO timestamp\n};\n\ntype FileTreeWireFolder = {\n name: string;\n type: \"folder\";\n children?: readonly FileTreeWire[];\n};\n\ntype FileTreeWire = FileTreeWireFile | FileTreeWireFolder;\n\ntype FileListResponseWire =\n | { bucketId: string; files: readonly FileTreeWire[] }\n | { bucketId: string; tree: FileTreeWireFolder };\n\n/** Recursively fix hex prefixes in FileTree structures */\nfunction fixFileTree(item: FileTreeWire): FileTree {\n if (item.type === \"file\") {\n return {\n name: item.name,\n type: item.type,\n sizeBytes: item.sizeBytes,\n fileKey: ensure0xPrefix(item.fileKey),\n status: item.status,\n uploadedAt: parseDate(item.uploadedAt)\n };\n }\n return {\n name: item.name,\n type: item.type,\n children: (item.children ?? []).map(fixFileTree)\n };\n}\n\nexport class BucketsModule extends ModuleBase {\n /** List all buckets for the current authenticated user */\n async listBuckets(signal?: AbortSignal): Promise<Bucket[]> {\n const headers = await this.withAuth();\n const wire = await this.ctx.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return wire.map((bucket: Bucket) => ({\n bucketId: ensure0xPrefix(bucket.bucketId),\n name: bucket.name,\n root: ensure0xPrefix(bucket.root),\n isPublic: bucket.isPublic,\n sizeBytes: bucket.sizeBytes,\n valuePropId: ensure0xPrefix(bucket.valuePropId),\n fileCount: bucket.fileCount\n }));\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n async getBucket(bucketId: string, signal?: AbortSignal): Promise<Bucket> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n\n const wire = await this.ctx.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n name: wire.name,\n root: ensure0xPrefix(wire.root),\n isPublic: wire.isPublic,\n sizeBytes: wire.sizeBytes,\n valuePropId: ensure0xPrefix(wire.valuePropId),\n fileCount: wire.fileCount\n };\n }\n\n /** List files/folders under a path for a bucket (root if no path) */\n async getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n\n const wire = await this.ctx.http.get<FileListResponseWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: this.normalizePath(options.path) } } : {})\n });\n\n const filesWire: readonly FileTreeWire[] = \"files\" in wire ? wire.files : [wire.tree];\n const files: FileTree[] = filesWire.map(fixFileTree);\n const tree = files[0];\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n files,\n ...(tree ? { tree } : {})\n } as unknown as FileListResponse;\n }\n}\n", "import {\n ensure0xPrefix,\n FileMetadata,\n FileTrie,\n hexToBytes,\n initWasm,\n parseDate\n} from \"@storagehub-sdk/core\";\nimport { ModuleBase } from \"../base.js\";\nimport type {\n DownloadOptions,\n DownloadResult,\n FileStatus,\n StorageFileInfo,\n UploadOptions,\n UploadReceipt\n} from \"../types.js\";\n\nexport class FilesModule extends ModuleBase {\n /** Get metadata for a file in a bucket by fileKey */\n async getFileInfo(\n bucketId: string,\n fileKey: string,\n signal?: AbortSignal\n ): Promise<StorageFileInfo> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n\n const wire = await this.ctx.http.get<{\n fileKey: string;\n fingerprint: string;\n bucketId: string;\n location: string;\n size: string; // Backend sends as string to avoid precision loss\n isPublic: boolean;\n uploadedAt: string; // ISO string, not Date object\n status: string;\n blockHash: string; // Block hash where file was created\n txHash?: string; // Optional EVM transaction hash\n }>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n fileKey: ensure0xPrefix(wire.fileKey),\n fingerprint: ensure0xPrefix(wire.fingerprint),\n bucketId: ensure0xPrefix(wire.bucketId),\n location: wire.location,\n size: BigInt(wire.size),\n isPublic: wire.isPublic,\n uploadedAt: parseDate(wire.uploadedAt),\n status: wire.status as FileStatus,\n blockHash: ensure0xPrefix(wire.blockHash),\n ...(wire.txHash ? { txHash: ensure0xPrefix(wire.txHash) } : {})\n };\n }\n\n /** Upload a file to a bucket with a specific key */\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 = await 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 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 = 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.ctx.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 /** Download a file by key */\n async downloadFile(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\n const headers = await this.withAuth(baseHeaders);\n\n try {\n const res = await this.ctx.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 } catch (error) {\n // Handle HTTP errors by returning them as a DownloadResult with the error status\n if (this.isHttpError(error)) {\n return {\n stream: this.createEmptyStream(),\n status: error.status,\n contentType: null,\n contentRange: null,\n contentLength: null\n };\n }\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n\n // Helpers\n private isHttpError(error: unknown): error is { status: number } {\n return (\n error !== null &&\n typeof error === \"object\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n }\n\n private createEmptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n }\n });\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 private async formFileMetadata(\n owner: string,\n bucketId: string,\n location: string,\n fingerprint: Uint8Array,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = hexToBytes(owner);\n const bucketIdBytes = hexToBytes(bucketId);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprint);\n }\n\n private async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n}\n", "import { ModuleBase } from \"../base.js\";\nimport type {\n HealthStatus,\n InfoResponse,\n PaymentStreamsResponse,\n StatsResponse,\n ValueProp\n} from \"../types.js\";\nimport { ensure0xPrefix } from \"@storagehub-sdk/core\";\n\nexport class InfoModule extends ModuleBase {\n getHealth(signal?: AbortSignal): Promise<HealthStatus> {\n return this.ctx.http.get<HealthStatus>(\"/health\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get general MSP information */\n async getInfo(signal?: AbortSignal): Promise<InfoResponse> {\n const wire = await this.ctx.http.get<{\n client: string;\n version: string;\n mspId: string;\n multiaddresses: string[];\n ownerAccount: string;\n paymentAccount: string;\n status: string;\n activeSince: number;\n uptime: string;\n }>(\"/info\", {\n ...(signal ? { signal } : {})\n });\n\n return {\n client: wire.client,\n version: wire.version,\n mspId: ensure0xPrefix(wire.mspId),\n multiaddresses: wire.multiaddresses,\n ownerAccount: ensure0xPrefix(wire.ownerAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n paymentAccount: ensure0xPrefix(wire.paymentAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n status: wire.status,\n activeSince: wire.activeSince,\n uptime: wire.uptime\n };\n }\n\n /** Get MSP statistics */\n getStats(signal?: AbortSignal): Promise<StatsResponse> {\n return this.ctx.http.get<StatsResponse>(\"/stats\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(signal?: AbortSignal): Promise<ValueProp[]> {\n return this.ctx.http.get<ValueProp[]>(\"/value-props\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get payment streams for current authenticated user */\n async getPaymentStreams(signal?: AbortSignal): Promise<PaymentStreamsResponse> {\n const headers = await this.withAuth();\n return this.ctx.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["HttpClient", "getAddress", "ModuleBase", "ctx", "sessionProviderRef", "headers", "token", "path", "_m", "offset", "DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS", "DEFAULT_SIWE_VERIFY_BACKOFF_MS", "AuthModule", "ModuleBase", "address", "chainId", "domain", "uri", "signal", "message", "signature", "wallet", "retry", "account", "methodName", "resolvedAddress", "getAddress", "lastError", "attemptIndex", "err", "ms", "resolve", "headers", "ensure0xPrefix", "parseDate", "fixFileTree", "item", "BucketsModule", "ModuleBase", "signal", "headers", "bucket", "bucketId", "path", "wire", "options", "files", "tree", "
|
|
4
|
+
"sourcesContent": ["import type { HttpClientConfig } from \"@storagehub-sdk/core\";\nimport { HttpClient } from \"@storagehub-sdk/core\";\nimport type { MspClientContext } from \"./context.js\";\nimport { AuthModule } from \"./modules/auth.js\";\nimport { BucketsModule } from \"./modules/buckets.js\";\nimport { ModuleBase } from \"./base.js\";\nimport { FilesModule } from \"./modules/files.js\";\nimport { InfoModule } from \"./modules/info.js\";\nimport type { SessionProvider } from \"./types.js\";\n\nexport class MspClient extends ModuleBase {\n public readonly config: HttpClientConfig;\n private readonly context: MspClientContext;\n public readonly auth: AuthModule;\n public readonly buckets: BucketsModule;\n public readonly files: FilesModule;\n public readonly info: InfoModule;\n\n private constructor(\n config: HttpClientConfig,\n http: HttpClient,\n sessionProviderRef: { current: SessionProvider }\n ) {\n const context: MspClientContext = { config, http };\n super(context, sessionProviderRef);\n this.config = config;\n this.context = context;\n this.auth = new AuthModule(this.context, sessionProviderRef);\n this.buckets = new BucketsModule(this.context, sessionProviderRef);\n this.files = new FilesModule(this.context, sessionProviderRef);\n this.info = new InfoModule(this.context, sessionProviderRef);\n }\n\n static async connect(\n config: HttpClientConfig,\n sessionProvider: SessionProvider = async () => undefined\n ): 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 // Create a shared reference object\n const sessionProviderRef = { current: sessionProvider };\n return new MspClient(config, http, sessionProviderRef);\n }\n\n /**\n * Updates the session provider for this client and all its modules.\n * This allows updating authentication after the client has been created.\n *\n * @param sessionProvider - The new session provider function.\n */\n setSessionProvider(sessionProvider: SessionProvider): void {\n this.sessionProviderRef.current = sessionProvider;\n }\n}\n", "import type { NonceResponse, Session, UserInfo } from \"../types.js\";\nimport { getAddress, type WalletClient } from \"viem\";\nimport { ModuleBase } from \"../base.js\";\n\nconst DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS = 10;\nconst DEFAULT_SIWE_VERIFY_BACKOFF_MS = 100;\n\nexport class AuthModule extends ModuleBase {\n /**\n * Request a nonce (challenge message) for Sign-In with Ethereum (SIWE).\n *\n * **Advanced use only:** Most users should use the `SIWE()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes). You must call `verify()` with a valid signature before expiration.\n *\n * @param address - The Ethereum address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the SIWE challenge message to be signed.\n */\n public getNonce(\n address: string,\n chainId: number,\n domain: string,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/nonce\", {\n body: {\n address,\n chainId,\n domain,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Request a message (challenge) for Sign-In with X (SIWX) using CAIP-122 standard.\n *\n * **Advanced use only:** Most users should use the `SIWX()` method instead, which handles the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * This method follows the CAIP-122 standard for chain-agnostic authentication.\n * The message uses CAIP-10 format for addresses (e.g., `eip155:55931:0x...`).\n *\n * **Important:** The challenge message expires after a short time (typically 5 minutes).\n * You must call `verify()` with a valid signature before expiration.\n *\n * **Note:** According to CAIP-122, the domain is extracted from the URI automatically.\n * You do not need to provide the domain separately - it will be extracted from the URI.\n *\n * @param address - The blockchain address requesting authentication (checksummed format recommended).\n * @param chainId - The chain ID the user is connected to.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to the CAIP-122 challenge message to be signed.\n */\n public getMessage(\n address: string,\n chainId: number,\n uri: string,\n signal?: AbortSignal\n ): Promise<NonceResponse> {\n return this.ctx.http.post<NonceResponse>(\"/auth/message\", {\n body: {\n address,\n chainId,\n uri\n },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n }\n\n /**\n * Verify a Sign-In signature (works with both SIWE and SIWX/CAIP-122 messages).\n *\n * **Advanced use only:** Most users should use the `SIWE()` or `SIWX()` methods instead, which handle the complete authentication flow automatically. This method is exposed only for custom authentication flows.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function passed to `MspClient.connect()`.\n * The session is not automatically persisted - you are responsible for managing session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * @param message - The challenge message received from `getNonce()` (SIWE) or `getMessage()` (CAIP-122).\n * @param signature - The signature of the message signed by the user's wallet.\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n public async verify(message: string, signature: string, signal?: AbortSignal): Promise<Session> {\n const session = await this.ctx.http.post<Session>(\"/auth/verify\", {\n body: { message, signature },\n headers: { \"Content-Type\": \"application/json\" },\n ...(signal ? { signal } : {})\n });\n\n return session;\n }\n\n /**\n * Complete Sign-In with Ethereum (SIWE) authentication flow using a `WalletClient`.\n *\n * This is the recommended method for authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a nonce, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param domain - The domain (host[:port]) for the SIWE message (e.g., \"datahaven.app\" or \"localhost:3000\").\n * @param uri - The full URI of your application (e.g., \"https://datahaven.app\" or \"http://localhost:3000\").\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWE(\n wallet: WalletClient,\n domain: string,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWE\");\n const { message } = await this.getNonce(address, chainId, domain, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWE\");\n }\n\n /**\n * Complete Sign-In with X (SIWX) authentication flow using CAIP-122 standard and a `WalletClient`.\n *\n * This is the recommended method for CAIP-122 authentication. It handles the complete flow automatically:\n * derives the wallet address, fetches a CAIP-122 message, prompts the user to sign the message, verifies the signature,\n * and returns a session token.\n *\n * **Important:** You must store the returned Session object and provide it via the `sessionProvider` function\n * passed to `MspClient.connect()`. The session is not automatically persisted - you are responsible for managing\n * session storage and ensuring your `sessionProvider` returns it for subsequent authenticated requests.\n *\n * **Note:** This method includes automatic retry logic for verification requests (default: 10 attempts with 100ms backoff).\n * The retry behavior can be customized via the `retry` parameter.\n *\n * **CAIP-122:** Unlike SIWE, this method does not require a `domain` parameter. The domain is automatically extracted\n * from the `uri` parameter on the backend per CAIP-122 specification.\n *\n * @param wallet - The Viem `WalletClient` instance. Must have an active account set (`wallet.account`).\n * - Browser wallets (e.g., MetaMask) automatically surface the user-selected address.\n * - Viem/local wallets must set `wallet.account` explicitly before calling.\n * @param uri - The full URI of your dApp (e.g., \"https://datahaven.app\"). This should be the dApp URL, not the MSP API URL.\n * The domain will be automatically extracted from this URI per CAIP-122 specification.\n * @param retry - Number of retry attempts for verification requests (default: 10).\n * @param signal - Optional AbortSignal for request cancellation.\n * @returns A promise resolving to a Session object that you must store and provide via your sessionProvider.\n */\n async SIWX(\n wallet: WalletClient,\n uri: string,\n retry = DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS,\n signal?: AbortSignal\n ): Promise<Session> {\n const { account, address, chainId } = await this.resolveAccount(wallet, \"SIWX\");\n const { message } = await this.getMessage(address, chainId, uri, signal);\n return this.signAndVerifyWithRetry(wallet, account, message, retry, signal, \"SIWX\");\n }\n\n /**\n * Resolves and validates the account from a WalletClient.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param methodName - The name of the calling method (for error messages).\n * @returns An object containing the account, checksummed address, and chainId.\n * @throws Error if the wallet has no active account.\n */\n private async resolveAccount(\n wallet: WalletClient,\n methodName: string\n ): Promise<{ account: NonNullable<WalletClient[\"account\"]>; address: string; chainId: number }> {\n const account = wallet.account;\n const resolvedAddress = typeof account === \"string\" ? account : account?.address;\n if (!resolvedAddress || !account) {\n throw new Error(\n `Wallet client has no active account; set wallet.account before calling ${methodName}`\n );\n }\n const address = getAddress(resolvedAddress);\n const chainId = await wallet.getChainId();\n return { account, address, chainId };\n }\n\n /**\n * Signs a message and verifies it with retry logic.\n *\n * @param wallet - The Viem WalletClient instance.\n * @param account - The account to sign with.\n * @param message - The message to sign.\n * @param retry - Number of retry attempts for verification.\n * @param signal - Optional AbortSignal for request cancellation.\n * @param methodName - The name of the calling method (for error messages).\n * @returns A promise resolving to a Session object.\n */\n private async signAndVerifyWithRetry(\n wallet: WalletClient,\n account: NonNullable<WalletClient[\"account\"]>,\n message: string,\n retry: number,\n signal: AbortSignal | undefined,\n methodName: string\n ): Promise<Session> {\n const signature = await wallet.signMessage({ account, message });\n\n // TODO: remove the retry logic once the backend is fixed.\n let lastError: unknown;\n for (let attemptIndex = 0; attemptIndex < retry; attemptIndex++) {\n try {\n return await this.verify(message, signature, signal);\n } catch (err) {\n lastError = err;\n await this.delay(DEFAULT_SIWE_VERIFY_BACKOFF_MS);\n }\n }\n throw lastError instanceof Error ? lastError : new Error(`${methodName} verification failed`);\n }\n\n private async delay(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Fetch authenticated user's profile.\n * - Requires valid `session` (Authorization header added automatically).\n */\n async getProfile(signal?: AbortSignal): Promise<UserInfo> {\n const headers = await this.withAuth();\n return this.ctx.http.get<UserInfo>(\"/auth/profile\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n", "import type { MspClientContext } from \"./context.js\";\nimport type { SessionProvider } from \"./types.js\";\n\n/**\n * Shared reference to sessionProvider so all modules use the same instance.\n */\ntype SessionProviderRef = { current: SessionProvider };\n\nexport abstract class ModuleBase {\n protected readonly ctx: MspClientContext;\n protected readonly sessionProviderRef: SessionProviderRef;\n\n constructor(ctx: MspClientContext, sessionProviderRef: SessionProviderRef) {\n this.ctx = ctx;\n this.sessionProviderRef = sessionProviderRef;\n }\n\n protected async withAuth(\n headers?: Record<string, string>\n ): Promise<Record<string, string> | undefined> {\n const session = await this.sessionProviderRef.current();\n const token = session?.token;\n if (!token) return headers;\n return headers\n ? { ...headers, Authorization: `Bearer ${token}` }\n : { Authorization: `Bearer ${token}` };\n }\n\n /**\n * Normalize a user-provided path for HTTP query usage.\n * - Removes all leading '/' characters to avoid double slashes in URLs.\n * - Collapses any repeated slashes in the middle or at the end to a single '/'.\n * Examples:\n * \"/foo/bar\" -> \"foo/bar\"\n * \"///docs\" -> \"docs\"\n * \"foo//bar\" -> \"foo/bar\"\n * \"///a//b///\" -> \"a/b/\"\n * \"foo/bar\" -> \"foo/bar\" (unchanged)\n * \"/\" -> \"\"\n */\n protected normalizePath(path: string): string {\n // Drop leading slashes (offset === 0), collapse others to '/'\n return path.replace(/^\\/+|\\/{2,}/g, (_m, offset: number) => (offset === 0 ? \"\" : \"/\"));\n }\n}\n", "import type { Bucket, FileListResponse, GetFilesOptions, FileTree, FileStatus } from \"../types.js\";\nimport { ModuleBase } from \"../base.js\";\nimport { ensure0xPrefix, parseDate } from \"@storagehub-sdk/core\";\n\n// Wire types received from backend JSON responses\ntype FileTreeWireFile = {\n name: string;\n type: \"file\";\n sizeBytes: number;\n fileKey: string; // may lack 0x\n status: FileStatus;\n uploadedAt: string; // ISO timestamp\n};\n\ntype FileTreeWireFolder = {\n name: string;\n type: \"folder\";\n children?: readonly FileTreeWire[];\n};\n\ntype FileTreeWire = FileTreeWireFile | FileTreeWireFolder;\n\ntype FileListResponseWire =\n | { bucketId: string; files: readonly FileTreeWire[] }\n | { bucketId: string; tree: FileTreeWireFolder };\n\n/** Recursively fix hex prefixes in FileTree structures */\nfunction fixFileTree(item: FileTreeWire): FileTree {\n if (item.type === \"file\") {\n return {\n name: item.name,\n type: item.type,\n sizeBytes: item.sizeBytes,\n fileKey: ensure0xPrefix(item.fileKey),\n status: item.status,\n uploadedAt: parseDate(item.uploadedAt)\n };\n }\n return {\n name: item.name,\n type: item.type,\n children: (item.children ?? []).map(fixFileTree)\n };\n}\n\nexport class BucketsModule extends ModuleBase {\n /** List all buckets for the current authenticated user */\n async listBuckets(signal?: AbortSignal): Promise<Bucket[]> {\n const headers = await this.withAuth();\n const wire = await this.ctx.http.get<Bucket[]>(\"/buckets\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return wire.map((bucket: Bucket) => ({\n bucketId: ensure0xPrefix(bucket.bucketId),\n name: bucket.name,\n root: ensure0xPrefix(bucket.root),\n isPublic: bucket.isPublic,\n sizeBytes: bucket.sizeBytes,\n valuePropId: ensure0xPrefix(bucket.valuePropId),\n fileCount: bucket.fileCount\n }));\n }\n\n /** Get a specific bucket's metadata by its bucket ID */\n async getBucket(bucketId: string, signal?: AbortSignal): Promise<Bucket> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}`;\n\n const wire = await this.ctx.http.get<Bucket>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n name: wire.name,\n root: ensure0xPrefix(wire.root),\n isPublic: wire.isPublic,\n sizeBytes: wire.sizeBytes,\n valuePropId: ensure0xPrefix(wire.valuePropId),\n fileCount: wire.fileCount\n };\n }\n\n /** List files/folders under a path for a bucket (root if no path) */\n async getFiles(bucketId: string, options?: GetFilesOptions): Promise<FileListResponse> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/files`;\n\n const wire = await this.ctx.http.get<FileListResponseWire>(path, {\n ...(headers ? { headers } : {}),\n ...(options?.signal ? { signal: options.signal } : {}),\n ...(options?.path ? { query: { path: this.normalizePath(options.path) } } : {})\n });\n\n const filesWire: readonly FileTreeWire[] = \"files\" in wire ? wire.files : [wire.tree];\n const files: FileTree[] = filesWire.map(fixFileTree);\n const tree = files[0];\n return {\n bucketId: ensure0xPrefix(wire.bucketId),\n files,\n ...(tree ? { tree } : {})\n } as unknown as FileListResponse;\n }\n}\n", "import {\n assert0xString,\n ensure0xPrefix,\n FileMetadata,\n hexToBytes,\n initWasm,\n parseDate\n} from \"@storagehub-sdk/core\";\nimport { ModuleBase } from \"../base.js\";\nimport type {\n DownloadOptions,\n DownloadResult,\n FileStatus,\n StorageFileInfo,\n UploadOptions,\n UploadReceipt\n} from \"../types.js\";\n\nexport class FilesModule extends ModuleBase {\n /** Get metadata for a file in a bucket by fileKey */\n async getFileInfo(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n signal?: AbortSignal\n ): Promise<StorageFileInfo> {\n const headers = await this.withAuth();\n const path = `/buckets/${encodeURIComponent(bucketId)}/info/${encodeURIComponent(fileKey)}`;\n\n const wire = await this.ctx.http.get<{\n fileKey: string;\n fingerprint: string;\n bucketId: string;\n location: string;\n size: string; // Backend sends as string to avoid precision loss\n isPublic: boolean;\n uploadedAt: string; // ISO string, not Date object\n status: string;\n blockHash: string; // Block hash where file was created\n txHash?: string; // Optional EVM transaction hash\n }>(path, {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n\n return {\n fileKey: ensure0xPrefix(wire.fileKey),\n fingerprint: ensure0xPrefix(wire.fingerprint),\n bucketId: ensure0xPrefix(wire.bucketId),\n location: wire.location,\n size: BigInt(wire.size),\n isPublic: wire.isPublic,\n uploadedAt: parseDate(wire.uploadedAt),\n status: wire.status as FileStatus,\n blockHash: ensure0xPrefix(wire.blockHash),\n ...(wire.txHash ? { txHash: ensure0xPrefix(wire.txHash) } : {})\n };\n }\n\n /** Upload a file to a bucket with a specific key */\n async uploadFile(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown,\n fingerprint: `0x${string}`,\n owner: `0x${string}`,\n location: string,\n _options?: UploadOptions\n ): Promise<UploadReceipt> {\n void _options;\n\n assert0xString(bucketId, 32, \"Invalid bucketId: expected 0x-prefixed 32-byte hex\");\n assert0xString(fingerprint, 32, \"Invalid fingerprint: expected 0x-prefixed 32-byte hex\");\n assert0xString(owner, 20, \"Invalid owner: expected 0x-prefixed 20-byte hex\");\n\n await initWasm();\n\n const backendPath = `/buckets/${encodeURIComponent(bucketId)}/upload/${encodeURIComponent(fileKey)}`;\n const authHeaders = await 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 // 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 = 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.ctx.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 /** Download a file by key */\n async downloadFile(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\n const headers = await this.withAuth(baseHeaders);\n\n try {\n const res = await this.ctx.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 } catch (error) {\n // Handle HTTP errors by returning them as a DownloadResult with the error status\n if (this.isHttpError(error)) {\n return {\n stream: this.createEmptyStream(),\n status: error.status,\n contentType: null,\n contentRange: null,\n contentLength: null\n };\n }\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n\n /**\n * Generate an absolute download URL\n *\n * @param bucketId - Bucket id (required to fetch metadata).\n * @param fileKey - File key to download.\n * @param signal - Optional AbortSignal for request cancellation.\n */\n async getDownloadUrl(\n bucketId: `0x${string}`,\n fileKey: `0x${string}`,\n signal?: AbortSignal\n ): Promise<string> {\n const bucketIdHex = ensure0xPrefix(bucketId);\n const fileKeyHex = ensure0xPrefix(fileKey);\n\n let info: StorageFileInfo;\n try {\n info = await this.getFileInfo(bucketIdHex, fileKeyHex, signal);\n } catch (error) {\n if (this.isHttpError(error) && error.status === 404) {\n throw new Error(`File not found: ${fileKeyHex}`);\n }\n throw error;\n }\n\n if (!info.isPublic) {\n throw new Error(\n `File is private: ${fileKeyHex}. Direct download URL for private files is not supported yet.`\n );\n }\n\n if (info.status !== \"ready\") {\n throw new Error(`File is not Ready (status=${info.status}): ${fileKeyHex}`);\n }\n\n // Construct the URL\n const baseUrl = this.ctx.config.baseUrl.replace(/\\/$/, \"\");\n const downloadPath = `/download/${encodeURIComponent(fileKeyHex)}`;\n return new URL(baseUrl + downloadPath).toString();\n }\n\n // Helpers\n private isHttpError(error: unknown): error is { status: number } {\n return (\n error !== null &&\n typeof error === \"object\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n }\n\n private createEmptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n }\n });\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 formFileMetadata(\n owner: `0x${string}`,\n bucketId: `0x${string}`,\n location: string,\n fingerprint: `0x${string}`,\n size: bigint\n ): Promise<FileMetadata> {\n const ownerBytes = hexToBytes(owner);\n const bucketIdBytes = hexToBytes(bucketId);\n const fingerprintBytes = hexToBytes(fingerprint);\n const locationBytes = new TextEncoder().encode(location);\n await initWasm();\n return new FileMetadata(ownerBytes, bucketIdBytes, locationBytes, size, fingerprintBytes);\n }\n\n private async computeFileKey(fileMetadata: FileMetadata): Promise<Uint8Array> {\n await initWasm();\n return fileMetadata.getFileKey();\n }\n}\n", "import { ModuleBase } from \"../base.js\";\nimport type {\n HealthStatus,\n InfoResponse,\n PaymentStreamsResponse,\n StatsResponse,\n ValueProp\n} from \"../types.js\";\nimport { ensure0xPrefix } from \"@storagehub-sdk/core\";\n\nexport class InfoModule extends ModuleBase {\n getHealth(signal?: AbortSignal): Promise<HealthStatus> {\n return this.ctx.http.get<HealthStatus>(\"/health\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get general MSP information */\n async getInfo(signal?: AbortSignal): Promise<InfoResponse> {\n const wire = await this.ctx.http.get<{\n client: string;\n version: string;\n mspId: string;\n multiaddresses: string[];\n ownerAccount: string;\n paymentAccount: string;\n status: string;\n activeSince: number;\n uptime: string;\n }>(\"/info\", {\n ...(signal ? { signal } : {})\n });\n\n return {\n client: wire.client,\n version: wire.version,\n mspId: ensure0xPrefix(wire.mspId),\n multiaddresses: wire.multiaddresses,\n ownerAccount: ensure0xPrefix(wire.ownerAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n paymentAccount: ensure0xPrefix(wire.paymentAccount), // Ensure 0x prefix (backend has it, but TypeScript needs guarantee)\n status: wire.status,\n activeSince: wire.activeSince,\n uptime: wire.uptime\n };\n }\n\n /** Get MSP statistics */\n getStats(signal?: AbortSignal): Promise<StatsResponse> {\n return this.ctx.http.get<StatsResponse>(\"/stats\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get available value propositions */\n getValuePropositions(signal?: AbortSignal): Promise<ValueProp[]> {\n return this.ctx.http.get<ValueProp[]>(\"/value-props\", {\n ...(signal ? { signal } : {})\n });\n }\n\n /** Get payment streams for current authenticated user */\n async getPaymentStreams(signal?: AbortSignal): Promise<PaymentStreamsResponse> {\n const headers = await this.withAuth();\n return this.ctx.http.get<PaymentStreamsResponse>(\"/payment_streams\", {\n ...(headers ? { headers } : {}),\n ...(signal ? { signal } : {})\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,OAAS,cAAAA,MAAkB,uBCA3B,OAAS,cAAAC,MAAqC,OCOvC,IAAeC,EAAf,KAA0B,CACZ,IACA,mBAEnB,YAAYC,EAAuBC,EAAwC,CACzE,KAAK,IAAMD,EACX,KAAK,mBAAqBC,CAC5B,CAEA,MAAgB,SACdC,EAC6C,CAE7C,IAAMC,GADU,MAAM,KAAK,mBAAmB,QAAQ,IAC/B,MACvB,OAAKA,EACED,EACH,CAAE,GAAGA,EAAS,cAAe,UAAUC,CAAK,EAAG,EAC/C,CAAE,cAAe,UAAUA,CAAK,EAAG,EAHpBD,CAIrB,CAcU,cAAcE,EAAsB,CAE5C,OAAOA,EAAK,QAAQ,eAAgB,CAACC,EAAIC,IAAoBA,IAAW,EAAI,GAAK,GAAI,CACvF,CACF,EDxCA,IAAMC,EAAoC,GACpCC,EAAiC,IAE1BC,EAAN,cAAyBC,CAAW,CAelC,SACLC,EACAC,EACAC,EACAC,EACAC,EACwB,CACxB,OAAO,KAAK,IAAI,KAAK,KAAoB,cAAe,CACtD,KAAM,CACJ,QAAAJ,EACA,QAAAC,EACA,OAAAC,EACA,IAAAC,CACF,EACA,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,GAAIC,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CAuBO,WACLJ,EACAC,EACAE,EACAC,EACwB,CACxB,OAAO,KAAK,IAAI,KAAK,KAAoB,gBAAiB,CACxD,KAAM,CACJ,QAAAJ,EACA,QAAAC,EACA,IAAAE,CACF,EACA,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,GAAIC,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CAeA,MAAa,OAAOC,EAAiBC,EAAmBF,EAAwC,CAO9F,OANgB,MAAM,KAAK,IAAI,KAAK,KAAc,eAAgB,CAChE,KAAM,CAAE,QAAAC,EAAS,UAAAC,CAAU,EAC3B,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,GAAIF,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CAGH,CAyBA,MAAM,KACJG,EACAL,EACAC,EACAK,EAAQZ,EACRQ,EACkB,CAClB,GAAM,CAAE,QAAAK,EAAS,QAAAT,EAAS,QAAAC,CAAQ,EAAI,MAAM,KAAK,eAAeM,EAAQ,MAAM,EACxE,CAAE,QAAAF,CAAQ,EAAI,MAAM,KAAK,SAASL,EAASC,EAASC,EAAQC,EAAKC,CAAM,EAC7E,OAAO,KAAK,uBAAuBG,EAAQE,EAASJ,EAASG,EAAOJ,EAAQ,MAAM,CACpF,CA4BA,MAAM,KACJG,EACAJ,EACAK,EAAQZ,EACRQ,EACkB,CAClB,GAAM,CAAE,QAAAK,EAAS,QAAAT,EAAS,QAAAC,CAAQ,EAAI,MAAM,KAAK,eAAeM,EAAQ,MAAM,EACxE,CAAE,QAAAF,CAAQ,EAAI,MAAM,KAAK,WAAWL,EAASC,EAASE,EAAKC,CAAM,EACvE,OAAO,KAAK,uBAAuBG,EAAQE,EAASJ,EAASG,EAAOJ,EAAQ,MAAM,CACpF,CAUA,MAAc,eACZG,EACAG,EAC8F,CAC9F,IAAMD,EAAUF,EAAO,QACjBI,EAAkB,OAAOF,GAAY,SAAWA,EAAUA,GAAS,QACzE,GAAI,CAACE,GAAmB,CAACF,EACvB,MAAM,IAAI,MACR,0EAA0EC,CAAU,EACtF,EAEF,IAAMV,EAAUY,EAAWD,CAAe,EACpCV,EAAU,MAAMM,EAAO,WAAW,EACxC,MAAO,CAAE,QAAAE,EAAS,QAAAT,EAAS,QAAAC,CAAQ,CACrC,CAaA,MAAc,uBACZM,EACAE,EACAJ,EACAG,EACAJ,EACAM,EACkB,CAClB,IAAMJ,EAAY,MAAMC,EAAO,YAAY,CAAE,QAAAE,EAAS,QAAAJ,CAAQ,CAAC,EAG3DQ,EACJ,QAASC,EAAe,EAAGA,EAAeN,EAAOM,IAC/C,GAAI,CACF,OAAO,MAAM,KAAK,OAAOT,EAASC,EAAWF,CAAM,CACrD,OAASW,EAAK,CACZF,EAAYE,EACZ,MAAM,KAAK,MAAMlB,CAA8B,CACjD,CAEF,MAAMgB,aAAqB,MAAQA,EAAY,IAAI,MAAM,GAAGH,CAAU,sBAAsB,CAC9F,CAEA,MAAc,MAAMM,EAA2B,CAC7C,MAAM,IAAI,QAASC,GAAY,WAAWA,EAASD,CAAE,CAAC,CACxD,CAMA,MAAM,WAAWZ,EAAyC,CACxD,IAAMc,EAAU,MAAM,KAAK,SAAS,EACpC,OAAO,KAAK,IAAI,KAAK,IAAc,gBAAiB,CAClD,GAAIA,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAId,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CACF,EErPA,OAAS,kBAAAe,EAAgB,aAAAC,MAAiB,uBAyB1C,SAASC,EAAYC,EAA8B,CACjD,OAAIA,EAAK,OAAS,OACT,CACL,KAAMA,EAAK,KACX,KAAMA,EAAK,KACX,UAAWA,EAAK,UAChB,QAASH,EAAeG,EAAK,OAAO,EACpC,OAAQA,EAAK,OACb,WAAYF,EAAUE,EAAK,UAAU,CACvC,EAEK,CACL,KAAMA,EAAK,KACX,KAAMA,EAAK,KACX,UAAWA,EAAK,UAAY,CAAC,GAAG,IAAID,CAAW,CACjD,CACF,CAEO,IAAME,EAAN,cAA4BC,CAAW,CAE5C,MAAM,YAAYC,EAAyC,CACzD,IAAMC,EAAU,MAAM,KAAK,SAAS,EAMpC,OALa,MAAM,KAAK,IAAI,KAAK,IAAc,WAAY,CACzD,GAAIA,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAID,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,GAEW,IAAKE,IAAoB,CACnC,SAAUR,EAAeQ,EAAO,QAAQ,EACxC,KAAMA,EAAO,KACb,KAAMR,EAAeQ,EAAO,IAAI,EAChC,SAAUA,EAAO,SACjB,UAAWA,EAAO,UAClB,YAAaR,EAAeQ,EAAO,WAAW,EAC9C,UAAWA,EAAO,SACpB,EAAE,CACJ,CAGA,MAAM,UAAUC,EAAkBH,EAAuC,CACvE,IAAMC,EAAU,MAAM,KAAK,SAAS,EAC9BG,EAAO,YAAY,mBAAmBD,CAAQ,CAAC,GAE/CE,EAAO,MAAM,KAAK,IAAI,KAAK,IAAYD,EAAM,CACjD,GAAIH,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAID,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,EAED,MAAO,CACL,SAAUN,EAAeW,EAAK,QAAQ,EACtC,KAAMA,EAAK,KACX,KAAMX,EAAeW,EAAK,IAAI,EAC9B,SAAUA,EAAK,SACf,UAAWA,EAAK,UAChB,YAAaX,EAAeW,EAAK,WAAW,EAC5C,UAAWA,EAAK,SAClB,CACF,CAGA,MAAM,SAASF,EAAkBG,EAAsD,CACrF,IAAML,EAAU,MAAM,KAAK,SAAS,EAC9BG,EAAO,YAAY,mBAAmBD,CAAQ,CAAC,SAE/CE,EAAO,MAAM,KAAK,IAAI,KAAK,IAA0BD,EAAM,CAC/D,GAAIH,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAIK,GAAS,OAAS,CAAE,OAAQA,EAAQ,MAAO,EAAI,CAAC,EACpD,GAAIA,GAAS,KAAO,CAAE,MAAO,CAAE,KAAM,KAAK,cAAcA,EAAQ,IAAI,CAAE,CAAE,EAAI,CAAC,CAC/E,CAAC,EAGKC,GADqC,UAAWF,EAAOA,EAAK,MAAQ,CAACA,EAAK,IAAI,GAChD,IAAIT,CAAW,EAC7CY,EAAOD,EAAM,CAAC,EACpB,MAAO,CACL,SAAUb,EAAeW,EAAK,QAAQ,EACtC,MAAAE,EACA,GAAIC,EAAO,CAAE,KAAAA,CAAK,EAAI,CAAC,CACzB,CACF,CACF,EC1GA,OACE,kBAAAC,EACA,kBAAAC,EACA,gBAAAC,EACA,cAAAC,EACA,YAAAC,EACA,aAAAC,MACK,uBAWA,IAAMC,EAAN,cAA0BC,CAAW,CAE1C,MAAM,YACJC,EACAC,EACAC,EAC0B,CAC1B,IAAMC,EAAU,MAAM,KAAK,SAAS,EAC9BC,EAAO,YAAY,mBAAmBJ,CAAQ,CAAC,SAAS,mBAAmBC,CAAO,CAAC,GAEnFI,EAAO,MAAM,KAAK,IAAI,KAAK,IAW9BD,EAAM,CACP,GAAID,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAID,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,EAED,MAAO,CACL,QAASI,EAAeD,EAAK,OAAO,EACpC,YAAaC,EAAeD,EAAK,WAAW,EAC5C,SAAUC,EAAeD,EAAK,QAAQ,EACtC,SAAUA,EAAK,SACf,KAAM,OAAOA,EAAK,IAAI,EACtB,SAAUA,EAAK,SACf,WAAYE,EAAUF,EAAK,UAAU,EACrC,OAAQA,EAAK,OACb,UAAWC,EAAeD,EAAK,SAAS,EACxC,GAAIA,EAAK,OAAS,CAAE,OAAQC,EAAeD,EAAK,MAAM,CAAE,EAAI,CAAC,CAC/D,CACF,CAGA,MAAM,WACJL,EACAC,EACAO,EACAC,EACAC,EACAC,EACAC,EACwB,CAGxBC,EAAeb,EAAU,GAAI,oDAAoD,EACjFa,EAAeJ,EAAa,GAAI,uDAAuD,EACvFI,EAAeH,EAAO,GAAI,iDAAiD,EAE3E,MAAMI,EAAS,EAEf,IAAMC,EAAc,YAAY,mBAAmBf,CAAQ,CAAC,WAAW,mBAAmBC,CAAO,CAAC,GAC5Fe,EAAc,MAAM,KAAK,SAAS,EAGlCC,EAAW,MAAM,KAAK,iBAAiBT,CAAI,EAC3CU,EAAWD,EAAS,KAGpBE,EAAW,MAAM,KAAK,iBAC1BT,EACAV,EACAW,EACAF,EACA,OAAOS,CAAQ,CACjB,EAGME,EAAkB,MAAM,KAAK,eAAeD,CAAQ,EACpDE,EAAuBC,EAAWrB,CAAO,EAC/C,GACEmB,EAAgB,SAAWC,EAAqB,QAChD,CAACD,EAAgB,MAAM,CAACG,EAAMC,IAAUD,IAASF,EAAqBG,CAAK,CAAC,EAE5E,MAAM,IAAI,MACR,qBAAqBJ,EAAgB,SAAS,CAAC,qCAAqCC,EAAqB,SAAS,CAAC,EACrH,EAIF,IAAMI,EAAkBN,EAAS,OAAO,EAGlCO,EAAO,IAAI,SACXC,EAAmB,IAAI,KAAK,CAAC,IAAI,WAAWF,CAAe,CAAC,EAAG,CACnE,KAAM,0BACR,CAAC,EACD,OAAAC,EAAK,OAAO,gBAAiBC,EAAkB,eAAe,EAC9DD,EAAK,OAAO,OAAQT,EAAU,MAAM,EAExB,MAAM,KAAK,IAAI,KAAK,IAC9BF,EACAC,EACI,CAAE,KAAMU,EAA6B,QAASV,CAAY,EAC1D,CAAE,KAAMU,CAA4B,CAC1C,CAEF,CAGA,MAAM,aAAazB,EAAiB2B,EAAoD,CACtF,IAAMxB,EAAO,aAAa,mBAAmBH,CAAO,CAAC,GAC/C4B,EAAsC,CAAE,OAAQ,KAAM,EAC5D,GAAID,GAAS,MAAO,CAClB,GAAM,CAAE,MAAAE,EAAO,IAAAC,CAAI,EAAIH,EAAQ,MACzBI,EAAa,SAASF,CAAK,IAAIC,GAAO,EAAE,GAC9CF,EAAY,MAAQG,CACtB,CAEA,IAAM7B,EAAU,MAAM,KAAK,SAAS0B,CAAW,EAE/C,GAAI,CACF,IAAMI,EAAM,MAAM,KAAK,IAAI,KAAK,OAAO7B,EAAM,CAC3C,GAAID,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAIyB,GAAS,OAAS,CAAE,OAAQA,EAAQ,MAAO,EAAI,CAAC,CACtD,CAAC,EAED,GAAI,CAACK,EAAI,KACP,MAAM,IAAI,MAAM,iDAAiD,EAGnE,IAAMC,EAAcD,EAAI,QAAQ,IAAI,cAAc,EAC5CE,EAAeF,EAAI,QAAQ,IAAI,eAAe,EAC9CG,EAAsBH,EAAI,QAAQ,IAAI,gBAAgB,EACtDI,EAAeD,IAAwB,KAAO,OAAOA,CAAmB,EAAI,OAC5EE,EACJ,OAAOD,GAAiB,UAAY,OAAO,SAASA,CAAY,EAAIA,EAAe,KAErF,MAAO,CACL,OAAQJ,EAAI,KACZ,OAAQA,EAAI,OACZ,YAAAC,EACA,aAAAC,EACA,cAAAG,CACF,CACF,OAASC,EAAO,CAEd,GAAI,KAAK,YAAYA,CAAK,EACxB,MAAO,CACL,OAAQ,KAAK,kBAAkB,EAC/B,OAAQA,EAAM,OACd,YAAa,KACb,aAAc,KACd,cAAe,IACjB,EAGF,MAAMA,CACR,CACF,CASA,MAAM,eACJvC,EACAC,EACAC,EACiB,CACjB,IAAMsC,EAAclC,EAAeN,CAAQ,EACrCyC,EAAanC,EAAeL,CAAO,EAErCyC,EACJ,GAAI,CACFA,EAAO,MAAM,KAAK,YAAYF,EAAaC,EAAYvC,CAAM,CAC/D,OAASqC,EAAO,CACd,MAAI,KAAK,YAAYA,CAAK,GAAKA,EAAM,SAAW,IACxC,IAAI,MAAM,mBAAmBE,CAAU,EAAE,EAE3CF,CACR,CAEA,GAAI,CAACG,EAAK,SACR,MAAM,IAAI,MACR,oBAAoBD,CAAU,+DAChC,EAGF,GAAIC,EAAK,SAAW,QAClB,MAAM,IAAI,MAAM,6BAA6BA,EAAK,MAAM,MAAMD,CAAU,EAAE,EAI5E,IAAME,EAAU,KAAK,IAAI,OAAO,QAAQ,QAAQ,MAAO,EAAE,EACnDC,EAAe,aAAa,mBAAmBH,CAAU,CAAC,GAChE,OAAO,IAAI,IAAIE,EAAUC,CAAY,EAAE,SAAS,CAClD,CAGQ,YAAYL,EAA6C,CAC/D,OACEA,IAAU,MACV,OAAOA,GAAU,UACjB,WAAYA,GACZ,OAAOA,EAAM,QAAW,QAE5B,CAEQ,mBAAgD,CACtD,OAAO,IAAI,eAA2B,CACpC,MAAMM,EAAY,CAChBA,EAAW,MAAM,CACnB,CACF,CAAC,CACH,CAEA,MAAc,iBACZrC,EACe,CACf,GAAI,OAAO,KAAS,KAAeA,aAAgB,KAAM,OAAOA,EAChE,GAAIA,aAAgB,WAAY,OAAO,IAAI,KAAK,CAACA,EAAK,MAAqB,CAAC,EAC5E,GAAI,OAAO,YAAgB,KAAeA,aAAgB,YAAa,OAAO,IAAI,KAAK,CAACA,CAAI,CAAC,EAG7F,GAAIA,aAAgB,eAAgB,CAClC,IAAMsC,EAAStC,EAAK,UAAU,EACxBuC,EAAuB,CAAC,EAC1BC,EAAc,EAElB,GAAI,CACF,OAAa,CACX,GAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAMJ,EAAO,KAAK,EAC1C,GAAIG,EAAM,MACNC,IACFH,EAAO,KAAKG,CAAK,EACjBF,GAAeE,EAAM,OAEzB,CACF,QAAE,CACAJ,EAAO,YAAY,CACrB,CAGA,IAAMK,EAAW,IAAI,WAAWH,CAAW,EACvCI,EAAS,EACb,QAAWC,KAASN,EAClBI,EAAS,IAAIE,EAAOD,CAAM,EAC1BA,GAAUC,EAAM,OAGlB,OAAO,IAAI,KAAK,CAACF,CAAQ,EAAG,CAAE,KAAM,0BAA2B,CAAC,CAClE,CAEA,OAAO,IAAI,KAAK,CAAC3C,CAAgB,EAAG,CAAE,KAAM,0BAA2B,CAAC,CAC1E,CAEA,MAAc,iBACZE,EACAV,EACAW,EACAF,EACA6C,EACuB,CACvB,IAAMC,EAAajC,EAAWZ,CAAK,EAC7B8C,EAAgBlC,EAAWtB,CAAQ,EACnCyD,EAAmBnC,EAAWb,CAAW,EACzCiD,EAAgB,IAAI,YAAY,EAAE,OAAO/C,CAAQ,EACvD,aAAMG,EAAS,EACR,IAAI6C,EAAaJ,EAAYC,EAAeE,EAAeJ,EAAMG,CAAgB,CAC1F,CAEA,MAAc,eAAeG,EAAiD,CAC5E,aAAM9C,EAAS,EACR8C,EAAa,WAAW,CACjC,CACF,EC9RA,OAAS,kBAAAC,MAAsB,uBAExB,IAAMC,EAAN,cAAyBC,CAAW,CACzC,UAAUC,EAA6C,CACrD,OAAO,KAAK,IAAI,KAAK,IAAkB,UAAW,CAChD,GAAIA,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CAGA,MAAM,QAAQA,EAA6C,CACzD,IAAMC,EAAO,MAAM,KAAK,IAAI,KAAK,IAU9B,QAAS,CACV,GAAID,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,EAED,MAAO,CACL,OAAQC,EAAK,OACb,QAASA,EAAK,QACd,MAAOJ,EAAeI,EAAK,KAAK,EAChC,eAAgBA,EAAK,eACrB,aAAcJ,EAAeI,EAAK,YAAY,EAC9C,eAAgBJ,EAAeI,EAAK,cAAc,EAClD,OAAQA,EAAK,OACb,YAAaA,EAAK,YAClB,OAAQA,EAAK,MACf,CACF,CAGA,SAASD,EAA8C,CACrD,OAAO,KAAK,IAAI,KAAK,IAAmB,SAAU,CAChD,GAAIA,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CAGA,qBAAqBA,EAA4C,CAC/D,OAAO,KAAK,IAAI,KAAK,IAAiB,eAAgB,CACpD,GAAIA,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CAGA,MAAM,kBAAkBA,EAAuD,CAC7E,IAAME,EAAU,MAAM,KAAK,SAAS,EACpC,OAAO,KAAK,IAAI,KAAK,IAA4B,mBAAoB,CACnE,GAAIA,EAAU,CAAE,QAAAA,CAAQ,EAAI,CAAC,EAC7B,GAAIF,EAAS,CAAE,OAAAA,CAAO,EAAI,CAAC,CAC7B,CAAC,CACH,CACF,EL1DO,IAAMG,EAAN,MAAMC,UAAkBC,CAAW,CACxB,OACC,QACD,KACA,QACA,MACA,KAER,YACNC,EACAC,EACAC,EACA,CACA,IAAMC,EAA4B,CAAE,OAAAH,EAAQ,KAAAC,CAAK,EACjD,MAAME,EAASD,CAAkB,EACjC,KAAK,OAASF,EACd,KAAK,QAAUG,EACf,KAAK,KAAO,IAAIC,EAAW,KAAK,QAASF,CAAkB,EAC3D,KAAK,QAAU,IAAIG,EAAc,KAAK,QAASH,CAAkB,EACjE,KAAK,MAAQ,IAAII,EAAY,KAAK,QAASJ,CAAkB,EAC7D,KAAK,KAAO,IAAIK,EAAW,KAAK,QAASL,CAAkB,CAC7D,CAEA,aAAa,QACXF,EACAQ,EAAmC,SAAS,GACxB,CACpB,GAAI,CAACR,GAAQ,QAAS,MAAM,IAAI,MAAM,wCAAwC,EAE9E,IAAMC,EAAO,IAAIQ,EAAW,CAC1B,QAAST,EAAO,QAChB,GAAIA,EAAO,YAAc,QAAa,CAAE,UAAWA,EAAO,SAAU,EACpE,GAAIA,EAAO,iBAAmB,QAAa,CACzC,eAAgBA,EAAO,cACzB,EACA,GAAIA,EAAO,YAAc,QAAa,CAAE,UAAWA,EAAO,SAAU,CACtE,CAAC,EAGKE,EAAqB,CAAE,QAASM,CAAgB,EACtD,OAAO,IAAIV,EAAUE,EAAQC,EAAMC,CAAkB,CACvD,CAQA,mBAAmBM,EAAwC,CACzD,KAAK,mBAAmB,QAAUA,CACpC,CACF",
|
|
6
|
+
"names": ["HttpClient", "getAddress", "ModuleBase", "ctx", "sessionProviderRef", "headers", "token", "path", "_m", "offset", "DEFAULT_SIWE_VERIFY_RETRY_ATTEMPS", "DEFAULT_SIWE_VERIFY_BACKOFF_MS", "AuthModule", "ModuleBase", "address", "chainId", "domain", "uri", "signal", "message", "signature", "wallet", "retry", "account", "methodName", "resolvedAddress", "getAddress", "lastError", "attemptIndex", "err", "ms", "resolve", "headers", "ensure0xPrefix", "parseDate", "fixFileTree", "item", "BucketsModule", "ModuleBase", "signal", "headers", "bucket", "bucketId", "path", "wire", "options", "files", "tree", "assert0xString", "ensure0xPrefix", "FileMetadata", "hexToBytes", "initWasm", "parseDate", "FilesModule", "ModuleBase", "bucketId", "fileKey", "signal", "headers", "path", "wire", "ensure0xPrefix", "parseDate", "file", "fingerprint", "owner", "location", "_options", "assert0xString", "initWasm", "backendPath", "authHeaders", "fileBlob", "fileSize", "metadata", "computedFileKey", "expectedFileKeyBytes", "hexToBytes", "byte", "index", "encodedMetadata", "form", "fileMetadataBlob", "options", "baseHeaders", "start", "end", "rangeValue", "res", "contentType", "contentRange", "contentLengthHeader", "parsedLength", "contentLength", "error", "bucketIdHex", "fileKeyHex", "info", "baseUrl", "downloadPath", "controller", "reader", "chunks", "totalLength", "done", "value", "combined", "offset", "chunk", "size", "ownerBytes", "bucketIdBytes", "fingerprintBytes", "locationBytes", "FileMetadata", "fileMetadata", "ensure0xPrefix", "InfoModule", "ModuleBase", "signal", "wire", "headers", "MspClient", "_MspClient", "ModuleBase", "config", "http", "sessionProviderRef", "context", "AuthModule", "BucketsModule", "FilesModule", "InfoModule", "sessionProvider", "HttpClient"]
|
|
7
7
|
}
|
package/dist/modules/files.d.ts
CHANGED
|
@@ -2,15 +2,22 @@ import { ModuleBase } from "../base.js";
|
|
|
2
2
|
import type { DownloadOptions, DownloadResult, StorageFileInfo, UploadOptions, UploadReceipt } from "../types.js";
|
|
3
3
|
export declare class FilesModule extends ModuleBase {
|
|
4
4
|
/** Get metadata for a file in a bucket by fileKey */
|
|
5
|
-
getFileInfo(bucketId: string
|
|
5
|
+
getFileInfo(bucketId: `0x${string}`, fileKey: `0x${string}`, signal?: AbortSignal): Promise<StorageFileInfo>;
|
|
6
6
|
/** Upload a file to a bucket with a specific key */
|
|
7
|
-
uploadFile(bucketId: string
|
|
7
|
+
uploadFile(bucketId: `0x${string}`, fileKey: `0x${string}`, file: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array> | unknown, fingerprint: `0x${string}`, owner: `0x${string}`, location: string, _options?: UploadOptions): Promise<UploadReceipt>;
|
|
8
8
|
/** Download a file by key */
|
|
9
9
|
downloadFile(fileKey: string, options?: DownloadOptions): Promise<DownloadResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Generate an absolute download URL
|
|
12
|
+
*
|
|
13
|
+
* @param bucketId - Bucket id (required to fetch metadata).
|
|
14
|
+
* @param fileKey - File key to download.
|
|
15
|
+
* @param signal - Optional AbortSignal for request cancellation.
|
|
16
|
+
*/
|
|
17
|
+
getDownloadUrl(bucketId: `0x${string}`, fileKey: `0x${string}`, signal?: AbortSignal): Promise<string>;
|
|
10
18
|
private isHttpError;
|
|
11
19
|
private createEmptyStream;
|
|
12
20
|
private coerceToFormPart;
|
|
13
|
-
private computeFileFingerprint;
|
|
14
21
|
private formFileMetadata;
|
|
15
22
|
private computeFileKey;
|
|
16
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storagehub-sdk/msp-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"viem": ">=2.38.3",
|
|
31
|
-
"@storagehub-sdk/core": "0.
|
|
31
|
+
"@storagehub-sdk/core": "0.5.0"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=22"
|