storacha-sol 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,14 +6,17 @@ Here are a couple of things you can do with this package:
6
6
 
7
7
  - Estimate upload fees based on the file size and duration
8
8
  - Make SOL payments for Storage on Storacha
9
+ - Multiple file (directory) uploads
10
+ - Show how much time is left to expiry
11
+ - View your upload history (all files you've stored with their details)
12
+ - Get expiration warnings via email before your files expire
13
+ - Automatic deletion of expired files from Storacha
14
+ - Renew/extend storage duration for existing uploads
9
15
 
10
16
  Stuffs we hope to cover or extend:
11
17
 
12
- - Multiple file (directory) uploads
13
- - List stored items in a wallet's space (space-management, pretty-much)
14
18
  - Allow payments from other chains. (Filecoin next)
15
19
  - Include implementations for other libs. Right now, we only have React. Hoping to cover, Vue, Svelte etc.
16
- - Show how much time is left to expiry and add ability to renew/icrease upload duration
17
20
 
18
21
  ## Usage
19
22
 
@@ -108,6 +111,115 @@ An edge-case you may want to consider before calling `createDeposit` is to check
108
111
 
109
112
  You can use `client.estimateStorageCost` to get the values in SOL and compare if the balance is less than what was estimated before paying and provide a reasonable error message for your end-users.
110
113
 
114
+ ### View Upload History
115
+
116
+ You can fetch all uploads associated with a wallet address:
117
+
118
+ ```ts
119
+ const client = useDeposit('testnet' as Environment);
120
+ const history = await client.getUserUploadHistory(publicKey.toString());
121
+
122
+ console.log(history.userHistory); // Array of all deposits
123
+ ```
124
+
125
+ Each deposit in the history includes:
126
+ - File details (name, size, type, CID)
127
+ - Expiration date
128
+ - Deletion status (`active`, `warned`, `deleted`)
129
+ - Transaction hash
130
+ - Duration and cost information
131
+
132
+ ### Email Expiration Warnings
133
+
134
+ When creating a deposit, you can optionally provide an email address to receive expiration warnings:
135
+
136
+ ```ts
137
+ const result = await client.createDeposit({
138
+ file,
139
+ durationDays: storageDuration,
140
+ payer: publicKey,
141
+ userEmail: 'user@example.com', // Optional email for expiration warnings
142
+ signTransaction: async (tx) => {
143
+ const signed = await signTransaction(tx);
144
+ return signed;
145
+ },
146
+ });
147
+ ```
148
+
149
+ If provided, you'll receive an email notification **7 days before your file expires**, giving you time to extend the storage duration (feature coming soon!).
150
+
151
+ The warning email includes:
152
+ - File name and CID
153
+ - Exact expiration date
154
+ - Number of days remaining
155
+ - Direct link to view your file on IPFS
156
+
157
+ ### Automatic Cleanup
158
+
159
+ Files that have expired are automatically deleted from Storacha storage. This happens through a scheduled job that:
160
+ 1. Identifies expired deposits
161
+ 2. Removes the data from Storacha (including shards)
162
+ 3. Updates the deletion status in the database
163
+
164
+ Your upload history will show the deletion status, so you can track which files are still active, warned, or deleted.
165
+
166
+ ### Storage Renewal
167
+
168
+ Extend the storage duration for your existing uploads before they expire:
169
+
170
+ ```ts
171
+ const client = useDeposit('testnet' as Environment);
172
+ const { publicKey, signTransaction } = useSolanaWallet();
173
+
174
+ // First, get a quote to see what it'll cost
175
+ const quote = await client.getStorageRenewalCost(cid, 30); // 30 additional days
176
+
177
+ console.log(`Current expiration: ${quote.currentExpirationDate}`);
178
+ console.log(`New expiration: ${quote.newExpirationDate}`);
179
+ console.log(`Cost: ${quote.costInSOL} SOL`);
180
+
181
+ const result = await client.renewStorageDuration({
182
+ cid,
183
+ additionalDays: 30,
184
+ payer: publicKey,
185
+ signTransaction: async (tx) => {
186
+ const signed = await signTransaction(tx);
187
+ return signed;
188
+ },
189
+ });
190
+
191
+ if (result.success) {
192
+ console.log('Storage renewed! Transaction:', result.signature);
193
+ }
194
+ ```
195
+
196
+ **How it works:**
197
+ - `getStorageRenewalCost()` shows you the cost and new expiration date before committing
198
+ - `renewStorageDuration()` creates a payment transaction (same flow as initial upload)
199
+ - After payment confirms, your file's expiration date gets updated
200
+
201
+ ## Usage with Vite
202
+
203
+ When using this SDK in a project built with Vite, you may encounter a `ReferenceError: process is not defined`. This is because Vite does not automatically polyfill the Node.js `process` global, which this library may use.
204
+
205
+ To resolve this, you can define `process.env` as an empty object in your `vite.config.ts` file:
206
+
207
+ ```ts
208
+ // vite.config.ts
209
+ import { defineConfig } from 'vite'
210
+ import react from '@vitejs/plugin-react'
211
+
212
+ export default defineConfig({
213
+ plugins: [react()],
214
+ // ... other config
215
+ define: {
216
+ 'process.env': {},
217
+ },
218
+ })
219
+ ```
220
+
221
+ This will prevent the runtime error and allow the SDK to function correctly.
222
+
111
223
  ## Want to contribute?
112
224
 
113
225
  Read the [Contributing guide](CONTRIBUTING.md)
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var D=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var B=(r,e)=>{for(var n in e)D(r,n,{get:e[n],enumerable:!0})},$=(r,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of j(e))!O.call(r,s)&&s!==n&&D(r,s,{get:()=>e[s],enumerable:!(t=C(e,s))||t.enumerable});return r};var A=r=>$(D({},"__esModule",{value:!0}),r);var N={};B(N,{Client:()=>d,Environment:()=>x,createDepositTxn:()=>E,fetchUserDepositHistory:()=>U,getRpcUrl:()=>R,useDeposit:()=>H});module.exports=A(N);var I=require("@solana/web3.js");var p=require("@solana/web3.js");var{NODE_ENV:F}=process.env,u=F==="development"?"http://localhost:5040":"https://storacha-solana-sdk-bshc.onrender.com";async function E({file:r,duration:e,payer:n,connection:t,signTransaction:s}){try{let o=new FormData;r.forEach(i=>o.append("file",i)),o.append("duration",e.toString()),o.append("publicKey",n.toBase58());let P=r.length>1,h,m=await fetch(`${u}/api/solana/deposit`,{method:"POST",body:o});if(!m.ok)throw new Error("Failed to get deposit instructions");let a=await m.json();if(!a.instructions||!a.instructions.length)throw new Error("No instructions from deposit API");let w=await t.getLatestBlockhash("confirmed"),g=a.instructions[0],S=new p.TransactionInstruction({programId:new p.PublicKey(g.programId),keys:g.keys.map(i=>({pubkey:new p.PublicKey(i.pubkey),isSigner:i.isSigner,isWritable:i.isWritable})),data:Buffer.from(g.data,"base64")}),f=new p.Transaction;f.recentBlockhash=w.blockhash,f.feePayer=n,f.add(S);let T=await s(f),k=await t.sendRawTransaction(T.serialize(),{skipPreflight:!1,preflightCommitment:"confirmed"}),y=await t.confirmTransaction({signature:k,blockhash:w.blockhash,lastValidBlockHeight:w.lastValidBlockHeight},"confirmed");if(y.value.err)throw console.error("Failed to confirm this transaction:",y.value.err),new Error(`Transaction failed: ${JSON.stringify(y.value.err)}`);a.error&&(h=a.error);let b=new FormData;r.forEach(i=>b.append("file",i));let l;if(P?l=await fetch(`${u}/api/user/upload-files?cid=${encodeURIComponent(a.cid)}`,{method:"POST",body:b}):l=await fetch(`${u}/api/user/upload-file?cid=${encodeURIComponent(a.cid)}`,{method:"POST",body:b}),!l.ok){let i="Unknown error";try{let v=await l.json();i=v.message||v.error||i}catch{}throw new Error("Deposit API error: "+i)}let c=await l?.json();return{signature:k,success:!0,cid:a.cid,url:c.object.url,message:c.object.message,fileInfo:c.object?{filename:c.object.fileInfo?.filename||"",size:c?.object?.fileInfo?.size||0,uploadedAt:c?.object?.fileInfo?.uploadedAt||"",type:c?.object?.fileInfo?.type||""}:void 0}}catch(o){return console.error(o),o instanceof Error&&(console.error("Error name:",o.name),console.error("Error message:",o.message),console.error("Error stack:",o.stack)),{signature:"",success:!1,cid:"",url:"",message:"",fileInfo:void 0,error:o instanceof Error?o.message:"Unknown error occurred"}}}async function U(r,e={}){if(!r||typeof r!="string")throw new Error("User address is required and must be a string");let n=e.url||"http://localhost:3000";try{let t=await fetch(`${n}/user-upload-history?userAddress=${encodeURIComponent(r)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){let o=await t.json().catch(()=>({}));throw new Error(o.message||`Failed to fetch deposit history: ${t.status} ${t.statusText}`)}let s=await t.json();if(typeof s!="object"||s===null)throw new Error("Invalid response format from server");if(typeof s.userAddress!="string")throw new Error("Invalid userAddress in response");return s}catch(t){throw t instanceof Error?t:new Error("Unknown error occurred while fetching deposit history")}}var x=(t=>(t.mainnet="mainnet-beta",t.testnet="testnet",t.devnet="devnet",t))(x||{});function R(r){switch(r){case"mainnet-beta":return"https://api.mainnet-beta.solana.com";case"testnet":return"https://api.testnet.solana.com";case"devnet":return"https://api.devnet.solana.com";default:throw new Error(`Unsupported environment: ${r}`)}}var d=class{constructor(e){this.estimateStorageCost=(e,n)=>{let o=e.reduce((h,m)=>h+m.size,0)*n*1e3;return{sol:o/1e9,lamports:o}};this.rpcUrl=R(e.environment)}async createDeposit({payer:e,file:n,durationDays:t,signTransaction:s}){console.log("Creating deposit transaction with environment:",this.rpcUrl);let o=new I.Connection(this.rpcUrl,"confirmed");return await E({file:n,duration:t*86400,payer:e,connection:o,signTransaction:s})}async getUserUploadHistory(e){return await U(e)}};var H=r=>new d({environment:r||"testnet"});0&&(module.exports={Client,Environment,createDepositTxn,fetchUserDepositHistory,getRpcUrl,useDeposit});
1
+ "use strict";var P=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var H=(r,e)=>{for(var o in e)P(r,o,{get:e[o],enumerable:!0})},z=(r,e,o,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of F(e))!_.call(r,n)&&n!==o&&P(r,n,{get:()=>e[n],enumerable:!(t=L(e,n))||t.enumerable});return r};var K=r=>z(P({},"__esModule",{value:!0}),r);var J={};H(J,{Client:()=>g,Environment:()=>N,createDepositTxn:()=>D,fetchUserDepositHistory:()=>x,fetchUserUploadHistory:()=>x,getRpcUrl:()=>$,getStorageRenewalCost:()=>I,getUserUploadHistory:()=>x,renewStorageTxn:()=>k,useDeposit:()=>q,useUpload:()=>q});module.exports=K(J);var C=require("@solana/web3.js");var{NODE_ENV:M}=process.env,p=M==="development"?"http://localhost:5040":"https://storacha-solana-sdk-bshc.onrender.com",O=86400,j=1e9,v=(r,e,o)=>r*o*e;var l=require("@solana/web3.js");async function D({file:r,duration:e,payer:o,connection:t,signTransaction:n,userEmail:i}){try{let a=new FormData;r.forEach(s=>a.append("file",s)),a.append("duration",e.toString()),a.append("publicKey",o.toBase58()),i&&a.append("userEmail",i);let u=r.length>1,f,y=await fetch(`${p}/api/solana/deposit`,{method:"POST",body:a});if(!y.ok)throw new Error("Failed to get deposit instructions");let c=await y.json();if(!c.instructions||!c.instructions.length)throw new Error("No instructions from deposit API");let b=await t.getLatestBlockhash("confirmed"),d=c.instructions[0],w=new l.TransactionInstruction({programId:new l.PublicKey(d.programId),keys:d.keys.map(s=>({pubkey:new l.PublicKey(s.pubkey),isSigner:s.isSigner,isWritable:s.isWritable})),data:Buffer.from(d.data,"base64")}),S=new l.Transaction;S.recentBlockhash=b.blockhash,S.feePayer=o,S.add(w);let A=await n(S),R;try{R=await t.sendRawTransaction(A.serialize(),{skipPreflight:!1,preflightCommitment:"confirmed"})}catch(s){throw s instanceof l.SendTransactionError?(s.logs??[]).some(B=>B.includes("already in use"))?new Error("This file has already been uploaded. You can find it in your dashboard."):new Error("Transaction failed during simulation. Please try again."):s}let U=await t.confirmTransaction({signature:R,blockhash:b.blockhash,lastValidBlockHeight:b.lastValidBlockHeight},"confirmed");if(U.value.err)throw console.error("Failed to confirm this transaction:",U.value.err),new Error(`Transaction failed: ${JSON.stringify(U.value.err)}`);try{await fetch(`${p}/api/user/update-transaction-hash`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:c.cid,transactionHash:R})})}catch(s){console.warn("Failed to update transaction hash:",s)}c.error&&(f=c.error);let E=new FormData;r.forEach(s=>E.append("file",s));let h;if(u?h=await fetch(`${p}/api/user/upload-files?cid=${encodeURIComponent(c.cid)}`,{method:"POST",body:E}):h=await fetch(`${p}/api/user/upload-file?cid=${encodeURIComponent(c.cid)}`,{method:"POST",body:E}),!h.ok){let s="Unknown error";try{let T=await h.json();s=T.message||T.error||s}catch{}throw new Error("Deposit API error: "+s)}let m=await h?.json();return{signature:R,success:!0,cid:c.cid,url:m.object.url,message:m.object.message,fileInfo:m.object?{filename:m.object.fileInfo?.filename||"",size:m?.object?.fileInfo?.size||0,uploadedAt:m?.object?.fileInfo?.uploadedAt||"",type:m?.object?.fileInfo?.type||""}:void 0}}catch(a){return console.error(a),a instanceof Error&&(console.error("Error name:",a.name),console.error("Error message:",a.message),console.error("Error stack:",a.stack)),{signature:"",success:!1,cid:"",url:"",message:"",fileInfo:void 0,error:a instanceof Error?a.message:"Unknown error occurred"}}}async function I(r,e){try{let o=await fetch(`${p}/api/user/renewal-cost?cid=${encodeURIComponent(r)}&duration=${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!o.ok){let t=await o.json();throw new Error(t.message||"Failed to get storage renewal cost")}return await o.json()}catch(o){return console.error("Failed to get storage renewal cost",o),null}}async function k({cid:r,duration:e,payer:o,connection:t,signTransaction:n}){let i=await fetch(`${p}/api/user/renew-storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:r,duration:e,publicKey:o.toString()})});if(!i.ok){let d=await i.json().catch(()=>({}));throw new Error(d.message||"Failed to create renewal transaction")}let a=await i.json(),u=new l.Transaction;a.instructions.forEach(d=>{u.add({programId:new l.PublicKey(d.programId),keys:d.keys.map(w=>({pubkey:new l.PublicKey(w.pubkey),isSigner:w.isSigner,isWritable:w.isWritable})),data:Buffer.from(d.data,"base64")})});let{blockhash:f}=await t.getLatestBlockhash();u.recentBlockhash=f,u.feePayer=o;let y=await n(u),c=await t.sendRawTransaction(y.serialize());return await t.confirmTransaction(c,"confirmed"),(await fetch(`${p}/api/user/confirm-renewal`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:r,duration:e,transactionHash:c})})).ok||console.error("Failed to confirm renewal on backend"),{success:!0,cid:r,signature:c,url:`https://w3s.link/ipfs/${r}`,message:"Storage renewed successfully"}}async function x(r,e={}){if(!r||typeof r!="string")throw new Error("User address is required and must be a string");let o=e.url||p;try{let t=await fetch(`${o}/api/user/user-upload-history?userAddress=${encodeURIComponent(r)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.message||`Failed to fetch upload history: ${t.status} ${t.statusText}`)}let n=await t.json();if(typeof n!="object"||n===null)throw new Error("Invalid response format from server");if(typeof n.userAddress!="string")throw new Error("Invalid userAddress in response");return n}catch(t){throw t instanceof Error?t:new Error("Unknown error occurred while fetching upload history")}}var N=(t=>(t.mainnet="mainnet-beta",t.testnet="testnet",t.devnet="devnet",t))(N||{});function $(r){switch(r){case"mainnet-beta":return"https://api.mainnet-beta.solana.com";case"testnet":return"https://api.testnet.solana.com";case"devnet":return"https://api.devnet.solana.com";default:throw new Error(`Unsupported environment: ${r}`)}}var g=class{constructor(e){this.estimateStorageCost=(e,o)=>{let n=e.reduce((u,f)=>u+f.size,0),i=v(n,1e3,o);return{sol:i/j,lamports:i}};this.rpcUrl=$(e.environment)}async createDeposit({payer:e,file:o,durationDays:t,signTransaction:n,userEmail:i}){console.log("Creating deposit transaction with environment:",this.rpcUrl);let a=new C.Connection(this.rpcUrl,"confirmed");return await D({file:o,duration:t*O,payer:e,connection:a,signTransaction:n,userEmail:i})}async getUserUploadHistory(e){return await x(e)}async getStorageRenewalCost(e,o){return await I(e,o)}async renewStorageDuration({cid:e,duration:o,payer:t,signTransaction:n}){let i=new C.Connection(this.rpcUrl,"confirmed");return await k({cid:e,duration:o,payer:t,connection:i,signTransaction:n})}};var q=r=>new g({environment:r||"testnet"});0&&(module.exports={Client,Environment,createDepositTxn,fetchUserDepositHistory,fetchUserUploadHistory,getRpcUrl,getStorageRenewalCost,getUserUploadHistory,renewStorageTxn,useDeposit,useUpload});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/payment.ts","../src/constants.ts","../src/depositHistory.ts","../src/hooks.ts"],"sourcesContent":["export * from \"./client\"\nexport * from \"./types\"\nexport * from \"./payment\"\nexport * from \"./hooks\"\nexport * from \"./depositHistory\"\n","import { PublicKey, Connection } from '@solana/web3.js';\nimport { createDepositTxn } from './payment';\nimport { CreateDepositArgs, UploadResult } from './types';\nimport { fetchUserDepositHistory } from './depositHistory';\n\nexport enum Environment {\n mainnet = 'mainnet-beta',\n testnet = 'testnet',\n devnet = 'devnet',\n}\n\nexport function getRpcUrl(env: Environment): string {\n switch (env) {\n case Environment.mainnet:\n return 'https://api.mainnet-beta.solana.com';\n case Environment.testnet:\n return 'https://api.testnet.solana.com';\n case Environment.devnet:\n return 'https://api.devnet.solana.com';\n default:\n throw new Error(`Unsupported environment: ${env}`);\n }\n}\n\nexport interface ClientOptions {\n /** Solana RPC endpoint to use for chain interactions */\n environment: Environment;\n}\n\nexport interface DepositParams\n extends Pick<CreateDepositArgs, 'signTransaction'> {\n /** Wallet public key of the payer */\n payer: PublicKey;\n /** File(s) to be stored */\n file: File[];\n /** Duration in days to store the data */\n durationDays: number;\n}\n\n/**\n * Solana Storage Client — simplified (no fee estimation)\n */\nexport class Client {\n private rpcUrl: string;\n\n constructor(options: ClientOptions) {\n this.rpcUrl = getRpcUrl(options.environment);\n }\n\n /**\n * Creates a deposit transaction ready to be signed & sent by user's wallet.\n *\n * @param {Object} params\n * @param {PublicKey} params.payer - The public key (wallet address) of the connected wallet.\n * @param {File} params.file - The file to be uploaded.\n * @param {number} params.durationDays - How long (in days) the file should be stored.\n * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction -\n * A callback function to authorize the transaction via the Solana wallet library.\n *\n * @example\n * const { publicKey, signTransaction } = useSolanaWallet();\n * const result = await createDeposit({\n * payer: publicKey,\n * file,\n * durationDays: 30,\n * signTransaction,\n * });\n *\n * @returns {Promise<UploadResult>} The upload result after transaction is processed.\n */\n async createDeposit({\n payer,\n file,\n durationDays,\n signTransaction,\n }: DepositParams): Promise<UploadResult> {\n console.log('Creating deposit transaction with environment:', this.rpcUrl);\n const connection = new Connection(this.rpcUrl, 'confirmed');\n\n return await createDepositTxn({\n file,\n duration: durationDays * 86400,\n payer,\n connection,\n signTransaction,\n });\n }\n\n /**\n * estimates the cost for a file based on the amount of days it should be stored for\n * @param {File} file - a file to be uploaded\n * @param {number} duration - how long (in seconds) the file should be stored for\n */\n estimateStorageCost = (file: File[], duration: number) => {\n const ratePerBytePerDay = 1000; // this would be obtained from the program config later\n const fileSizeInBytes = file.reduce((acc, f) => acc + f.size, 0);\n const totalLamports = fileSizeInBytes * duration * ratePerBytePerDay;\n const totalSOL = totalLamports / 1_000_000_000;\n\n return {\n sol: totalSOL,\n lamports: totalLamports,\n };\n };\n\n async getUserUploadHistory(userAddress: string) {\n const response = await fetchUserDepositHistory(userAddress);\n return response;\n }\n}\n","import { Signature } from '@solana/kit';\nimport { CreateDepositArgs, DepositResult, UploadResult } from './types';\nimport {\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from '@solana/web3.js';\nimport { ENDPOINT } from './constants';\n\n/**\n * Calls the deposit API for on-chain storage and returns a Transaction\n * which must be signed and sent externally by the user.\n *\n * @param params - {\n * cid: string;\n * file: File;\n * duration: number;\n * payer: PublicKey;\n * connection: Connection;\n * }\n * @returns Transaction\n */\nexport async function createDepositTxn({\n file,\n duration,\n payer,\n connection,\n signTransaction,\n}: CreateDepositArgs): Promise<UploadResult> {\n try {\n const formData = new FormData();\n file.forEach((f) => formData.append(\"file\", f))\n formData.append('duration', duration.toString());\n formData.append('publicKey', payer.toBase58());\n\n const isMultipleFiles = file.length > 1\n\n let uploadErr;\n\n const depositReq = await fetch(`${ENDPOINT}/api/solana/deposit`, {\n method: 'POST',\n body: formData,\n });\n if (!depositReq.ok) throw new Error('Failed to get deposit instructions');\n\n const depositRes: DepositResult = await depositReq.json();\n if (!depositRes.instructions || !depositRes.instructions.length)\n throw new Error('No instructions from deposit API');\n\n const latestBlockhash = await connection.getLatestBlockhash('confirmed');\n const instructions = depositRes.instructions[0];\n\n const depositInstruction = new TransactionInstruction({\n programId: new PublicKey(instructions.programId),\n keys: instructions.keys.map((k) => ({\n pubkey: new PublicKey(k.pubkey),\n isSigner: k.isSigner,\n isWritable: k.isWritable,\n })),\n data: Buffer.from(instructions.data, 'base64'),\n });\n\n const tx = new Transaction();\n tx.recentBlockhash = latestBlockhash.blockhash;\n tx.feePayer = payer;\n tx.add(depositInstruction);\n\n const signedTx = await signTransaction(tx);\n const signature = await connection.sendRawTransaction(\n signedTx.serialize(),\n {\n skipPreflight: false, // not sure we should be disabling this verification step\n preflightCommitment: 'confirmed',\n }\n );\n const confirmation = await connection.confirmTransaction(\n {\n signature,\n blockhash: latestBlockhash.blockhash,\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\n },\n 'confirmed'\n );\n\n if (confirmation.value.err) {\n console.error(\n 'Failed to confirm this transaction:',\n confirmation.value.err\n );\n throw new Error(\n `Transaction failed: ${JSON.stringify(confirmation.value.err)}`\n );\n }\n\n if (depositRes.error) {\n uploadErr = depositRes.error;\n }\n\n const uploadForm = new FormData();\n file.forEach((f) => uploadForm.append(\"file\", f))\n\n let fileUploadReq;\n // calls the upload functionality on our server with the file when deposit is succesful\n if (isMultipleFiles) {\n fileUploadReq = await fetch(\n `${ENDPOINT}/api/user/upload-files?cid=${encodeURIComponent(depositRes.cid)}`,\n {\n method: 'POST',\n body: uploadForm,\n }\n );\n } else {\n fileUploadReq = await fetch(\n `${ENDPOINT}/api/user/upload-file?cid=${encodeURIComponent(depositRes.cid)}`,\n {\n method: 'POST',\n body: uploadForm,\n }\n );\n }\n\n if (!fileUploadReq.ok) {\n let err = 'Unknown error';\n try {\n const data: DepositResult = await fileUploadReq.json();\n err = data.message || data.error || err;\n } catch {}\n throw new Error('Deposit API error: ' + err);\n }\n\n const fileUploadRes: Pick<DepositResult, 'object' | 'cid' | 'message'> =\n await fileUploadReq?.json();\n\n return {\n signature: signature as Signature,\n success: true,\n cid: depositRes.cid,\n url: fileUploadRes.object.url,\n message: fileUploadRes.object.message,\n fileInfo: fileUploadRes.object\n ? {\n filename: fileUploadRes.object.fileInfo?.filename || '',\n size: fileUploadRes?.object?.fileInfo?.size || 0,\n uploadedAt: fileUploadRes?.object?.fileInfo?.uploadedAt || '',\n type: fileUploadRes?.object?.fileInfo?.type || '',\n }\n : undefined,\n };\n } catch (error) {\n console.error(error);\n if (error instanceof Error) {\n console.error('Error name:', error.name);\n console.error('Error message:', error.message);\n console.error('Error stack:', error.stack);\n }\n\n return {\n signature: '' as Signature,\n success: false,\n cid: '',\n url: '',\n message: '',\n fileInfo: undefined,\n error: error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n}\n","const { NODE_ENV } = process.env;\n\nexport const ENDPOINT =\n NODE_ENV === 'development'\n ? 'http://localhost:5040'\n : 'https://storacha-solana-sdk-bshc.onrender.com';\n","import { DepositHistoryResponse, ServerOptions } from './types';\n\n/**\n * Fetches the deposit history for a given user address from the backend\n *\n * @param userAddress - The wallet address of the user to fetch deposit history for\n * @param options - Optional server configuration\n * @returns Promise<DepositHistoryResponse> - The user's deposit history\n *\n * @example\n * ```typescript\n * const history = await fetchUserDepositHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');\n * console.log('User deposit history:', history.userHistory);\n * ```\n *\n * @throws {Error} When the user address is invalid or the request fails\n */\nexport async function fetchUserDepositHistory(\n userAddress: string,\n options: ServerOptions = {}\n): Promise<DepositHistoryResponse> {\n // Validate user address\n if (!userAddress || typeof userAddress !== 'string') {\n throw new Error('User address is required and must be a string');\n }\n\n // Default backend URL - can be overridden via options\n const baseUrl = options.url || 'http://localhost:3000';\n\n try {\n const response = await fetch(\n `${baseUrl}/user-upload-history?userAddress=${encodeURIComponent(userAddress)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n errorData.message ||\n `Failed to fetch deposit history: ${response.status} ${response.statusText}`\n );\n }\n\n const data: DepositHistoryResponse = await response.json();\n\n // Validate response structure\n if (typeof data !== 'object' || data === null) {\n throw new Error('Invalid response format from server');\n }\n\n if (typeof data.userAddress !== 'string') {\n throw new Error('Invalid userAddress in response');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error('Unknown error occurred while fetching deposit history');\n }\n}\n","import { Client, ClientOptions } from './client';\n\nexport const useDeposit = (environment: ClientOptions['environment']) => {\n const client = new Client({ environment: environment || 'testnet' });\n return client;\n};\n"],"mappings":"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","names":["index_exports","__export","Client","Environment","createDepositTxn","fetchUserDepositHistory","getRpcUrl","useDeposit","__toCommonJS","import_web3","import_web3","NODE_ENV","ENDPOINT","createDepositTxn","file","duration","payer","connection","signTransaction","formData","f","isMultipleFiles","uploadErr","depositReq","ENDPOINT","depositRes","latestBlockhash","instructions","depositInstruction","k","tx","signedTx","signature","confirmation","uploadForm","fileUploadReq","err","data","fileUploadRes","error","fetchUserDepositHistory","userAddress","options","baseUrl","response","errorData","data","error","Environment","getRpcUrl","env","Client","options","file","duration","totalLamports","acc","f","payer","durationDays","signTransaction","connection","createDepositTxn","userAddress","fetchUserDepositHistory","useDeposit","environment","Client"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/constants.ts","../src/payment.ts","../src/upload-history.ts","../src/hooks.ts"],"sourcesContent":["export * from './client';\nexport * from './hooks';\nexport * from './payment';\nexport * from './types';\nexport * from './upload-history';\n","import { Connection, PublicKey, Transaction } from '@solana/web3.js';\nimport {\n DAY_TIME_IN_SECONDS,\n getAmountInLamports,\n ONE_BILLION_LAMPORTS,\n} from './constants';\nimport {\n createDepositTxn,\n getStorageRenewalCost,\n renewStorageTxn,\n} from './payment';\nimport {\n CreateDepositArgs,\n StorageRenewalCost,\n StorageRenewalParams,\n UploadResult,\n} from './types';\nimport { getUserUploadHistory } from './upload-history';\n\nexport enum Environment {\n mainnet = 'mainnet-beta',\n testnet = 'testnet',\n devnet = 'devnet',\n}\n\nexport function getRpcUrl(env: Environment): string {\n switch (env) {\n case Environment.mainnet:\n return 'https://api.mainnet-beta.solana.com';\n case Environment.testnet:\n return 'https://api.testnet.solana.com';\n case Environment.devnet:\n return 'https://api.devnet.solana.com';\n default:\n throw new Error(`Unsupported environment: ${env}`);\n }\n}\n\nexport interface ClientOptions {\n /** Solana RPC endpoint to use for chain interactions */\n environment: Environment;\n}\n\nexport interface UploadParams\n extends Pick<CreateDepositArgs, 'signTransaction' | 'userEmail'> {\n /** Wallet public key of the payer */\n payer: PublicKey;\n /** File(s) to be stored */\n file: File[];\n /** Duration in days to store the data */\n durationDays: number;\n}\n\n/**\n * @deprecated Use {@link UploadParams} instead.\n */\nexport type DepositParams = UploadParams;\n\n/**\n * Solana Storage Client — simplified (no fee estimation)\n */\nexport class Client {\n private rpcUrl: string;\n\n constructor(options: ClientOptions) {\n this.rpcUrl = getRpcUrl(options.environment);\n }\n\n /**\n * Creates a deposit transaction ready to be signed & sent by user's wallet.\n *\n * @param {Object} params\n * @param {PublicKey} params.payer - The public key (wallet address) of the connected wallet.\n * @param {File} params.file - The file to be uploaded.\n * @param {number} params.durationDays - How long (in days) the file should be stored.\n * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction -\n * A callback function to authorize the transaction via the Solana wallet library.\n *\n * @example\n * const { publicKey, signTransaction } = useSolanaWallet();\n * const result = await createDeposit({\n * payer: publicKey,\n * file,\n * durationDays: 30,\n * signTransaction,\n * });\n *\n * @returns {Promise<UploadResult>} The upload result after transaction is processed.\n */\n async createDeposit({\n payer,\n file,\n durationDays,\n signTransaction,\n userEmail,\n }: UploadParams): Promise<UploadResult> {\n console.log('Creating deposit transaction with environment:', this.rpcUrl);\n const connection = new Connection(this.rpcUrl, 'confirmed');\n\n return await createDepositTxn({\n file,\n duration: durationDays * DAY_TIME_IN_SECONDS,\n payer,\n connection,\n signTransaction,\n userEmail,\n });\n }\n\n /**\n * estimates the cost for a file based on the amount of days it should be stored for\n * @param {File} file - a file to be uploaded\n * @param {number} duration - how long (in seconds) the file should be stored for\n */\n estimateStorageCost = (file: File[], duration: number) => {\n const ratePerBytePerDay = 1000; // this would be obtained from the program config later\n const fileSizeInBytes = file.reduce((acc, f) => acc + f.size, 0);\n const totalLamports = getAmountInLamports(\n fileSizeInBytes,\n ratePerBytePerDay,\n duration\n );\n const totalSOL = totalLamports / ONE_BILLION_LAMPORTS;\n\n return {\n sol: totalSOL,\n lamports: totalLamports,\n };\n };\n\n async getUserUploadHistory(userAddress: string) {\n const response = await getUserUploadHistory(userAddress);\n return response;\n }\n\n /**\n * Get cost estimate for renewing storage duration\n *\n * @param {string} cid - Content identifier of the file to renew\n * @param {number} duration - Number of additional days to extend storage\n *\n * @example\n * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);\n * console.log(`Renewal cost: ${quote.costInSOL} SOL`);\n *\n * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details\n */\n async getStorageRenewalCost(\n cid: string,\n duration: number\n ): Promise<StorageRenewalCost | null> {\n return await getStorageRenewalCost(cid, duration);\n }\n\n /**\n * Renew storage for an existing deposit\n *\n * @param {Object} params\n * @param {string} params.cid - Content identifier of the file to renew\n * @param {number} params.duration - Number of additional days to extend storage\n * @param {PublicKey} params.payer - Wallet public key paying for the renewal\n * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback\n *\n * @example\n * const { publicKey, signTransaction } = useSolanaWallet();\n * const result = await client.renewStorage({\n * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',\n * duration: 30,\n * payer: publicKey,\n * signTransaction,\n * });\n *\n * @returns {Promise<UploadResult>} Result of the renewal transaction\n */\n async renewStorageDuration({\n cid,\n duration,\n payer,\n signTransaction,\n }: StorageRenewalParams): Promise<UploadResult> {\n const connection = new Connection(this.rpcUrl, 'confirmed');\n\n return await renewStorageTxn({\n cid,\n duration,\n payer,\n connection,\n signTransaction,\n });\n }\n}\n","const { NODE_ENV } = process.env;\n\nexport const ENDPOINT =\n NODE_ENV === 'development'\n ? 'http://localhost:5040'\n : 'https://storacha-solana-sdk-bshc.onrender.com';\n\nexport const DAY_TIME_IN_SECONDS = 86400;\n\n/** 1 SOL in Lamports */\nexport const ONE_BILLION_LAMPORTS = 1_000_000_000;\n\n/**\n * Get amount in Lamports\n * @param fileSize - size of the file\n * @param rate - rate per byte of a file per day\n * @param duration - storage duration\n * @returns\n */\nexport const getAmountInLamports = (\n fileSize: number,\n rate: number,\n duration: number\n): number => {\n const amountInLamports = fileSize * duration * rate;\n return amountInLamports;\n};\n","import { Signature } from '@solana/kit';\nimport {\n PublicKey,\n Transaction,\n TransactionInstruction,\n SendTransactionError,\n} from '@solana/web3.js';\nimport { ENDPOINT } from './constants';\nimport {\n CreateDepositArgs,\n DepositResult,\n RenewStorageDurationArgs,\n StorageRenewalCost,\n StorageRenewalResult,\n UploadResult,\n} from './types';\n\n/**\n * Calls the deposit API for on-chain storage and returns a Transaction\n * which must be signed and sent externally by the user.\n *\n * @param params - {\n * cid: string;\n * file: File;\n * duration: number;\n * payer: PublicKey;\n * connection: Connection;\n * }\n * @returns Transaction\n */\nexport async function createDepositTxn({\n file,\n duration,\n payer,\n connection,\n signTransaction,\n userEmail,\n}: CreateDepositArgs): Promise<UploadResult> {\n try {\n const formData = new FormData();\n file.forEach((f) => formData.append('file', f));\n formData.append('duration', duration.toString());\n formData.append('publicKey', payer.toBase58());\n if (userEmail) {\n formData.append('userEmail', userEmail);\n }\n\n const isMultipleFiles = file.length > 1;\n\n let uploadErr;\n\n const depositReq = await fetch(`${ENDPOINT}/api/solana/deposit`, {\n method: 'POST',\n body: formData,\n });\n if (!depositReq.ok) throw new Error('Failed to get deposit instructions');\n\n const depositRes: DepositResult = await depositReq.json();\n if (!depositRes.instructions || !depositRes.instructions.length)\n throw new Error('No instructions from deposit API');\n\n const latestBlockhash = await connection.getLatestBlockhash('confirmed');\n const instructions = depositRes.instructions[0];\n\n const depositInstruction = new TransactionInstruction({\n programId: new PublicKey(instructions.programId),\n keys: instructions.keys.map((k) => ({\n pubkey: new PublicKey(k.pubkey),\n isSigner: k.isSigner,\n isWritable: k.isWritable,\n })),\n data: Buffer.from(instructions.data, 'base64'),\n });\n\n const tx = new Transaction();\n tx.recentBlockhash = latestBlockhash.blockhash;\n tx.feePayer = payer;\n tx.add(depositInstruction);\n\n const signedTx = await signTransaction(tx);\n let signature: string;\n\n try {\n signature = await connection.sendRawTransaction(signedTx.serialize(), {\n skipPreflight: false, // not sure we should be disabling this verification step\n preflightCommitment: 'confirmed',\n });\n } catch (err) {\n if (err instanceof SendTransactionError) {\n const logs = err.logs ?? [];\n\n const isDuplicateUpload = logs.some((log) =>\n log.includes('already in use')\n );\n\n if (isDuplicateUpload) {\n throw new Error(\n 'This file has already been uploaded. You can find it in your dashboard.'\n );\n }\n\n throw new Error(\n 'Transaction failed during simulation. Please try again.'\n );\n }\n\n throw err;\n }\n const confirmation = await connection.confirmTransaction(\n {\n signature,\n blockhash: latestBlockhash.blockhash,\n lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,\n },\n 'confirmed'\n );\n\n if (confirmation.value.err) {\n console.error(\n 'Failed to confirm this transaction:',\n confirmation.value.err\n );\n throw new Error(\n `Transaction failed: ${JSON.stringify(confirmation.value.err)}`\n );\n }\n\n try {\n await fetch(`${ENDPOINT}/api/user/update-transaction-hash`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n cid: depositRes.cid,\n transactionHash: signature,\n }),\n });\n } catch (err) {\n console.warn('Failed to update transaction hash:', err);\n }\n\n if (depositRes.error) {\n uploadErr = depositRes.error;\n }\n\n const uploadForm = new FormData();\n file.forEach((f) => uploadForm.append('file', f));\n\n let fileUploadReq;\n // calls the upload functionality on our server with the file when deposit is successful\n if (isMultipleFiles) {\n fileUploadReq = await fetch(\n `${ENDPOINT}/api/user/upload-files?cid=${encodeURIComponent(\n depositRes.cid\n )}`,\n {\n method: 'POST',\n body: uploadForm,\n }\n );\n } else {\n fileUploadReq = await fetch(\n `${ENDPOINT}/api/user/upload-file?cid=${encodeURIComponent(\n depositRes.cid\n )}`,\n {\n method: 'POST',\n body: uploadForm,\n }\n );\n }\n\n if (!fileUploadReq.ok) {\n let err = 'Unknown error';\n try {\n const data: DepositResult = await fileUploadReq.json();\n err = data.message || data.error || err;\n } catch {}\n throw new Error('Deposit API error: ' + err);\n }\n\n const fileUploadRes: Pick<DepositResult, 'object' | 'cid' | 'message'> =\n await fileUploadReq?.json();\n\n return {\n signature: signature as Signature,\n success: true,\n cid: depositRes.cid,\n url: fileUploadRes.object.url,\n message: fileUploadRes.object.message,\n fileInfo: fileUploadRes.object\n ? {\n filename: fileUploadRes.object.fileInfo?.filename || '',\n size: fileUploadRes?.object?.fileInfo?.size || 0,\n uploadedAt: fileUploadRes?.object?.fileInfo?.uploadedAt || '',\n type: fileUploadRes?.object?.fileInfo?.type || '',\n }\n : undefined,\n };\n } catch (error) {\n console.error(error);\n if (error instanceof Error) {\n console.error('Error name:', error.name);\n console.error('Error message:', error.message);\n console.error('Error stack:', error.stack);\n }\n\n return {\n signature: '' as Signature,\n success: false,\n cid: '',\n url: '',\n message: '',\n fileInfo: undefined,\n error: error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n}\n\n/**\n * Get cost estimate for renewing storage duration\n *\n * @param {string} cid - Content identifier of the uploaded data to renew\n * @param {number} duration - Number of additional days to extend storage\n *\n * @example\n * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);\n * console.log(`Renewal cost: ${quote.costInSOL} SOL`);\n *\n * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details\n */\nexport async function getStorageRenewalCost(\n cid: string,\n duration: number\n): Promise<StorageRenewalCost | null> {\n try {\n const request = await fetch(\n `${ENDPOINT}/api/user/renewal-cost?cid=${encodeURIComponent(\n cid\n )}&duration=${duration}`,\n {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n }\n );\n\n if (!request.ok) {\n const response = await request.json();\n throw new Error(response.message || 'Failed to get storage renewal cost');\n }\n\n return await request.json();\n } catch (error) {\n console.error('Failed to get storage renewal cost', error);\n return null;\n }\n}\n\n/**\n * Renew storage for an existing deposit\n *\n * @param {Object} params\n * @param {string} params.cid - Content identifier of the uploaded data to renew\n * @param {number} params.duration - Number of additional days to extend storage\n * @param {PublicKey} params.payer - Wallet public key paying for the renewal\n * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback\n *\n * @example\n * const { publicKey, signTransaction } = useSolanaWallet();\n * const result = await client.renewStorage({\n * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',\n * additionalDays: 30,\n * payer: publicKey,\n * signTransaction,\n * });\n *\n * @returns {Promise<UploadResult>} Result of the renewal transaction\n */\nexport async function renewStorageTxn({\n cid,\n duration,\n payer,\n connection,\n signTransaction,\n}: RenewStorageDurationArgs): Promise<UploadResult> {\n const renewalTransactionIx = await fetch(\n `${ENDPOINT}/api/user/renew-storage`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n cid,\n duration,\n publicKey: payer.toString(),\n }),\n }\n );\n\n if (!renewalTransactionIx.ok) {\n const errorData = await renewalTransactionIx.json().catch(() => ({}));\n throw new Error(\n errorData.message || 'Failed to create renewal transaction'\n );\n }\n\n const renewalData: StorageRenewalResult = await renewalTransactionIx.json();\n const transaction = new Transaction();\n\n renewalData.instructions.forEach((ix) => {\n transaction.add({\n programId: new PublicKey(ix.programId),\n keys: ix.keys.map((key) => ({\n pubkey: new PublicKey(key.pubkey),\n isSigner: key.isSigner,\n isWritable: key.isWritable,\n })),\n data: Buffer.from(ix.data, 'base64'),\n });\n });\n\n const { blockhash } = await connection.getLatestBlockhash();\n transaction.recentBlockhash = blockhash;\n transaction.feePayer = payer;\n\n const signed = await signTransaction(transaction);\n const signature = await connection.sendRawTransaction(signed.serialize());\n await connection.confirmTransaction(signature, 'confirmed');\n\n const confirmRenewalTx = await fetch(`${ENDPOINT}/api/user/confirm-renewal`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n cid,\n duration,\n transactionHash: signature,\n }),\n });\n\n if (!confirmRenewalTx.ok) {\n console.error('Failed to confirm renewal on backend');\n }\n\n return {\n success: true,\n cid,\n signature: signature as Signature,\n url: `https://w3s.link/ipfs/${cid}`,\n message: 'Storage renewed successfully',\n };\n}\n","import { ENDPOINT } from './constants';\nimport { ServerOptions, UploadHistoryResponse } from './types';\n\n/**\n * Get the upload history for a given user address from the backend\n *\n * @param userAddress - The wallet address of the user to fetch upload history for\n * @param options - Optional server configuration\n * @returns Promise<UploadHistoryResponse> - The user's upload history\n *\n * @example\n * ```typescript\n * const history = await getUserUploadHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');\n * console.log('User upload history:', history.userHistory);\n * ```\n *\n * @throws {Error} When the user address is invalid or the request fails\n */\nexport async function getUserUploadHistory(\n userAddress: string,\n options: ServerOptions = {}\n): Promise<UploadHistoryResponse> {\n // Validate user address\n if (!userAddress || typeof userAddress !== 'string') {\n throw new Error('User address is required and must be a string');\n }\n\n // Use ENDPOINT constant, or allow override via options\n const baseUrl = options.url || ENDPOINT;\n\n try {\n const response = await fetch(\n `${baseUrl}/api/user/user-upload-history?userAddress=${encodeURIComponent(userAddress)}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(\n errorData.message ||\n `Failed to fetch upload history: ${response.status} ${response.statusText}`\n );\n }\n\n const data: UploadHistoryResponse = await response.json();\n\n // Validate response structure\n if (typeof data !== 'object' || data === null) {\n throw new Error('Invalid response format from server');\n }\n\n if (typeof data.userAddress !== 'string') {\n throw new Error('Invalid userAddress in response');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error('Unknown error occurred while fetching upload history');\n }\n}\n\n/**\n * @deprecated Use getUserUploadHistory instead\n */\nexport { getUserUploadHistory as fetchUserUploadHistory };\n\n/**\n * @deprecated Use getUserUploadHistory instead\n */\nexport { getUserUploadHistory as fetchUserDepositHistory };\n","import { Client, ClientOptions } from './client';\n\nexport const useUpload = (environment: ClientOptions['environment']) => {\n const client = new Client({ environment: environment || 'testnet' });\n return client;\n};\n\n/**\n * @deprecated Use {@link useUpload} instead.\n */\nexport { useUpload as useDeposit };\n"],"mappings":"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","names":["index_exports","__export","Client","Environment","createDepositTxn","getUserUploadHistory","getRpcUrl","getStorageRenewalCost","renewStorageTxn","useUpload","__toCommonJS","import_web3","NODE_ENV","ENDPOINT","DAY_TIME_IN_SECONDS","ONE_BILLION_LAMPORTS","getAmountInLamports","fileSize","rate","duration","import_web3","createDepositTxn","file","duration","payer","connection","signTransaction","userEmail","formData","f","isMultipleFiles","uploadErr","depositReq","ENDPOINT","depositRes","latestBlockhash","instructions","depositInstruction","k","tx","signedTx","signature","err","log","confirmation","uploadForm","fileUploadReq","data","fileUploadRes","error","getStorageRenewalCost","cid","request","response","renewStorageTxn","renewalTransactionIx","errorData","renewalData","transaction","ix","key","blockhash","signed","getUserUploadHistory","userAddress","options","baseUrl","ENDPOINT","response","errorData","data","error","Environment","getRpcUrl","env","Client","options","file","duration","fileSizeInBytes","acc","totalLamports","getAmountInLamports","ONE_BILLION_LAMPORTS","payer","durationDays","signTransaction","userEmail","connection","createDepositTxn","DAY_TIME_IN_SECONDS","userAddress","getUserUploadHistory","cid","getStorageRenewalCost","renewStorageTxn","useUpload","environment","Client"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Address, Signature } from '@solana/kit';
2
- import { PublicKey, Connection, Transaction } from '@solana/web3.js';
2
+ import { PublicKey, Connection, Transaction as Transaction$1 } from '@solana/web3.js';
3
3
 
4
4
  interface ServerOptions {
5
5
  /** URL pointing to the backend (mostly Storacha's) */
@@ -116,38 +116,153 @@ interface CreateDepositArgs extends Omit<OnChainDeposit, 'depositAmount' | 'depo
116
116
  * const {publickKey, signTransaction} = useSolanaWallet()
117
117
  * const signTransaction = await signTransaction(tx)
118
118
  * */
119
- signTransaction: (tx: Transaction) => Promise<Transaction>;
119
+ signTransaction: (tx: Transaction$1) => Promise<Transaction$1>;
120
+ /** Optional user email for expiration notifications */
121
+ userEmail?: string;
122
+ }
123
+ /** Arguments for renewing storage duration */
124
+ interface StorageRenewalParams extends Pick<CreateDepositArgs, 'payer' | 'signTransaction'> {
125
+ /** Content identifier of the uploaded data to be renewed */
126
+ cid: string;
127
+ /** Duration in days to extend storage */
128
+ duration: number;
129
+ }
130
+ /** Internal arguments for renewStorageTxn */
131
+ interface RenewStorageDurationArgs extends Pick<CreateDepositArgs, 'payer' | 'signTransaction' | 'connection'> {
132
+ /** Content identifier of the uploaded data to be renewed */
133
+ cid: string;
134
+ /** Duration in days to extend storage */
135
+ duration: number;
136
+ }
137
+ /**
138
+ * Transaction record for an upload (initial deposit or renewal)
139
+ */
140
+ interface Transaction {
141
+ /** Unique identifier for the transaction */
142
+ id: number;
143
+ /** ID of the associated deposit */
144
+ depositId: number;
145
+ /** Content identifier of the upload */
146
+ contentCid: string;
147
+ /** Solana transaction hash */
148
+ transactionHash: string;
149
+ /** Type of transaction: 'initial_deposit' | 'renewal' */
150
+ transactionType: string;
151
+ /** Amount paid in lamports */
152
+ amountInLamports: number;
153
+ /** Duration in days purchased */
154
+ durationDays: number;
155
+ /** Timestamp when the transaction was created */
156
+ createdAt: string;
120
157
  }
121
158
  /**
122
- * Individual deposit history entry from the backend
159
+ * Individual upload history entry from the server
123
160
  */
124
- interface DepositHistoryEntry {
161
+ interface UploadHistory {
125
162
  /** Unique identifier for the deposit */
126
163
  id: number;
127
164
  /** User's wallet address (deposit key) */
128
- deposit_key: string;
165
+ depositKey: string;
129
166
  /** Content identifier of the uploaded file */
130
- content_cid: string;
167
+ contentCid: string;
131
168
  /** Duration in days the file is stored for */
132
- duration_days: number;
169
+ durationDays: number;
133
170
  /** Amount deposited in lamports */
134
- deposit_amount: number;
171
+ depositAmount: number;
135
172
  /** Slot when the deposit was made */
136
- deposit_slot: number;
173
+ depositSlot: number;
137
174
  /** Last slot when rewards were claimed */
138
- last_claimed_slot: number;
175
+ lastClaimedSlot: number;
139
176
  /** Timestamp when the deposit was created */
140
- created_at: string;
177
+ createdAt: string;
178
+ /** Expiration date of the upload */
179
+ expiresAt?: string;
180
+ /** User email for notifications */
181
+ userEmail?: string;
182
+ /** Name of the uploaded file */
183
+ fileName?: string;
184
+ /** MIME type of the file */
185
+ fileType?: string;
186
+ /** Size of the file in bytes */
187
+ fileSize?: number;
188
+ /** Solana transaction hash */
189
+ transactionHash?: string;
190
+ /** Deletion status: 'active' | 'warned' | 'deleted' */
191
+ deletionStatus?: string;
192
+ /** Timestamp when warning email was sent */
193
+ warningSentAt?: string;
194
+ /** Optional array of all transactions for this upload */
195
+ transactions?: Transaction[];
141
196
  }
197
+ /**
198
+ * @deprecated Use UploadHistory instead
199
+ */
200
+ type DepositHistoryEntry = UploadHistory;
142
201
  /**
143
202
  * Response from the getUserUploadHistory endpoint
144
203
  */
145
- interface DepositHistoryResponse {
146
- /** Array of deposit history entries */
147
- userHistory: DepositHistoryEntry[] | null;
204
+ interface UploadHistoryResponse {
205
+ /** Array of upload history entries */
206
+ userHistory: UploadHistory[] | null;
148
207
  /** The user address that was queried */
149
208
  userAddress: string;
150
209
  }
210
+ /**
211
+ * @deprecated Use UploadHistoryResponse instead
212
+ */
213
+ type DepositHistoryResponse = UploadHistoryResponse;
214
+ /**
215
+ * Storage renewal cost estimation
216
+ */
217
+ type StorageRenewalCost = {
218
+ /** New expiration date after renewal */
219
+ newExpirationDate: string;
220
+ /** Current expiration date before renewal */
221
+ currentExpirationDate: string;
222
+ /** Number of additional days being added */
223
+ additionalDays: string;
224
+ /** Cost of renewal in lamports */
225
+ costInLamports: number;
226
+ /** Cost of renewal in SOL */
227
+ costInSOL: number;
228
+ /** Details about the file being renewed */
229
+ fileDetails: {
230
+ /** Content identifier */
231
+ cid: string;
232
+ /** Name of the file */
233
+ fileName: string;
234
+ /** Size of the file in bytes */
235
+ fileSize: number;
236
+ };
237
+ };
238
+ /**
239
+ * Storage renewal transaction result
240
+ */
241
+ type StorageRenewalResult = {
242
+ /** Content identifier of the uploaded data to be renewed */
243
+ cid: string;
244
+ /** Status message about the renewal */
245
+ message: string;
246
+ /** Transaction instructions for the user to sign */
247
+ instructions: Array<{
248
+ programId: string;
249
+ keys: Array<{
250
+ pubkey: string;
251
+ isSigner: boolean;
252
+ isWritable: boolean;
253
+ }>;
254
+ data: string;
255
+ }>;
256
+ /** Number of additional days being added */
257
+ duration: number;
258
+ /** Cost breakdown for the renewal */
259
+ cost: {
260
+ /** Cost in lamports */
261
+ lamports: number;
262
+ /** Cost in SOL */
263
+ sol: number;
264
+ };
265
+ };
151
266
 
152
267
  declare enum Environment {
153
268
  mainnet = "mainnet-beta",
@@ -159,7 +274,7 @@ interface ClientOptions {
159
274
  /** Solana RPC endpoint to use for chain interactions */
160
275
  environment: Environment;
161
276
  }
162
- interface DepositParams extends Pick<CreateDepositArgs, 'signTransaction'> {
277
+ interface UploadParams extends Pick<CreateDepositArgs, 'signTransaction' | 'userEmail'> {
163
278
  /** Wallet public key of the payer */
164
279
  payer: PublicKey;
165
280
  /** File(s) to be stored */
@@ -167,6 +282,10 @@ interface DepositParams extends Pick<CreateDepositArgs, 'signTransaction'> {
167
282
  /** Duration in days to store the data */
168
283
  durationDays: number;
169
284
  }
285
+ /**
286
+ * @deprecated Use {@link UploadParams} instead.
287
+ */
288
+ type DepositParams = UploadParams;
170
289
  /**
171
290
  * Solana Storage Client — simplified (no fee estimation)
172
291
  */
@@ -194,7 +313,7 @@ declare class Client {
194
313
  *
195
314
  * @returns {Promise<UploadResult>} The upload result after transaction is processed.
196
315
  */
197
- createDeposit({ payer, file, durationDays, signTransaction, }: DepositParams): Promise<UploadResult>;
316
+ createDeposit({ payer, file, durationDays, signTransaction, userEmail, }: UploadParams): Promise<UploadResult>;
198
317
  /**
199
318
  * estimates the cost for a file based on the amount of days it should be stored for
200
319
  * @param {File} file - a file to be uploaded
@@ -204,9 +323,45 @@ declare class Client {
204
323
  sol: number;
205
324
  lamports: number;
206
325
  };
207
- getUserUploadHistory(userAddress: string): Promise<DepositHistoryResponse>;
326
+ getUserUploadHistory(userAddress: string): Promise<UploadHistoryResponse>;
327
+ /**
328
+ * Get cost estimate for renewing storage duration
329
+ *
330
+ * @param {string} cid - Content identifier of the file to renew
331
+ * @param {number} duration - Number of additional days to extend storage
332
+ *
333
+ * @example
334
+ * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);
335
+ * console.log(`Renewal cost: ${quote.costInSOL} SOL`);
336
+ *
337
+ * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details
338
+ */
339
+ getStorageRenewalCost(cid: string, duration: number): Promise<StorageRenewalCost | null>;
340
+ /**
341
+ * Renew storage for an existing deposit
342
+ *
343
+ * @param {Object} params
344
+ * @param {string} params.cid - Content identifier of the file to renew
345
+ * @param {number} params.duration - Number of additional days to extend storage
346
+ * @param {PublicKey} params.payer - Wallet public key paying for the renewal
347
+ * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback
348
+ *
349
+ * @example
350
+ * const { publicKey, signTransaction } = useSolanaWallet();
351
+ * const result = await client.renewStorage({
352
+ * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',
353
+ * duration: 30,
354
+ * payer: publicKey,
355
+ * signTransaction,
356
+ * });
357
+ *
358
+ * @returns {Promise<UploadResult>} Result of the renewal transaction
359
+ */
360
+ renewStorageDuration({ cid, duration, payer, signTransaction, }: StorageRenewalParams): Promise<UploadResult>;
208
361
  }
209
362
 
363
+ declare const useUpload: (environment: ClientOptions["environment"]) => Client;
364
+
210
365
  /**
211
366
  * Calls the deposit API for on-chain storage and returns a Transaction
212
367
  * which must be signed and sent externally by the user.
@@ -220,25 +375,57 @@ declare class Client {
220
375
  * }
221
376
  * @returns Transaction
222
377
  */
223
- declare function createDepositTxn({ file, duration, payer, connection, signTransaction, }: CreateDepositArgs): Promise<UploadResult>;
224
-
225
- declare const useDeposit: (environment: ClientOptions["environment"]) => Client;
378
+ declare function createDepositTxn({ file, duration, payer, connection, signTransaction, userEmail, }: CreateDepositArgs): Promise<UploadResult>;
379
+ /**
380
+ * Get cost estimate for renewing storage duration
381
+ *
382
+ * @param {string} cid - Content identifier of the uploaded data to renew
383
+ * @param {number} duration - Number of additional days to extend storage
384
+ *
385
+ * @example
386
+ * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);
387
+ * console.log(`Renewal cost: ${quote.costInSOL} SOL`);
388
+ *
389
+ * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details
390
+ */
391
+ declare function getStorageRenewalCost(cid: string, duration: number): Promise<StorageRenewalCost | null>;
392
+ /**
393
+ * Renew storage for an existing deposit
394
+ *
395
+ * @param {Object} params
396
+ * @param {string} params.cid - Content identifier of the uploaded data to renew
397
+ * @param {number} params.duration - Number of additional days to extend storage
398
+ * @param {PublicKey} params.payer - Wallet public key paying for the renewal
399
+ * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback
400
+ *
401
+ * @example
402
+ * const { publicKey, signTransaction } = useSolanaWallet();
403
+ * const result = await client.renewStorage({
404
+ * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',
405
+ * additionalDays: 30,
406
+ * payer: publicKey,
407
+ * signTransaction,
408
+ * });
409
+ *
410
+ * @returns {Promise<UploadResult>} Result of the renewal transaction
411
+ */
412
+ declare function renewStorageTxn({ cid, duration, payer, connection, signTransaction, }: RenewStorageDurationArgs): Promise<UploadResult>;
226
413
 
227
414
  /**
228
- * Fetches the deposit history for a given user address from the backend
415
+ * Get the upload history for a given user address from the backend
229
416
  *
230
- * @param userAddress - The wallet address of the user to fetch deposit history for
417
+ * @param userAddress - The wallet address of the user to fetch upload history for
231
418
  * @param options - Optional server configuration
232
- * @returns Promise<DepositHistoryResponse> - The user's deposit history
419
+ * @returns Promise<UploadHistoryResponse> - The user's upload history
233
420
  *
234
421
  * @example
235
422
  * ```typescript
236
- * const history = await fetchUserDepositHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');
237
- * console.log('User deposit history:', history.userHistory);
423
+ * const history = await getUserUploadHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');
424
+ * console.log('User upload history:', history.userHistory);
238
425
  * ```
239
426
  *
240
427
  * @throws {Error} When the user address is invalid or the request fails
241
428
  */
242
- declare function fetchUserDepositHistory(userAddress: string, options?: ServerOptions): Promise<DepositHistoryResponse>;
429
+ declare function getUserUploadHistory(userAddress: string, options?: ServerOptions): Promise<UploadHistoryResponse>;
243
430
 
244
- export { Client, type ClientOptions, type CreateDepositArgs, type DepositHistoryEntry, type DepositHistoryResponse, type DepositParams, type DepositResult, Environment, type OnChainConfig, type OnChainDeposit, type ServerOptions, type UploadOptions, type UploadResult, type WalletItem, createDepositTxn, fetchUserDepositHistory, getRpcUrl, useDeposit };
431
+ export { Client, type ClientOptions, type CreateDepositArgs, type DepositHistoryEntry, type DepositHistoryResponse, type DepositParams, type DepositResult, Environment, type OnChainConfig, type OnChainDeposit, type RenewStorageDurationArgs, type ServerOptions, type StorageRenewalCost, type StorageRenewalParams, type StorageRenewalResult, type Transaction, type UploadHistory, type UploadHistoryResponse, type UploadOptions, type UploadParams, type UploadResult, type WalletItem, createDepositTxn, getUserUploadHistory as fetchUserDepositHistory, getUserUploadHistory as fetchUserUploadHistory, getRpcUrl, getStorageRenewalCost, getUserUploadHistory, renewStorageTxn, useUpload as useDeposit, useUpload };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Address, Signature } from '@solana/kit';
2
- import { PublicKey, Connection, Transaction } from '@solana/web3.js';
2
+ import { PublicKey, Connection, Transaction as Transaction$1 } from '@solana/web3.js';
3
3
 
4
4
  interface ServerOptions {
5
5
  /** URL pointing to the backend (mostly Storacha's) */
@@ -116,38 +116,153 @@ interface CreateDepositArgs extends Omit<OnChainDeposit, 'depositAmount' | 'depo
116
116
  * const {publickKey, signTransaction} = useSolanaWallet()
117
117
  * const signTransaction = await signTransaction(tx)
118
118
  * */
119
- signTransaction: (tx: Transaction) => Promise<Transaction>;
119
+ signTransaction: (tx: Transaction$1) => Promise<Transaction$1>;
120
+ /** Optional user email for expiration notifications */
121
+ userEmail?: string;
122
+ }
123
+ /** Arguments for renewing storage duration */
124
+ interface StorageRenewalParams extends Pick<CreateDepositArgs, 'payer' | 'signTransaction'> {
125
+ /** Content identifier of the uploaded data to be renewed */
126
+ cid: string;
127
+ /** Duration in days to extend storage */
128
+ duration: number;
129
+ }
130
+ /** Internal arguments for renewStorageTxn */
131
+ interface RenewStorageDurationArgs extends Pick<CreateDepositArgs, 'payer' | 'signTransaction' | 'connection'> {
132
+ /** Content identifier of the uploaded data to be renewed */
133
+ cid: string;
134
+ /** Duration in days to extend storage */
135
+ duration: number;
136
+ }
137
+ /**
138
+ * Transaction record for an upload (initial deposit or renewal)
139
+ */
140
+ interface Transaction {
141
+ /** Unique identifier for the transaction */
142
+ id: number;
143
+ /** ID of the associated deposit */
144
+ depositId: number;
145
+ /** Content identifier of the upload */
146
+ contentCid: string;
147
+ /** Solana transaction hash */
148
+ transactionHash: string;
149
+ /** Type of transaction: 'initial_deposit' | 'renewal' */
150
+ transactionType: string;
151
+ /** Amount paid in lamports */
152
+ amountInLamports: number;
153
+ /** Duration in days purchased */
154
+ durationDays: number;
155
+ /** Timestamp when the transaction was created */
156
+ createdAt: string;
120
157
  }
121
158
  /**
122
- * Individual deposit history entry from the backend
159
+ * Individual upload history entry from the server
123
160
  */
124
- interface DepositHistoryEntry {
161
+ interface UploadHistory {
125
162
  /** Unique identifier for the deposit */
126
163
  id: number;
127
164
  /** User's wallet address (deposit key) */
128
- deposit_key: string;
165
+ depositKey: string;
129
166
  /** Content identifier of the uploaded file */
130
- content_cid: string;
167
+ contentCid: string;
131
168
  /** Duration in days the file is stored for */
132
- duration_days: number;
169
+ durationDays: number;
133
170
  /** Amount deposited in lamports */
134
- deposit_amount: number;
171
+ depositAmount: number;
135
172
  /** Slot when the deposit was made */
136
- deposit_slot: number;
173
+ depositSlot: number;
137
174
  /** Last slot when rewards were claimed */
138
- last_claimed_slot: number;
175
+ lastClaimedSlot: number;
139
176
  /** Timestamp when the deposit was created */
140
- created_at: string;
177
+ createdAt: string;
178
+ /** Expiration date of the upload */
179
+ expiresAt?: string;
180
+ /** User email for notifications */
181
+ userEmail?: string;
182
+ /** Name of the uploaded file */
183
+ fileName?: string;
184
+ /** MIME type of the file */
185
+ fileType?: string;
186
+ /** Size of the file in bytes */
187
+ fileSize?: number;
188
+ /** Solana transaction hash */
189
+ transactionHash?: string;
190
+ /** Deletion status: 'active' | 'warned' | 'deleted' */
191
+ deletionStatus?: string;
192
+ /** Timestamp when warning email was sent */
193
+ warningSentAt?: string;
194
+ /** Optional array of all transactions for this upload */
195
+ transactions?: Transaction[];
141
196
  }
197
+ /**
198
+ * @deprecated Use UploadHistory instead
199
+ */
200
+ type DepositHistoryEntry = UploadHistory;
142
201
  /**
143
202
  * Response from the getUserUploadHistory endpoint
144
203
  */
145
- interface DepositHistoryResponse {
146
- /** Array of deposit history entries */
147
- userHistory: DepositHistoryEntry[] | null;
204
+ interface UploadHistoryResponse {
205
+ /** Array of upload history entries */
206
+ userHistory: UploadHistory[] | null;
148
207
  /** The user address that was queried */
149
208
  userAddress: string;
150
209
  }
210
+ /**
211
+ * @deprecated Use UploadHistoryResponse instead
212
+ */
213
+ type DepositHistoryResponse = UploadHistoryResponse;
214
+ /**
215
+ * Storage renewal cost estimation
216
+ */
217
+ type StorageRenewalCost = {
218
+ /** New expiration date after renewal */
219
+ newExpirationDate: string;
220
+ /** Current expiration date before renewal */
221
+ currentExpirationDate: string;
222
+ /** Number of additional days being added */
223
+ additionalDays: string;
224
+ /** Cost of renewal in lamports */
225
+ costInLamports: number;
226
+ /** Cost of renewal in SOL */
227
+ costInSOL: number;
228
+ /** Details about the file being renewed */
229
+ fileDetails: {
230
+ /** Content identifier */
231
+ cid: string;
232
+ /** Name of the file */
233
+ fileName: string;
234
+ /** Size of the file in bytes */
235
+ fileSize: number;
236
+ };
237
+ };
238
+ /**
239
+ * Storage renewal transaction result
240
+ */
241
+ type StorageRenewalResult = {
242
+ /** Content identifier of the uploaded data to be renewed */
243
+ cid: string;
244
+ /** Status message about the renewal */
245
+ message: string;
246
+ /** Transaction instructions for the user to sign */
247
+ instructions: Array<{
248
+ programId: string;
249
+ keys: Array<{
250
+ pubkey: string;
251
+ isSigner: boolean;
252
+ isWritable: boolean;
253
+ }>;
254
+ data: string;
255
+ }>;
256
+ /** Number of additional days being added */
257
+ duration: number;
258
+ /** Cost breakdown for the renewal */
259
+ cost: {
260
+ /** Cost in lamports */
261
+ lamports: number;
262
+ /** Cost in SOL */
263
+ sol: number;
264
+ };
265
+ };
151
266
 
152
267
  declare enum Environment {
153
268
  mainnet = "mainnet-beta",
@@ -159,7 +274,7 @@ interface ClientOptions {
159
274
  /** Solana RPC endpoint to use for chain interactions */
160
275
  environment: Environment;
161
276
  }
162
- interface DepositParams extends Pick<CreateDepositArgs, 'signTransaction'> {
277
+ interface UploadParams extends Pick<CreateDepositArgs, 'signTransaction' | 'userEmail'> {
163
278
  /** Wallet public key of the payer */
164
279
  payer: PublicKey;
165
280
  /** File(s) to be stored */
@@ -167,6 +282,10 @@ interface DepositParams extends Pick<CreateDepositArgs, 'signTransaction'> {
167
282
  /** Duration in days to store the data */
168
283
  durationDays: number;
169
284
  }
285
+ /**
286
+ * @deprecated Use {@link UploadParams} instead.
287
+ */
288
+ type DepositParams = UploadParams;
170
289
  /**
171
290
  * Solana Storage Client — simplified (no fee estimation)
172
291
  */
@@ -194,7 +313,7 @@ declare class Client {
194
313
  *
195
314
  * @returns {Promise<UploadResult>} The upload result after transaction is processed.
196
315
  */
197
- createDeposit({ payer, file, durationDays, signTransaction, }: DepositParams): Promise<UploadResult>;
316
+ createDeposit({ payer, file, durationDays, signTransaction, userEmail, }: UploadParams): Promise<UploadResult>;
198
317
  /**
199
318
  * estimates the cost for a file based on the amount of days it should be stored for
200
319
  * @param {File} file - a file to be uploaded
@@ -204,9 +323,45 @@ declare class Client {
204
323
  sol: number;
205
324
  lamports: number;
206
325
  };
207
- getUserUploadHistory(userAddress: string): Promise<DepositHistoryResponse>;
326
+ getUserUploadHistory(userAddress: string): Promise<UploadHistoryResponse>;
327
+ /**
328
+ * Get cost estimate for renewing storage duration
329
+ *
330
+ * @param {string} cid - Content identifier of the file to renew
331
+ * @param {number} duration - Number of additional days to extend storage
332
+ *
333
+ * @example
334
+ * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);
335
+ * console.log(`Renewal cost: ${quote.costInSOL} SOL`);
336
+ *
337
+ * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details
338
+ */
339
+ getStorageRenewalCost(cid: string, duration: number): Promise<StorageRenewalCost | null>;
340
+ /**
341
+ * Renew storage for an existing deposit
342
+ *
343
+ * @param {Object} params
344
+ * @param {string} params.cid - Content identifier of the file to renew
345
+ * @param {number} params.duration - Number of additional days to extend storage
346
+ * @param {PublicKey} params.payer - Wallet public key paying for the renewal
347
+ * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback
348
+ *
349
+ * @example
350
+ * const { publicKey, signTransaction } = useSolanaWallet();
351
+ * const result = await client.renewStorage({
352
+ * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',
353
+ * duration: 30,
354
+ * payer: publicKey,
355
+ * signTransaction,
356
+ * });
357
+ *
358
+ * @returns {Promise<UploadResult>} Result of the renewal transaction
359
+ */
360
+ renewStorageDuration({ cid, duration, payer, signTransaction, }: StorageRenewalParams): Promise<UploadResult>;
208
361
  }
209
362
 
363
+ declare const useUpload: (environment: ClientOptions["environment"]) => Client;
364
+
210
365
  /**
211
366
  * Calls the deposit API for on-chain storage and returns a Transaction
212
367
  * which must be signed and sent externally by the user.
@@ -220,25 +375,57 @@ declare class Client {
220
375
  * }
221
376
  * @returns Transaction
222
377
  */
223
- declare function createDepositTxn({ file, duration, payer, connection, signTransaction, }: CreateDepositArgs): Promise<UploadResult>;
224
-
225
- declare const useDeposit: (environment: ClientOptions["environment"]) => Client;
378
+ declare function createDepositTxn({ file, duration, payer, connection, signTransaction, userEmail, }: CreateDepositArgs): Promise<UploadResult>;
379
+ /**
380
+ * Get cost estimate for renewing storage duration
381
+ *
382
+ * @param {string} cid - Content identifier of the uploaded data to renew
383
+ * @param {number} duration - Number of additional days to extend storage
384
+ *
385
+ * @example
386
+ * const quote = await client.getRenewalQuote('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi', 30);
387
+ * console.log(`Renewal cost: ${quote.costInSOL} SOL`);
388
+ *
389
+ * @returns {Promise<StorageRenewalCost | null>} Cost breakdown and expiration details
390
+ */
391
+ declare function getStorageRenewalCost(cid: string, duration: number): Promise<StorageRenewalCost | null>;
392
+ /**
393
+ * Renew storage for an existing deposit
394
+ *
395
+ * @param {Object} params
396
+ * @param {string} params.cid - Content identifier of the uploaded data to renew
397
+ * @param {number} params.duration - Number of additional days to extend storage
398
+ * @param {PublicKey} params.payer - Wallet public key paying for the renewal
399
+ * @param {(tx: Transaction) => Promise<Transaction>} params.signTransaction - Transaction signing callback
400
+ *
401
+ * @example
402
+ * const { publicKey, signTransaction } = useSolanaWallet();
403
+ * const result = await client.renewStorage({
404
+ * cid: 'bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi',
405
+ * additionalDays: 30,
406
+ * payer: publicKey,
407
+ * signTransaction,
408
+ * });
409
+ *
410
+ * @returns {Promise<UploadResult>} Result of the renewal transaction
411
+ */
412
+ declare function renewStorageTxn({ cid, duration, payer, connection, signTransaction, }: RenewStorageDurationArgs): Promise<UploadResult>;
226
413
 
227
414
  /**
228
- * Fetches the deposit history for a given user address from the backend
415
+ * Get the upload history for a given user address from the backend
229
416
  *
230
- * @param userAddress - The wallet address of the user to fetch deposit history for
417
+ * @param userAddress - The wallet address of the user to fetch upload history for
231
418
  * @param options - Optional server configuration
232
- * @returns Promise<DepositHistoryResponse> - The user's deposit history
419
+ * @returns Promise<UploadHistoryResponse> - The user's upload history
233
420
  *
234
421
  * @example
235
422
  * ```typescript
236
- * const history = await fetchUserDepositHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');
237
- * console.log('User deposit history:', history.userHistory);
423
+ * const history = await getUserUploadHistory('9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM');
424
+ * console.log('User upload history:', history.userHistory);
238
425
  * ```
239
426
  *
240
427
  * @throws {Error} When the user address is invalid or the request fails
241
428
  */
242
- declare function fetchUserDepositHistory(userAddress: string, options?: ServerOptions): Promise<DepositHistoryResponse>;
429
+ declare function getUserUploadHistory(userAddress: string, options?: ServerOptions): Promise<UploadHistoryResponse>;
243
430
 
244
- export { Client, type ClientOptions, type CreateDepositArgs, type DepositHistoryEntry, type DepositHistoryResponse, type DepositParams, type DepositResult, Environment, type OnChainConfig, type OnChainDeposit, type ServerOptions, type UploadOptions, type UploadResult, type WalletItem, createDepositTxn, fetchUserDepositHistory, getRpcUrl, useDeposit };
431
+ export { Client, type ClientOptions, type CreateDepositArgs, type DepositHistoryEntry, type DepositHistoryResponse, type DepositParams, type DepositResult, Environment, type OnChainConfig, type OnChainDeposit, type RenewStorageDurationArgs, type ServerOptions, type StorageRenewalCost, type StorageRenewalParams, type StorageRenewalResult, type Transaction, type UploadHistory, type UploadHistoryResponse, type UploadOptions, type UploadParams, type UploadResult, type WalletItem, createDepositTxn, getUserUploadHistory as fetchUserDepositHistory, getUserUploadHistory as fetchUserUploadHistory, getRpcUrl, getStorageRenewalCost, getUserUploadHistory, renewStorageTxn, useUpload as useDeposit, useUpload };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{Connection as T}from"@solana/web3.js";import{PublicKey as U,Transaction as R,TransactionInstruction as S}from"@solana/web3.js";var{NODE_ENV:x}=process.env,m=x==="development"?"http://localhost:5040":"https://storacha-solana-sdk-bshc.onrender.com";async function P({file:r,duration:o,payer:n,connection:e,signTransaction:i}){try{let t=new FormData;r.forEach(s=>t.append("file",s)),t.append("duration",o.toString()),t.append("publicKey",n.toBase58());let b=r.length>1,u,l=await fetch(`${m}/api/solana/deposit`,{method:"POST",body:t});if(!l.ok)throw new Error("Failed to get deposit instructions");let a=await l.json();if(!a.instructions||!a.instructions.length)throw new Error("No instructions from deposit API");let h=await e.getLatestBlockhash("confirmed"),w=a.instructions[0],v=new S({programId:new U(w.programId),keys:w.keys.map(s=>({pubkey:new U(s.pubkey),isSigner:s.isSigner,isWritable:s.isWritable})),data:Buffer.from(w.data,"base64")}),d=new R;d.recentBlockhash=h.blockhash,d.feePayer=n,d.add(v);let I=await i(d),D=await e.sendRawTransaction(I.serialize(),{skipPreflight:!1,preflightCommitment:"confirmed"}),g=await e.confirmTransaction({signature:D,blockhash:h.blockhash,lastValidBlockHeight:h.lastValidBlockHeight},"confirmed");if(g.value.err)throw console.error("Failed to confirm this transaction:",g.value.err),new Error(`Transaction failed: ${JSON.stringify(g.value.err)}`);a.error&&(u=a.error);let y=new FormData;r.forEach(s=>y.append("file",s));let p;if(b?p=await fetch(`${m}/api/user/upload-files?cid=${encodeURIComponent(a.cid)}`,{method:"POST",body:y}):p=await fetch(`${m}/api/user/upload-file?cid=${encodeURIComponent(a.cid)}`,{method:"POST",body:y}),!p.ok){let s="Unknown error";try{let E=await p.json();s=E.message||E.error||s}catch{}throw new Error("Deposit API error: "+s)}let c=await p?.json();return{signature:D,success:!0,cid:a.cid,url:c.object.url,message:c.object.message,fileInfo:c.object?{filename:c.object.fileInfo?.filename||"",size:c?.object?.fileInfo?.size||0,uploadedAt:c?.object?.fileInfo?.uploadedAt||"",type:c?.object?.fileInfo?.type||""}:void 0}}catch(t){return console.error(t),t instanceof Error&&(console.error("Error name:",t.name),console.error("Error message:",t.message),console.error("Error stack:",t.stack)),{signature:"",success:!1,cid:"",url:"",message:"",fileInfo:void 0,error:t instanceof Error?t.message:"Unknown error occurred"}}}async function k(r,o={}){if(!r||typeof r!="string")throw new Error("User address is required and must be a string");let n=o.url||"http://localhost:3000";try{let e=await fetch(`${n}/user-upload-history?userAddress=${encodeURIComponent(r)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){let t=await e.json().catch(()=>({}));throw new Error(t.message||`Failed to fetch deposit history: ${e.status} ${e.statusText}`)}let i=await e.json();if(typeof i!="object"||i===null)throw new Error("Invalid response format from server");if(typeof i.userAddress!="string")throw new Error("Invalid userAddress in response");return i}catch(e){throw e instanceof Error?e:new Error("Unknown error occurred while fetching deposit history")}}var C=(e=>(e.mainnet="mainnet-beta",e.testnet="testnet",e.devnet="devnet",e))(C||{});function j(r){switch(r){case"mainnet-beta":return"https://api.mainnet-beta.solana.com";case"testnet":return"https://api.testnet.solana.com";case"devnet":return"https://api.devnet.solana.com";default:throw new Error(`Unsupported environment: ${r}`)}}var f=class{constructor(o){this.estimateStorageCost=(o,n)=>{let t=o.reduce((u,l)=>u+l.size,0)*n*1e3;return{sol:t/1e9,lamports:t}};this.rpcUrl=j(o.environment)}async createDeposit({payer:o,file:n,durationDays:e,signTransaction:i}){console.log("Creating deposit transaction with environment:",this.rpcUrl);let t=new T(this.rpcUrl,"confirmed");return await P({file:n,duration:e*86400,payer:o,connection:t,signTransaction:i})}async getUserUploadHistory(o){return await k(o)}};var V=r=>new f({environment:r||"testnet"});export{f as Client,C as Environment,P as createDepositTxn,k as fetchUserDepositHistory,j as getRpcUrl,V as useDeposit};
1
+ import{Connection as v}from"@solana/web3.js";var{NODE_ENV:A}=process.env,l=A==="development"?"http://localhost:5040":"https://storacha-solana-sdk-bshc.onrender.com",P=86400,D=1e9,I=(o,r,t)=>o*t*r;import{PublicKey as S,Transaction as k,TransactionInstruction as B,SendTransactionError as L}from"@solana/web3.js";async function x({file:o,duration:r,payer:t,connection:e,signTransaction:i,userEmail:s}){try{let n=new FormData;o.forEach(a=>n.append("file",a)),n.append("duration",r.toString()),n.append("publicKey",t.toBase58()),s&&n.append("userEmail",s);let d=o.length>1,m,h=await fetch(`${l}/api/solana/deposit`,{method:"POST",body:n});if(!h.ok)throw new Error("Failed to get deposit instructions");let c=await h.json();if(!c.instructions||!c.instructions.length)throw new Error("No instructions from deposit API");let g=await e.getLatestBlockhash("confirmed"),p=c.instructions[0],f=new B({programId:new S(p.programId),keys:p.keys.map(a=>({pubkey:new S(a.pubkey),isSigner:a.isSigner,isWritable:a.isWritable})),data:Buffer.from(p.data,"base64")}),y=new k;y.recentBlockhash=g.blockhash,y.feePayer=t,y.add(f);let N=await i(y),b;try{b=await e.sendRawTransaction(N.serialize(),{skipPreflight:!1,preflightCommitment:"confirmed"})}catch(a){throw a instanceof L?(a.logs??[]).some($=>$.includes("already in use"))?new Error("This file has already been uploaded. You can find it in your dashboard."):new Error("Transaction failed during simulation. Please try again."):a}let U=await e.confirmTransaction({signature:b,blockhash:g.blockhash,lastValidBlockHeight:g.lastValidBlockHeight},"confirmed");if(U.value.err)throw console.error("Failed to confirm this transaction:",U.value.err),new Error(`Transaction failed: ${JSON.stringify(U.value.err)}`);try{await fetch(`${l}/api/user/update-transaction-hash`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:c.cid,transactionHash:b})})}catch(a){console.warn("Failed to update transaction hash:",a)}c.error&&(m=c.error);let E=new FormData;o.forEach(a=>E.append("file",a));let w;if(d?w=await fetch(`${l}/api/user/upload-files?cid=${encodeURIComponent(c.cid)}`,{method:"POST",body:E}):w=await fetch(`${l}/api/user/upload-file?cid=${encodeURIComponent(c.cid)}`,{method:"POST",body:E}),!w.ok){let a="Unknown error";try{let T=await w.json();a=T.message||T.error||a}catch{}throw new Error("Deposit API error: "+a)}let u=await w?.json();return{signature:b,success:!0,cid:c.cid,url:u.object.url,message:u.object.message,fileInfo:u.object?{filename:u.object.fileInfo?.filename||"",size:u?.object?.fileInfo?.size||0,uploadedAt:u?.object?.fileInfo?.uploadedAt||"",type:u?.object?.fileInfo?.type||""}:void 0}}catch(n){return console.error(n),n instanceof Error&&(console.error("Error name:",n.name),console.error("Error message:",n.message),console.error("Error stack:",n.stack)),{signature:"",success:!1,cid:"",url:"",message:"",fileInfo:void 0,error:n instanceof Error?n.message:"Unknown error occurred"}}}async function C(o,r){try{let t=await fetch(`${l}/api/user/renewal-cost?cid=${encodeURIComponent(o)}&duration=${r}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok){let e=await t.json();throw new Error(e.message||"Failed to get storage renewal cost")}return await t.json()}catch(t){return console.error("Failed to get storage renewal cost",t),null}}async function O({cid:o,duration:r,payer:t,connection:e,signTransaction:i}){let s=await fetch(`${l}/api/user/renew-storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:o,duration:r,publicKey:t.toString()})});if(!s.ok){let p=await s.json().catch(()=>({}));throw new Error(p.message||"Failed to create renewal transaction")}let n=await s.json(),d=new k;n.instructions.forEach(p=>{d.add({programId:new S(p.programId),keys:p.keys.map(f=>({pubkey:new S(f.pubkey),isSigner:f.isSigner,isWritable:f.isWritable})),data:Buffer.from(p.data,"base64")})});let{blockhash:m}=await e.getLatestBlockhash();d.recentBlockhash=m,d.feePayer=t;let h=await i(d),c=await e.sendRawTransaction(h.serialize());return await e.confirmTransaction(c,"confirmed"),(await fetch(`${l}/api/user/confirm-renewal`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cid:o,duration:r,transactionHash:c})})).ok||console.error("Failed to confirm renewal on backend"),{success:!0,cid:o,signature:c,url:`https://w3s.link/ipfs/${o}`,message:"Storage renewed successfully"}}async function j(o,r={}){if(!o||typeof o!="string")throw new Error("User address is required and must be a string");let t=r.url||l;try{let e=await fetch(`${t}/api/user/user-upload-history?userAddress=${encodeURIComponent(o)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok){let s=await e.json().catch(()=>({}));throw new Error(s.message||`Failed to fetch upload history: ${e.status} ${e.statusText}`)}let i=await e.json();if(typeof i!="object"||i===null)throw new Error("Invalid response format from server");if(typeof i.userAddress!="string")throw new Error("Invalid userAddress in response");return i}catch(e){throw e instanceof Error?e:new Error("Unknown error occurred while fetching upload history")}}var F=(e=>(e.mainnet="mainnet-beta",e.testnet="testnet",e.devnet="devnet",e))(F||{});function _(o){switch(o){case"mainnet-beta":return"https://api.mainnet-beta.solana.com";case"testnet":return"https://api.testnet.solana.com";case"devnet":return"https://api.devnet.solana.com";default:throw new Error(`Unsupported environment: ${o}`)}}var R=class{constructor(r){this.estimateStorageCost=(r,t)=>{let i=r.reduce((d,m)=>d+m.size,0),s=I(i,1e3,t);return{sol:s/D,lamports:s}};this.rpcUrl=_(r.environment)}async createDeposit({payer:r,file:t,durationDays:e,signTransaction:i,userEmail:s}){console.log("Creating deposit transaction with environment:",this.rpcUrl);let n=new v(this.rpcUrl,"confirmed");return await x({file:t,duration:e*P,payer:r,connection:n,signTransaction:i,userEmail:s})}async getUserUploadHistory(r){return await j(r)}async getStorageRenewalCost(r,t){return await C(r,t)}async renewStorageDuration({cid:r,duration:t,payer:e,signTransaction:i}){let s=new v(this.rpcUrl,"confirmed");return await O({cid:r,duration:t,payer:e,connection:s,signTransaction:i})}};var oe=o=>new R({environment:o||"testnet"});export{R as Client,F as Environment,x as createDepositTxn,j as fetchUserDepositHistory,j as fetchUserUploadHistory,_ as getRpcUrl,C as getStorageRenewalCost,j as getUserUploadHistory,O as renewStorageTxn,oe as useDeposit,oe as useUpload};
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "storacha-sol",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "main": "./dist/index.js",
5
5
  "scripts": {
6
6
  "build": "tsup src/index.ts --minify",
7
- "dev": "pnpm build --watch"
7
+ "dev": "pnpm build --watch",
8
+ "pack:local": "pnpm build && pnpm pack",
9
+ "knip": "knip"
8
10
  },
9
11
  "exports": {
10
12
  "import": {
@@ -20,7 +22,7 @@
20
22
  ],
21
23
  "repository": {
22
24
  "type": "git",
23
- "url": "git+https://github.com/seetadev/storacha-solana-sdk"
25
+ "url": "git+https://github.com/seetadev/storacha-solana-sdk.git"
24
26
  },
25
27
  "types": "./dist/index.d.ts",
26
28
  "type": "module",
@@ -42,7 +44,7 @@
42
44
  "standard-version": "^9.5.0"
43
45
  },
44
46
  "devDependencies": {
45
- "esbuild": "^0.21.4",
47
+ "knip": "^5.72.0",
46
48
  "tsup": "^8.5.0",
47
49
  "typescript": "^5.8.3"
48
50
  }