@3mate/walrus-sponsor-sdk 0.1.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/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/index.d.mts +199 -0
- package/dist/index.d.ts +199 -0
- package/dist/index.js +264 -0
- package/dist/index.mjs +238 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 3mate Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @3mate/walrus-sponsor-sdk
|
|
2
|
+
|
|
3
|
+
Official SDK for [3mate Walrus Sponsor](https://github.com/3MateLabs/walrus-sponsor-sdk) — sponsored blob storage on the [Walrus](https://walrus.space) network.
|
|
4
|
+
|
|
5
|
+
Zero runtime dependencies. Works in Node.js 18+ and modern browsers.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @3mate/walrus-sponsor-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { WalrusSponsor } from "@3mate/walrus-sponsor-sdk";
|
|
17
|
+
|
|
18
|
+
const walrus = new WalrusSponsor({
|
|
19
|
+
apiKey: "sbk_live_...",
|
|
20
|
+
baseUrl: "https://your-backend.com",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Upload a file (browser)
|
|
24
|
+
const file = document.querySelector<HTMLInputElement>("#file")!.files![0];
|
|
25
|
+
const result = await walrus.upload(file, {
|
|
26
|
+
creatorAddress: "0x123...",
|
|
27
|
+
epochs: 3,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log("View:", walrus.getBlobUrl(result.blobId));
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### Constructor
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
new WalrusSponsor({
|
|
39
|
+
apiKey: string; // Required — your API key (sbk_live_...)
|
|
40
|
+
baseUrl: string; // Required — your backend URL
|
|
41
|
+
aggregatorUrl?: string; // Optional — defaults to mainnet aggregator
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Methods
|
|
46
|
+
|
|
47
|
+
| Method | Description |
|
|
48
|
+
|--------|-------------|
|
|
49
|
+
| `health()` | Check if backend is live |
|
|
50
|
+
| `epoch()` | Get current Walrus epoch info |
|
|
51
|
+
| `estimateCost(size, epochs?)` | Estimate WAL storage cost |
|
|
52
|
+
| `upload(file, opts)` | Upload a file via sponsored publisher |
|
|
53
|
+
| `listBlobs(opts?)` | List blobs with optional filters |
|
|
54
|
+
| `getBlob(id)` | Get single blob details |
|
|
55
|
+
| `getBlobUrl(blobId)` | Build aggregator URL (no network call) |
|
|
56
|
+
|
|
57
|
+
### Upload
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// Browser — File or Blob
|
|
61
|
+
await walrus.upload(file, { creatorAddress: "0x..." });
|
|
62
|
+
|
|
63
|
+
// Node.js — Buffer
|
|
64
|
+
await walrus.upload(
|
|
65
|
+
{ data: buffer, filename: "photo.png", contentType: "image/png" },
|
|
66
|
+
{ creatorAddress: "0x...", epochs: 3 }
|
|
67
|
+
);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
|
|
72
|
+
| Option | Type | Default | Description |
|
|
73
|
+
|--------|------|---------|-------------|
|
|
74
|
+
| `creatorAddress` | `string` | — | Required. Sui address to own the blob |
|
|
75
|
+
| `epochs` | `number` | `1` | Storage duration in epochs |
|
|
76
|
+
| `deletable` | `boolean` | `true` | Whether the blob can be deleted |
|
|
77
|
+
|
|
78
|
+
### List & Get Blobs
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const { blobs, total } = await walrus.listBlobs({
|
|
82
|
+
status: "active",
|
|
83
|
+
creatorAddress: "0x...",
|
|
84
|
+
limit: 10,
|
|
85
|
+
offset: 0,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const blob = await walrus.getBlob("0x1234...");
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Estimate Cost
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const cost = await walrus.estimateCost(1024 * 1024, 3); // 1 MB, 3 epochs
|
|
95
|
+
console.log(cost.totalCost); // WAL amount as string
|
|
96
|
+
console.log(cost.storageCost); // storage component
|
|
97
|
+
console.log(cost.writeCost); // write component
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Error Handling
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { WalrusSponsorError } from "@3mate/walrus-sponsor-sdk";
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await walrus.upload(file, opts);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if (err instanceof WalrusSponsorError) {
|
|
109
|
+
console.error(err.message); // Human-readable message
|
|
110
|
+
console.error(err.statusCode); // 401, 402, 502, etc.
|
|
111
|
+
console.error(err.details); // Raw API error body
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Status | Meaning |
|
|
117
|
+
|--------|---------|
|
|
118
|
+
| 401 | Invalid or missing API key |
|
|
119
|
+
| 402 | Insufficient workspace balance |
|
|
120
|
+
| 502 | Storage service unavailable |
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
interface WalrusSponsorConfig {
|
|
2
|
+
/** API key (starts with sbk_live_) */
|
|
3
|
+
apiKey: string;
|
|
4
|
+
/** Base URL of your walrus-sponsor backend */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Walrus aggregator URL for blob retrieval (default: mainnet aggregator) */
|
|
7
|
+
aggregatorUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
interface UploadOptions {
|
|
10
|
+
/** Sui address that will own the SponsoredBlob (0x-prefixed, 64 hex chars) */
|
|
11
|
+
creatorAddress: string;
|
|
12
|
+
/** Storage duration in epochs (default: 1) */
|
|
13
|
+
epochs?: number;
|
|
14
|
+
/** Whether the blob can be deleted (default: true) */
|
|
15
|
+
deletable?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface ListBlobsOptions {
|
|
18
|
+
/** Filter by status */
|
|
19
|
+
status?: "active" | "deleted" | "expired" | "transferred";
|
|
20
|
+
/** Filter by creator address */
|
|
21
|
+
creatorAddress?: string;
|
|
22
|
+
/** Max results (default: 50) */
|
|
23
|
+
limit?: number;
|
|
24
|
+
/** Pagination offset (default: 0) */
|
|
25
|
+
offset?: number;
|
|
26
|
+
}
|
|
27
|
+
interface HealthResponse {
|
|
28
|
+
status: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
}
|
|
31
|
+
interface EpochResponse {
|
|
32
|
+
currentEpoch: number;
|
|
33
|
+
startTime: string;
|
|
34
|
+
endTime: string;
|
|
35
|
+
epochDurationDays: number;
|
|
36
|
+
}
|
|
37
|
+
interface StorageCostEstimate {
|
|
38
|
+
size: number;
|
|
39
|
+
epochs: number;
|
|
40
|
+
storageCost: string;
|
|
41
|
+
writeCost: string;
|
|
42
|
+
totalCost: string;
|
|
43
|
+
totalCostNumber: number;
|
|
44
|
+
}
|
|
45
|
+
interface SponsoredBlob {
|
|
46
|
+
sponsoredBlobId: string;
|
|
47
|
+
blobId: string;
|
|
48
|
+
creatorAddress: string;
|
|
49
|
+
sponsorAddress: string;
|
|
50
|
+
txDigest: string;
|
|
51
|
+
sizeBytes: number;
|
|
52
|
+
walCost: number;
|
|
53
|
+
gasFee: number;
|
|
54
|
+
totalCharged: number;
|
|
55
|
+
endEpoch: number;
|
|
56
|
+
status: string;
|
|
57
|
+
}
|
|
58
|
+
interface AlreadyCertifiedBlob {
|
|
59
|
+
blobId: string;
|
|
60
|
+
endEpoch: number;
|
|
61
|
+
alreadyCertified: true;
|
|
62
|
+
txDigest: string;
|
|
63
|
+
}
|
|
64
|
+
type UploadResult = SponsoredBlob | AlreadyCertifiedBlob;
|
|
65
|
+
interface BlobSummary {
|
|
66
|
+
id: string;
|
|
67
|
+
objectId: string;
|
|
68
|
+
blobId: string;
|
|
69
|
+
creatorAddress: string;
|
|
70
|
+
sponsorAddress: string;
|
|
71
|
+
sizeBytes: number;
|
|
72
|
+
contentType: string | null;
|
|
73
|
+
filename: string | null;
|
|
74
|
+
endEpoch: number;
|
|
75
|
+
status: string;
|
|
76
|
+
createdAt: string;
|
|
77
|
+
}
|
|
78
|
+
interface BlobDetail extends BlobSummary {
|
|
79
|
+
txDigest: string;
|
|
80
|
+
sponsorCanDelete: boolean;
|
|
81
|
+
autoRenew: boolean;
|
|
82
|
+
autoRenewEpochs: number | null;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
}
|
|
85
|
+
interface ListBlobsResponse {
|
|
86
|
+
blobs: BlobSummary[];
|
|
87
|
+
total: number;
|
|
88
|
+
}
|
|
89
|
+
/** Browser File/Blob or Node.js Buffer with metadata */
|
|
90
|
+
type FileInput = File | Blob | Buffer | {
|
|
91
|
+
data: Buffer;
|
|
92
|
+
filename: string;
|
|
93
|
+
contentType?: string;
|
|
94
|
+
};
|
|
95
|
+
declare class WalrusSponsorError extends Error {
|
|
96
|
+
statusCode: number;
|
|
97
|
+
details?: any;
|
|
98
|
+
constructor(message: string, statusCode: number, details?: any);
|
|
99
|
+
}
|
|
100
|
+
declare class WalrusSponsor {
|
|
101
|
+
private apiKey;
|
|
102
|
+
private baseUrl;
|
|
103
|
+
private aggregatorUrl;
|
|
104
|
+
constructor(config: WalrusSponsorConfig);
|
|
105
|
+
private request;
|
|
106
|
+
/**
|
|
107
|
+
* Check backend health (no auth required).
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const h = await walrus.health();
|
|
112
|
+
* console.log(h.status); // "ok"
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
health(): Promise<HealthResponse>;
|
|
116
|
+
/**
|
|
117
|
+
* Get current Walrus epoch info (no auth required).
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* const e = await walrus.epoch();
|
|
122
|
+
* console.log(e.currentEpoch);
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
epoch(): Promise<EpochResponse>;
|
|
126
|
+
/**
|
|
127
|
+
* Estimate WAL storage cost for a given file size and epoch count.
|
|
128
|
+
*
|
|
129
|
+
* @param size - File size in bytes
|
|
130
|
+
* @param epochs - Storage duration in epochs (default: 1)
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const cost = await walrus.estimateCost(1024 * 1024, 3);
|
|
135
|
+
* console.log(cost.totalCost);
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
estimateCost(size: number, epochs?: number): Promise<StorageCostEstimate>;
|
|
139
|
+
/**
|
|
140
|
+
* Upload a file to Walrus via the sponsored publisher.
|
|
141
|
+
*
|
|
142
|
+
* @param file - File, Blob, Buffer, or { data, filename, contentType }
|
|
143
|
+
* @param opts - Upload options (creatorAddress required)
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // Browser
|
|
148
|
+
* const input = document.querySelector<HTMLInputElement>("#file");
|
|
149
|
+
* const result = await walrus.upload(input.files[0], {
|
|
150
|
+
* creatorAddress: "0x123...",
|
|
151
|
+
* epochs: 3,
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* // Node.js
|
|
155
|
+
* const buf = fs.readFileSync("photo.png");
|
|
156
|
+
* const result = await walrus.upload(
|
|
157
|
+
* { data: buf, filename: "photo.png", contentType: "image/png" },
|
|
158
|
+
* { creatorAddress: "0x123...", epochs: 3 }
|
|
159
|
+
* );
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
upload(file: FileInput, opts: UploadOptions): Promise<UploadResult>;
|
|
163
|
+
/**
|
|
164
|
+
* List sponsored blobs for the current API key.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const { blobs, total } = await walrus.listBlobs({ status: "active", limit: 10 });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
listBlobs(opts?: ListBlobsOptions): Promise<ListBlobsResponse>;
|
|
172
|
+
/**
|
|
173
|
+
* Get details of a single sponsored blob.
|
|
174
|
+
*
|
|
175
|
+
* @param id - Blob object_id or database id
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const blob = await walrus.getBlob("0x1234...");
|
|
180
|
+
* console.log(blob.status, blob.endEpoch);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
getBlob(id: string): Promise<BlobDetail>;
|
|
184
|
+
/**
|
|
185
|
+
* Build the aggregator URL for retrieving a blob's content.
|
|
186
|
+
* This is a client-side helper — no network call.
|
|
187
|
+
*
|
|
188
|
+
* @param blobId - The Walrus blob ID (base64url encoded)
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* const url = walrus.getBlobUrl("Aqz5l...");
|
|
193
|
+
* // => "https://aggregator.walrus-mainnet.walrus.space/v1/Aqz5l..."
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
getBlobUrl(blobId: string): string;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { type AlreadyCertifiedBlob, type BlobDetail, type BlobSummary, type EpochResponse, type FileInput, type HealthResponse, type ListBlobsOptions, type ListBlobsResponse, type SponsoredBlob, type StorageCostEstimate, type UploadOptions, type UploadResult, WalrusSponsor, type WalrusSponsorConfig, WalrusSponsorError, WalrusSponsor as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
interface WalrusSponsorConfig {
|
|
2
|
+
/** API key (starts with sbk_live_) */
|
|
3
|
+
apiKey: string;
|
|
4
|
+
/** Base URL of your walrus-sponsor backend */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Walrus aggregator URL for blob retrieval (default: mainnet aggregator) */
|
|
7
|
+
aggregatorUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
interface UploadOptions {
|
|
10
|
+
/** Sui address that will own the SponsoredBlob (0x-prefixed, 64 hex chars) */
|
|
11
|
+
creatorAddress: string;
|
|
12
|
+
/** Storage duration in epochs (default: 1) */
|
|
13
|
+
epochs?: number;
|
|
14
|
+
/** Whether the blob can be deleted (default: true) */
|
|
15
|
+
deletable?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface ListBlobsOptions {
|
|
18
|
+
/** Filter by status */
|
|
19
|
+
status?: "active" | "deleted" | "expired" | "transferred";
|
|
20
|
+
/** Filter by creator address */
|
|
21
|
+
creatorAddress?: string;
|
|
22
|
+
/** Max results (default: 50) */
|
|
23
|
+
limit?: number;
|
|
24
|
+
/** Pagination offset (default: 0) */
|
|
25
|
+
offset?: number;
|
|
26
|
+
}
|
|
27
|
+
interface HealthResponse {
|
|
28
|
+
status: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
}
|
|
31
|
+
interface EpochResponse {
|
|
32
|
+
currentEpoch: number;
|
|
33
|
+
startTime: string;
|
|
34
|
+
endTime: string;
|
|
35
|
+
epochDurationDays: number;
|
|
36
|
+
}
|
|
37
|
+
interface StorageCostEstimate {
|
|
38
|
+
size: number;
|
|
39
|
+
epochs: number;
|
|
40
|
+
storageCost: string;
|
|
41
|
+
writeCost: string;
|
|
42
|
+
totalCost: string;
|
|
43
|
+
totalCostNumber: number;
|
|
44
|
+
}
|
|
45
|
+
interface SponsoredBlob {
|
|
46
|
+
sponsoredBlobId: string;
|
|
47
|
+
blobId: string;
|
|
48
|
+
creatorAddress: string;
|
|
49
|
+
sponsorAddress: string;
|
|
50
|
+
txDigest: string;
|
|
51
|
+
sizeBytes: number;
|
|
52
|
+
walCost: number;
|
|
53
|
+
gasFee: number;
|
|
54
|
+
totalCharged: number;
|
|
55
|
+
endEpoch: number;
|
|
56
|
+
status: string;
|
|
57
|
+
}
|
|
58
|
+
interface AlreadyCertifiedBlob {
|
|
59
|
+
blobId: string;
|
|
60
|
+
endEpoch: number;
|
|
61
|
+
alreadyCertified: true;
|
|
62
|
+
txDigest: string;
|
|
63
|
+
}
|
|
64
|
+
type UploadResult = SponsoredBlob | AlreadyCertifiedBlob;
|
|
65
|
+
interface BlobSummary {
|
|
66
|
+
id: string;
|
|
67
|
+
objectId: string;
|
|
68
|
+
blobId: string;
|
|
69
|
+
creatorAddress: string;
|
|
70
|
+
sponsorAddress: string;
|
|
71
|
+
sizeBytes: number;
|
|
72
|
+
contentType: string | null;
|
|
73
|
+
filename: string | null;
|
|
74
|
+
endEpoch: number;
|
|
75
|
+
status: string;
|
|
76
|
+
createdAt: string;
|
|
77
|
+
}
|
|
78
|
+
interface BlobDetail extends BlobSummary {
|
|
79
|
+
txDigest: string;
|
|
80
|
+
sponsorCanDelete: boolean;
|
|
81
|
+
autoRenew: boolean;
|
|
82
|
+
autoRenewEpochs: number | null;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
}
|
|
85
|
+
interface ListBlobsResponse {
|
|
86
|
+
blobs: BlobSummary[];
|
|
87
|
+
total: number;
|
|
88
|
+
}
|
|
89
|
+
/** Browser File/Blob or Node.js Buffer with metadata */
|
|
90
|
+
type FileInput = File | Blob | Buffer | {
|
|
91
|
+
data: Buffer;
|
|
92
|
+
filename: string;
|
|
93
|
+
contentType?: string;
|
|
94
|
+
};
|
|
95
|
+
declare class WalrusSponsorError extends Error {
|
|
96
|
+
statusCode: number;
|
|
97
|
+
details?: any;
|
|
98
|
+
constructor(message: string, statusCode: number, details?: any);
|
|
99
|
+
}
|
|
100
|
+
declare class WalrusSponsor {
|
|
101
|
+
private apiKey;
|
|
102
|
+
private baseUrl;
|
|
103
|
+
private aggregatorUrl;
|
|
104
|
+
constructor(config: WalrusSponsorConfig);
|
|
105
|
+
private request;
|
|
106
|
+
/**
|
|
107
|
+
* Check backend health (no auth required).
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const h = await walrus.health();
|
|
112
|
+
* console.log(h.status); // "ok"
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
health(): Promise<HealthResponse>;
|
|
116
|
+
/**
|
|
117
|
+
* Get current Walrus epoch info (no auth required).
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* const e = await walrus.epoch();
|
|
122
|
+
* console.log(e.currentEpoch);
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
epoch(): Promise<EpochResponse>;
|
|
126
|
+
/**
|
|
127
|
+
* Estimate WAL storage cost for a given file size and epoch count.
|
|
128
|
+
*
|
|
129
|
+
* @param size - File size in bytes
|
|
130
|
+
* @param epochs - Storage duration in epochs (default: 1)
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const cost = await walrus.estimateCost(1024 * 1024, 3);
|
|
135
|
+
* console.log(cost.totalCost);
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
estimateCost(size: number, epochs?: number): Promise<StorageCostEstimate>;
|
|
139
|
+
/**
|
|
140
|
+
* Upload a file to Walrus via the sponsored publisher.
|
|
141
|
+
*
|
|
142
|
+
* @param file - File, Blob, Buffer, or { data, filename, contentType }
|
|
143
|
+
* @param opts - Upload options (creatorAddress required)
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // Browser
|
|
148
|
+
* const input = document.querySelector<HTMLInputElement>("#file");
|
|
149
|
+
* const result = await walrus.upload(input.files[0], {
|
|
150
|
+
* creatorAddress: "0x123...",
|
|
151
|
+
* epochs: 3,
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* // Node.js
|
|
155
|
+
* const buf = fs.readFileSync("photo.png");
|
|
156
|
+
* const result = await walrus.upload(
|
|
157
|
+
* { data: buf, filename: "photo.png", contentType: "image/png" },
|
|
158
|
+
* { creatorAddress: "0x123...", epochs: 3 }
|
|
159
|
+
* );
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
upload(file: FileInput, opts: UploadOptions): Promise<UploadResult>;
|
|
163
|
+
/**
|
|
164
|
+
* List sponsored blobs for the current API key.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const { blobs, total } = await walrus.listBlobs({ status: "active", limit: 10 });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
listBlobs(opts?: ListBlobsOptions): Promise<ListBlobsResponse>;
|
|
172
|
+
/**
|
|
173
|
+
* Get details of a single sponsored blob.
|
|
174
|
+
*
|
|
175
|
+
* @param id - Blob object_id or database id
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const blob = await walrus.getBlob("0x1234...");
|
|
180
|
+
* console.log(blob.status, blob.endEpoch);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
getBlob(id: string): Promise<BlobDetail>;
|
|
184
|
+
/**
|
|
185
|
+
* Build the aggregator URL for retrieving a blob's content.
|
|
186
|
+
* This is a client-side helper — no network call.
|
|
187
|
+
*
|
|
188
|
+
* @param blobId - The Walrus blob ID (base64url encoded)
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* const url = walrus.getBlobUrl("Aqz5l...");
|
|
193
|
+
* // => "https://aggregator.walrus-mainnet.walrus.space/v1/Aqz5l..."
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
getBlobUrl(blobId: string): string;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { type AlreadyCertifiedBlob, type BlobDetail, type BlobSummary, type EpochResponse, type FileInput, type HealthResponse, type ListBlobsOptions, type ListBlobsResponse, type SponsoredBlob, type StorageCostEstimate, type UploadOptions, type UploadResult, WalrusSponsor, type WalrusSponsorConfig, WalrusSponsorError, WalrusSponsor as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
WalrusSponsor: () => WalrusSponsor,
|
|
24
|
+
WalrusSponsorError: () => WalrusSponsorError,
|
|
25
|
+
default: () => index_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var DEFAULT_AGGREGATOR_URL = "https://aggregator.walrus-mainnet.walrus.space";
|
|
29
|
+
var ERROR_MAP = {
|
|
30
|
+
401: "Invalid or missing API key",
|
|
31
|
+
402: "Insufficient workspace balance",
|
|
32
|
+
404: "Resource not found",
|
|
33
|
+
502: "Storage service unavailable \u2014 publisher may be down"
|
|
34
|
+
};
|
|
35
|
+
var WalrusSponsorError = class extends Error {
|
|
36
|
+
constructor(message, statusCode, details) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "WalrusSponsorError";
|
|
39
|
+
this.statusCode = statusCode;
|
|
40
|
+
this.details = details;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
function toCamelCase(obj) {
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const key of Object.keys(obj)) {
|
|
46
|
+
const camel = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
47
|
+
const val = obj[key];
|
|
48
|
+
out[camel] = val !== null && typeof val === "object" && !Array.isArray(val) ? toCamelCase(val) : val;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function buildFormData(file, opts) {
|
|
53
|
+
const fd = new FormData();
|
|
54
|
+
if (typeof File !== "undefined" && file instanceof File) {
|
|
55
|
+
fd.append("file", file);
|
|
56
|
+
} else if (typeof Blob !== "undefined" && file instanceof Blob) {
|
|
57
|
+
fd.append("file", file, "upload");
|
|
58
|
+
} else if (Buffer.isBuffer(file)) {
|
|
59
|
+
fd.append("file", new Blob([new Uint8Array(file)]), "upload");
|
|
60
|
+
} else if (typeof file === "object" && "data" in file && Buffer.isBuffer(file.data)) {
|
|
61
|
+
const blob = new Blob([new Uint8Array(file.data)], {
|
|
62
|
+
type: file.contentType || "application/octet-stream"
|
|
63
|
+
});
|
|
64
|
+
fd.append("file", blob, file.filename);
|
|
65
|
+
} else {
|
|
66
|
+
throw new WalrusSponsorError(
|
|
67
|
+
"Invalid file input \u2014 provide a File, Blob, Buffer, or { data, filename }",
|
|
68
|
+
400
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
fd.append("creator_address", opts.creatorAddress);
|
|
72
|
+
if (opts.epochs !== void 0) fd.append("epochs", String(opts.epochs));
|
|
73
|
+
if (opts.deletable !== void 0)
|
|
74
|
+
fd.append("deletable", String(opts.deletable));
|
|
75
|
+
return fd;
|
|
76
|
+
}
|
|
77
|
+
var WalrusSponsor = class {
|
|
78
|
+
constructor(config) {
|
|
79
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
80
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
81
|
+
this.apiKey = config.apiKey;
|
|
82
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
83
|
+
this.aggregatorUrl = (config.aggregatorUrl || DEFAULT_AGGREGATOR_URL).replace(/\/+$/, "");
|
|
84
|
+
}
|
|
85
|
+
// ── Internal fetch wrapper ────────────────────────────────────────────
|
|
86
|
+
async request(method, path, opts) {
|
|
87
|
+
const auth = opts?.auth ?? true;
|
|
88
|
+
let url = `${this.baseUrl}${path}`;
|
|
89
|
+
if (opts?.query) {
|
|
90
|
+
const params = new URLSearchParams();
|
|
91
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
92
|
+
if (v !== void 0) params.append(k, String(v));
|
|
93
|
+
}
|
|
94
|
+
const qs = params.toString();
|
|
95
|
+
if (qs) url += `?${qs}`;
|
|
96
|
+
}
|
|
97
|
+
const headers = {};
|
|
98
|
+
if (auth) headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
99
|
+
let body;
|
|
100
|
+
if (opts?.formData) {
|
|
101
|
+
body = opts.formData;
|
|
102
|
+
} else if (opts?.body) {
|
|
103
|
+
headers["Content-Type"] = "application/json";
|
|
104
|
+
body = JSON.stringify(opts.body);
|
|
105
|
+
}
|
|
106
|
+
let res;
|
|
107
|
+
try {
|
|
108
|
+
res = await fetch(url, { method, headers, body });
|
|
109
|
+
} catch (err) {
|
|
110
|
+
throw new WalrusSponsorError(
|
|
111
|
+
`Network error: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
112
|
+
0,
|
|
113
|
+
err
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
let message = ERROR_MAP[res.status] || `Request failed (${res.status})`;
|
|
118
|
+
let details;
|
|
119
|
+
try {
|
|
120
|
+
const data2 = await res.json();
|
|
121
|
+
if (data2.error) message = data2.error;
|
|
122
|
+
details = data2;
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
throw new WalrusSponsorError(message, res.status, details);
|
|
126
|
+
}
|
|
127
|
+
const data = await res.json();
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
// ── Public methods ────────────────────────────────────────────────────
|
|
131
|
+
/**
|
|
132
|
+
* Check backend health (no auth required).
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* const h = await walrus.health();
|
|
137
|
+
* console.log(h.status); // "ok"
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async health() {
|
|
141
|
+
return this.request("GET", "/health", { auth: false });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get current Walrus epoch info (no auth required).
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const e = await walrus.epoch();
|
|
149
|
+
* console.log(e.currentEpoch);
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
async epoch() {
|
|
153
|
+
const raw = await this.request("GET", "/epoch", { auth: false });
|
|
154
|
+
return toCamelCase(raw);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Estimate WAL storage cost for a given file size and epoch count.
|
|
158
|
+
*
|
|
159
|
+
* @param size - File size in bytes
|
|
160
|
+
* @param epochs - Storage duration in epochs (default: 1)
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const cost = await walrus.estimateCost(1024 * 1024, 3);
|
|
165
|
+
* console.log(cost.totalCost);
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
async estimateCost(size, epochs) {
|
|
169
|
+
const raw = await this.request("GET", "/v1/storage-cost", {
|
|
170
|
+
query: { size, epochs }
|
|
171
|
+
});
|
|
172
|
+
return toCamelCase(raw);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Upload a file to Walrus via the sponsored publisher.
|
|
176
|
+
*
|
|
177
|
+
* @param file - File, Blob, Buffer, or { data, filename, contentType }
|
|
178
|
+
* @param opts - Upload options (creatorAddress required)
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* // Browser
|
|
183
|
+
* const input = document.querySelector<HTMLInputElement>("#file");
|
|
184
|
+
* const result = await walrus.upload(input.files[0], {
|
|
185
|
+
* creatorAddress: "0x123...",
|
|
186
|
+
* epochs: 3,
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* // Node.js
|
|
190
|
+
* const buf = fs.readFileSync("photo.png");
|
|
191
|
+
* const result = await walrus.upload(
|
|
192
|
+
* { data: buf, filename: "photo.png", contentType: "image/png" },
|
|
193
|
+
* { creatorAddress: "0x123...", epochs: 3 }
|
|
194
|
+
* );
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
async upload(file, opts) {
|
|
198
|
+
if (!opts.creatorAddress)
|
|
199
|
+
throw new WalrusSponsorError("creatorAddress is required", 400);
|
|
200
|
+
const fd = buildFormData(file, opts);
|
|
201
|
+
const raw = await this.request("POST", "/v1/upload", {
|
|
202
|
+
formData: fd
|
|
203
|
+
});
|
|
204
|
+
return toCamelCase(raw);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* List sponsored blobs for the current API key.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```ts
|
|
211
|
+
* const { blobs, total } = await walrus.listBlobs({ status: "active", limit: 10 });
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
async listBlobs(opts) {
|
|
215
|
+
const raw = await this.request("GET", "/v1/blobs", {
|
|
216
|
+
query: {
|
|
217
|
+
status: opts?.status,
|
|
218
|
+
creator_address: opts?.creatorAddress,
|
|
219
|
+
limit: opts?.limit,
|
|
220
|
+
offset: opts?.offset
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
blobs: (raw.blobs || []).map((b) => toCamelCase(b)),
|
|
225
|
+
total: raw.total
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get details of a single sponsored blob.
|
|
230
|
+
*
|
|
231
|
+
* @param id - Blob object_id or database id
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const blob = await walrus.getBlob("0x1234...");
|
|
236
|
+
* console.log(blob.status, blob.endEpoch);
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
async getBlob(id) {
|
|
240
|
+
const raw = await this.request("GET", `/v1/blobs/${id}`);
|
|
241
|
+
return toCamelCase(raw);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Build the aggregator URL for retrieving a blob's content.
|
|
245
|
+
* This is a client-side helper — no network call.
|
|
246
|
+
*
|
|
247
|
+
* @param blobId - The Walrus blob ID (base64url encoded)
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* const url = walrus.getBlobUrl("Aqz5l...");
|
|
252
|
+
* // => "https://aggregator.walrus-mainnet.walrus.space/v1/Aqz5l..."
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
getBlobUrl(blobId) {
|
|
256
|
+
return `${this.aggregatorUrl}/v1/${blobId}`;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
var index_default = WalrusSponsor;
|
|
260
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
261
|
+
0 && (module.exports = {
|
|
262
|
+
WalrusSponsor,
|
|
263
|
+
WalrusSponsorError
|
|
264
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEFAULT_AGGREGATOR_URL = "https://aggregator.walrus-mainnet.walrus.space";
|
|
3
|
+
var ERROR_MAP = {
|
|
4
|
+
401: "Invalid or missing API key",
|
|
5
|
+
402: "Insufficient workspace balance",
|
|
6
|
+
404: "Resource not found",
|
|
7
|
+
502: "Storage service unavailable \u2014 publisher may be down"
|
|
8
|
+
};
|
|
9
|
+
var WalrusSponsorError = class extends Error {
|
|
10
|
+
constructor(message, statusCode, details) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "WalrusSponsorError";
|
|
13
|
+
this.statusCode = statusCode;
|
|
14
|
+
this.details = details;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function toCamelCase(obj) {
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const key of Object.keys(obj)) {
|
|
20
|
+
const camel = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
21
|
+
const val = obj[key];
|
|
22
|
+
out[camel] = val !== null && typeof val === "object" && !Array.isArray(val) ? toCamelCase(val) : val;
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
function buildFormData(file, opts) {
|
|
27
|
+
const fd = new FormData();
|
|
28
|
+
if (typeof File !== "undefined" && file instanceof File) {
|
|
29
|
+
fd.append("file", file);
|
|
30
|
+
} else if (typeof Blob !== "undefined" && file instanceof Blob) {
|
|
31
|
+
fd.append("file", file, "upload");
|
|
32
|
+
} else if (Buffer.isBuffer(file)) {
|
|
33
|
+
fd.append("file", new Blob([new Uint8Array(file)]), "upload");
|
|
34
|
+
} else if (typeof file === "object" && "data" in file && Buffer.isBuffer(file.data)) {
|
|
35
|
+
const blob = new Blob([new Uint8Array(file.data)], {
|
|
36
|
+
type: file.contentType || "application/octet-stream"
|
|
37
|
+
});
|
|
38
|
+
fd.append("file", blob, file.filename);
|
|
39
|
+
} else {
|
|
40
|
+
throw new WalrusSponsorError(
|
|
41
|
+
"Invalid file input \u2014 provide a File, Blob, Buffer, or { data, filename }",
|
|
42
|
+
400
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
fd.append("creator_address", opts.creatorAddress);
|
|
46
|
+
if (opts.epochs !== void 0) fd.append("epochs", String(opts.epochs));
|
|
47
|
+
if (opts.deletable !== void 0)
|
|
48
|
+
fd.append("deletable", String(opts.deletable));
|
|
49
|
+
return fd;
|
|
50
|
+
}
|
|
51
|
+
var WalrusSponsor = class {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
if (!config.apiKey) throw new Error("apiKey is required");
|
|
54
|
+
if (!config.baseUrl) throw new Error("baseUrl is required");
|
|
55
|
+
this.apiKey = config.apiKey;
|
|
56
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
57
|
+
this.aggregatorUrl = (config.aggregatorUrl || DEFAULT_AGGREGATOR_URL).replace(/\/+$/, "");
|
|
58
|
+
}
|
|
59
|
+
// ── Internal fetch wrapper ────────────────────────────────────────────
|
|
60
|
+
async request(method, path, opts) {
|
|
61
|
+
const auth = opts?.auth ?? true;
|
|
62
|
+
let url = `${this.baseUrl}${path}`;
|
|
63
|
+
if (opts?.query) {
|
|
64
|
+
const params = new URLSearchParams();
|
|
65
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
66
|
+
if (v !== void 0) params.append(k, String(v));
|
|
67
|
+
}
|
|
68
|
+
const qs = params.toString();
|
|
69
|
+
if (qs) url += `?${qs}`;
|
|
70
|
+
}
|
|
71
|
+
const headers = {};
|
|
72
|
+
if (auth) headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
73
|
+
let body;
|
|
74
|
+
if (opts?.formData) {
|
|
75
|
+
body = opts.formData;
|
|
76
|
+
} else if (opts?.body) {
|
|
77
|
+
headers["Content-Type"] = "application/json";
|
|
78
|
+
body = JSON.stringify(opts.body);
|
|
79
|
+
}
|
|
80
|
+
let res;
|
|
81
|
+
try {
|
|
82
|
+
res = await fetch(url, { method, headers, body });
|
|
83
|
+
} catch (err) {
|
|
84
|
+
throw new WalrusSponsorError(
|
|
85
|
+
`Network error: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
86
|
+
0,
|
|
87
|
+
err
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
let message = ERROR_MAP[res.status] || `Request failed (${res.status})`;
|
|
92
|
+
let details;
|
|
93
|
+
try {
|
|
94
|
+
const data2 = await res.json();
|
|
95
|
+
if (data2.error) message = data2.error;
|
|
96
|
+
details = data2;
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
throw new WalrusSponsorError(message, res.status, details);
|
|
100
|
+
}
|
|
101
|
+
const data = await res.json();
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
// ── Public methods ────────────────────────────────────────────────────
|
|
105
|
+
/**
|
|
106
|
+
* Check backend health (no auth required).
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const h = await walrus.health();
|
|
111
|
+
* console.log(h.status); // "ok"
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
async health() {
|
|
115
|
+
return this.request("GET", "/health", { auth: false });
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get current Walrus epoch info (no auth required).
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const e = await walrus.epoch();
|
|
123
|
+
* console.log(e.currentEpoch);
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
async epoch() {
|
|
127
|
+
const raw = await this.request("GET", "/epoch", { auth: false });
|
|
128
|
+
return toCamelCase(raw);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Estimate WAL storage cost for a given file size and epoch count.
|
|
132
|
+
*
|
|
133
|
+
* @param size - File size in bytes
|
|
134
|
+
* @param epochs - Storage duration in epochs (default: 1)
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* const cost = await walrus.estimateCost(1024 * 1024, 3);
|
|
139
|
+
* console.log(cost.totalCost);
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
async estimateCost(size, epochs) {
|
|
143
|
+
const raw = await this.request("GET", "/v1/storage-cost", {
|
|
144
|
+
query: { size, epochs }
|
|
145
|
+
});
|
|
146
|
+
return toCamelCase(raw);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Upload a file to Walrus via the sponsored publisher.
|
|
150
|
+
*
|
|
151
|
+
* @param file - File, Blob, Buffer, or { data, filename, contentType }
|
|
152
|
+
* @param opts - Upload options (creatorAddress required)
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* // Browser
|
|
157
|
+
* const input = document.querySelector<HTMLInputElement>("#file");
|
|
158
|
+
* const result = await walrus.upload(input.files[0], {
|
|
159
|
+
* creatorAddress: "0x123...",
|
|
160
|
+
* epochs: 3,
|
|
161
|
+
* });
|
|
162
|
+
*
|
|
163
|
+
* // Node.js
|
|
164
|
+
* const buf = fs.readFileSync("photo.png");
|
|
165
|
+
* const result = await walrus.upload(
|
|
166
|
+
* { data: buf, filename: "photo.png", contentType: "image/png" },
|
|
167
|
+
* { creatorAddress: "0x123...", epochs: 3 }
|
|
168
|
+
* );
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
async upload(file, opts) {
|
|
172
|
+
if (!opts.creatorAddress)
|
|
173
|
+
throw new WalrusSponsorError("creatorAddress is required", 400);
|
|
174
|
+
const fd = buildFormData(file, opts);
|
|
175
|
+
const raw = await this.request("POST", "/v1/upload", {
|
|
176
|
+
formData: fd
|
|
177
|
+
});
|
|
178
|
+
return toCamelCase(raw);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* List sponsored blobs for the current API key.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* const { blobs, total } = await walrus.listBlobs({ status: "active", limit: 10 });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
async listBlobs(opts) {
|
|
189
|
+
const raw = await this.request("GET", "/v1/blobs", {
|
|
190
|
+
query: {
|
|
191
|
+
status: opts?.status,
|
|
192
|
+
creator_address: opts?.creatorAddress,
|
|
193
|
+
limit: opts?.limit,
|
|
194
|
+
offset: opts?.offset
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
blobs: (raw.blobs || []).map((b) => toCamelCase(b)),
|
|
199
|
+
total: raw.total
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get details of a single sponsored blob.
|
|
204
|
+
*
|
|
205
|
+
* @param id - Blob object_id or database id
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* const blob = await walrus.getBlob("0x1234...");
|
|
210
|
+
* console.log(blob.status, blob.endEpoch);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
async getBlob(id) {
|
|
214
|
+
const raw = await this.request("GET", `/v1/blobs/${id}`);
|
|
215
|
+
return toCamelCase(raw);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Build the aggregator URL for retrieving a blob's content.
|
|
219
|
+
* This is a client-side helper — no network call.
|
|
220
|
+
*
|
|
221
|
+
* @param blobId - The Walrus blob ID (base64url encoded)
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const url = walrus.getBlobUrl("Aqz5l...");
|
|
226
|
+
* // => "https://aggregator.walrus-mainnet.walrus.space/v1/Aqz5l..."
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
getBlobUrl(blobId) {
|
|
230
|
+
return `${this.aggregatorUrl}/v1/${blobId}`;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var index_default = WalrusSponsor;
|
|
234
|
+
export {
|
|
235
|
+
WalrusSponsor,
|
|
236
|
+
WalrusSponsorError,
|
|
237
|
+
index_default as default
|
|
238
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@3mate/walrus-sponsor-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official SDK for 3mate Walrus Sponsor — Sponsored blob storage on Walrus",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
13
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"walrus",
|
|
18
|
+
"sui",
|
|
19
|
+
"blob",
|
|
20
|
+
"storage",
|
|
21
|
+
"sponsor",
|
|
22
|
+
"web3",
|
|
23
|
+
"3mate"
|
|
24
|
+
],
|
|
25
|
+
"author": "3mate Labs",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/3MateLabs/walrus-sponsor-sdk"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.3.0",
|
|
33
|
+
"tsup": "^8.0.1",
|
|
34
|
+
"typescript": "^5.3.3"
|
|
35
|
+
}
|
|
36
|
+
}
|