@stack0/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +388 -0
- package/dist/cdn/index.d.mts +322 -0
- package/dist/cdn/index.d.ts +322 -0
- package/dist/cdn/index.js +347 -0
- package/dist/cdn/index.js.map +1 -0
- package/dist/cdn/index.mjs +345 -0
- package/dist/cdn/index.mjs.map +1 -0
- package/dist/http-client-Wr9lXo9_.d.mts +10 -0
- package/dist/http-client-Wr9lXo9_.d.ts +10 -0
- package/dist/index.d.mts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +421 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +414 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mail/index.d.mts +101 -0
- package/dist/mail/index.d.ts +101 -0
- package/dist/mail/index.js +125 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/index.mjs +123 -0
- package/dist/mail/index.mjs.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Stack0 SDK
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for Stack0 services.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @stack0/sdk
|
|
9
|
+
# or
|
|
10
|
+
yarn add @stack0/sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @stack0/sdk
|
|
13
|
+
# or
|
|
14
|
+
bun add @stack0/sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Stack0 } from '@stack0/sdk';
|
|
21
|
+
|
|
22
|
+
const stack0 = new Stack0({
|
|
23
|
+
apiKey: 'stack0_...',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Send an email
|
|
27
|
+
const email = await stack0.mail.send({
|
|
28
|
+
from: 'noreply@example.com',
|
|
29
|
+
to: 'user@example.com',
|
|
30
|
+
subject: 'Welcome!',
|
|
31
|
+
html: '<h1>Hello World</h1>',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Upload a file to CDN
|
|
35
|
+
const asset = await stack0.cdn.upload({
|
|
36
|
+
projectSlug: 'my-project',
|
|
37
|
+
file: fileBuffer,
|
|
38
|
+
filename: 'image.jpg',
|
|
39
|
+
mimeType: 'image/jpeg',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log(asset.cdnUrl); // https://cdn.stack0.com/...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Stack0 } from '@stack0/sdk';
|
|
49
|
+
|
|
50
|
+
const stack0 = new Stack0({
|
|
51
|
+
apiKey: 'stack0_...', // Required: Your API key
|
|
52
|
+
baseUrl: 'https://api.stack0.com/v1', // Optional: Custom API endpoint
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CDN API
|
|
57
|
+
|
|
58
|
+
Upload, manage, and transform assets with the CDN API.
|
|
59
|
+
|
|
60
|
+
### Upload File
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Simple upload (handles presigned URL flow automatically)
|
|
64
|
+
const asset = await stack0.cdn.upload({
|
|
65
|
+
projectSlug: 'my-project',
|
|
66
|
+
file: fileBuffer, // Blob, Buffer, or ArrayBuffer
|
|
67
|
+
filename: 'photo.jpg',
|
|
68
|
+
mimeType: 'image/jpeg',
|
|
69
|
+
folder: '/images/avatars', // Optional
|
|
70
|
+
metadata: { userId: 'user_123' }, // Optional
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
console.log(asset.id); // Asset ID
|
|
74
|
+
console.log(asset.cdnUrl); // CDN URL
|
|
75
|
+
console.log(asset.status); // 'ready', 'processing', etc.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Manual Upload Flow
|
|
79
|
+
|
|
80
|
+
For more control, use the presigned URL flow:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// 1. Get presigned upload URL
|
|
84
|
+
const { uploadUrl, assetId } = await stack0.cdn.getUploadUrl({
|
|
85
|
+
projectSlug: 'my-project',
|
|
86
|
+
filename: 'document.pdf',
|
|
87
|
+
mimeType: 'application/pdf',
|
|
88
|
+
size: file.size,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 2. Upload directly to S3
|
|
92
|
+
await fetch(uploadUrl, {
|
|
93
|
+
method: 'PUT',
|
|
94
|
+
body: file,
|
|
95
|
+
headers: { 'Content-Type': 'application/pdf' },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// 3. Confirm upload
|
|
99
|
+
const asset = await stack0.cdn.confirmUpload(assetId);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### List Assets
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const { assets, total, hasMore } = await stack0.cdn.list({
|
|
106
|
+
projectSlug: 'my-project',
|
|
107
|
+
type: 'image', // Optional: 'image', 'video', 'audio', 'document', 'other'
|
|
108
|
+
folder: '/images', // Optional
|
|
109
|
+
status: 'ready', // Optional
|
|
110
|
+
search: 'avatar', // Optional: search in filename
|
|
111
|
+
tags: ['profile'], // Optional
|
|
112
|
+
sortBy: 'createdAt', // Optional: 'createdAt', 'filename', 'size', 'type'
|
|
113
|
+
sortOrder: 'desc', // Optional: 'asc', 'desc'
|
|
114
|
+
limit: 20, // Optional
|
|
115
|
+
offset: 0, // Optional
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
for (const asset of assets) {
|
|
119
|
+
console.log(asset.filename, asset.cdnUrl);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Get Asset
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const asset = await stack0.cdn.get('asset-id');
|
|
127
|
+
|
|
128
|
+
console.log(asset.filename);
|
|
129
|
+
console.log(asset.size);
|
|
130
|
+
console.log(asset.mimeType);
|
|
131
|
+
console.log(asset.width, asset.height); // For images/videos
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Update Asset
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const asset = await stack0.cdn.update({
|
|
138
|
+
id: 'asset-id',
|
|
139
|
+
filename: 'new-name.jpg', // Optional
|
|
140
|
+
folder: '/images/archived', // Optional
|
|
141
|
+
tags: ['nature', 'sunset'], // Optional
|
|
142
|
+
alt: 'A beautiful sunset', // Optional
|
|
143
|
+
metadata: { category: 'landscape' }, // Optional
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Delete Assets
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Delete single asset
|
|
151
|
+
await stack0.cdn.delete('asset-id');
|
|
152
|
+
|
|
153
|
+
// Delete multiple assets
|
|
154
|
+
const { deletedCount } = await stack0.cdn.deleteMany([
|
|
155
|
+
'asset-1',
|
|
156
|
+
'asset-2',
|
|
157
|
+
'asset-3',
|
|
158
|
+
]);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Move Assets
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
await stack0.cdn.move({
|
|
165
|
+
assetIds: ['asset-1', 'asset-2'],
|
|
166
|
+
folder: '/images/archive', // Use null for root folder
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Image Transformations
|
|
171
|
+
|
|
172
|
+
Get optimized and transformed image URLs:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const { url } = await stack0.cdn.getTransformUrl({
|
|
176
|
+
assetId: 'asset-id',
|
|
177
|
+
options: {
|
|
178
|
+
width: 800,
|
|
179
|
+
height: 600,
|
|
180
|
+
fit: 'cover', // 'cover', 'contain', 'fill', 'inside', 'outside'
|
|
181
|
+
format: 'webp', // 'webp', 'jpeg', 'png', 'avif'
|
|
182
|
+
quality: 80,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Use in <img> tag
|
|
187
|
+
// <img src={url} alt="Optimized image" />
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Folders
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Get folder tree
|
|
194
|
+
const tree = await stack0.cdn.getFolderTree({
|
|
195
|
+
projectSlug: 'my-project',
|
|
196
|
+
maxDepth: 3,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Create folder
|
|
200
|
+
const folder = await stack0.cdn.createFolder({
|
|
201
|
+
projectSlug: 'my-project',
|
|
202
|
+
name: 'avatars',
|
|
203
|
+
parentId: 'parent-folder-id', // Optional
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Delete folder
|
|
207
|
+
await stack0.cdn.deleteFolder('folder-id');
|
|
208
|
+
await stack0.cdn.deleteFolder('folder-id', true); // Delete with contents
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Mail API
|
|
212
|
+
|
|
213
|
+
The Mail API is compatible with the Resend API for easy migration.
|
|
214
|
+
|
|
215
|
+
### Send Email
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// Simple email
|
|
219
|
+
await stack0.mail.send({
|
|
220
|
+
from: 'hello@example.com',
|
|
221
|
+
to: 'user@example.com',
|
|
222
|
+
subject: 'Hello',
|
|
223
|
+
html: '<p>Welcome to Stack0!</p>',
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// With multiple recipients
|
|
227
|
+
await stack0.mail.send({
|
|
228
|
+
from: 'hello@example.com',
|
|
229
|
+
to: ['user1@example.com', 'user2@example.com'],
|
|
230
|
+
subject: 'Newsletter',
|
|
231
|
+
html: '<p>Monthly update</p>',
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// With name and email
|
|
235
|
+
await stack0.mail.send({
|
|
236
|
+
from: { name: 'Acme Inc', email: 'noreply@acme.com' },
|
|
237
|
+
to: { name: 'John Doe', email: 'john@example.com' },
|
|
238
|
+
subject: 'Important Update',
|
|
239
|
+
html: '<p>Your account has been updated</p>',
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// With CC and BCC
|
|
243
|
+
await stack0.mail.send({
|
|
244
|
+
from: 'hello@example.com',
|
|
245
|
+
to: 'user@example.com',
|
|
246
|
+
cc: 'manager@example.com',
|
|
247
|
+
bcc: ['audit@example.com', 'compliance@example.com'],
|
|
248
|
+
subject: 'Team Update',
|
|
249
|
+
html: '<p>Quarterly results</p>',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// With plain text alternative
|
|
253
|
+
await stack0.mail.send({
|
|
254
|
+
from: 'hello@example.com',
|
|
255
|
+
to: 'user@example.com',
|
|
256
|
+
subject: 'Hello',
|
|
257
|
+
html: '<h1>Welcome!</h1><p>Thanks for joining</p>',
|
|
258
|
+
text: 'Welcome! Thanks for joining',
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// With tags and metadata
|
|
262
|
+
await stack0.mail.send({
|
|
263
|
+
from: 'hello@example.com',
|
|
264
|
+
to: 'user@example.com',
|
|
265
|
+
subject: 'Order Confirmation',
|
|
266
|
+
html: '<p>Your order #12345 is confirmed</p>',
|
|
267
|
+
tags: ['transactional', 'order'],
|
|
268
|
+
metadata: {
|
|
269
|
+
orderId: '12345',
|
|
270
|
+
customerId: 'cus_abc123',
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// With template
|
|
275
|
+
await stack0.mail.send({
|
|
276
|
+
from: 'hello@example.com',
|
|
277
|
+
to: 'user@example.com',
|
|
278
|
+
subject: 'Welcome {{name}}',
|
|
279
|
+
templateId: 'template-uuid',
|
|
280
|
+
templateVariables: {
|
|
281
|
+
name: 'John',
|
|
282
|
+
activationUrl: 'https://example.com/activate?token=...',
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// With attachments
|
|
287
|
+
await stack0.mail.send({
|
|
288
|
+
from: 'hello@example.com',
|
|
289
|
+
to: 'user@example.com',
|
|
290
|
+
subject: 'Invoice',
|
|
291
|
+
html: '<p>Your invoice is attached</p>',
|
|
292
|
+
attachments: [
|
|
293
|
+
{
|
|
294
|
+
filename: 'invoice.pdf',
|
|
295
|
+
content: 'base64-encoded-content',
|
|
296
|
+
contentType: 'application/pdf',
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Get Email
|
|
303
|
+
|
|
304
|
+
Retrieve details about a sent email:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const email = await stack0.mail.get('email-id-uuid');
|
|
308
|
+
|
|
309
|
+
console.log(email.status); // 'sent', 'delivered', 'bounced', etc.
|
|
310
|
+
console.log(email.openedAt); // Date or null
|
|
311
|
+
console.log(email.deliveredAt); // Date or null
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Error Handling
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
try {
|
|
318
|
+
await stack0.mail.send({
|
|
319
|
+
from: 'hello@example.com',
|
|
320
|
+
to: 'user@example.com',
|
|
321
|
+
subject: 'Test',
|
|
322
|
+
html: '<p>Test</p>',
|
|
323
|
+
});
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error.statusCode === 401) {
|
|
326
|
+
console.error('Invalid API key');
|
|
327
|
+
} else if (error.statusCode === 403) {
|
|
328
|
+
console.error('Insufficient permissions');
|
|
329
|
+
} else if (error.statusCode === 400) {
|
|
330
|
+
console.error('Validation error:', error.message);
|
|
331
|
+
} else {
|
|
332
|
+
console.error('Error:', error.message);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## TypeScript Support
|
|
338
|
+
|
|
339
|
+
The SDK is written in TypeScript and includes full type definitions:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import type {
|
|
343
|
+
// Mail types
|
|
344
|
+
SendEmailRequest,
|
|
345
|
+
SendEmailResponse,
|
|
346
|
+
// CDN types
|
|
347
|
+
Asset,
|
|
348
|
+
UploadUrlRequest,
|
|
349
|
+
ListAssetsRequest,
|
|
350
|
+
TransformOptions,
|
|
351
|
+
} from '@stack0/sdk';
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Environment Variables
|
|
355
|
+
|
|
356
|
+
For security, store your API key in environment variables:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
const stack0 = new Stack0({
|
|
360
|
+
apiKey: process.env.STACK0_API_KEY!,
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Migration from Resend
|
|
365
|
+
|
|
366
|
+
Stack0 Mail API is designed to be compatible with Resend:
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
// Before (Resend)
|
|
370
|
+
import { Resend } from 'resend';
|
|
371
|
+
const resend = new Resend('re_...');
|
|
372
|
+
await resend.emails.send({ ... });
|
|
373
|
+
|
|
374
|
+
// After (Stack0)
|
|
375
|
+
import { Stack0 } from '@stack0/sdk';
|
|
376
|
+
const stack0 = new Stack0({ apiKey: 'stack0_...' });
|
|
377
|
+
await stack0.mail.send({ ... });
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Support
|
|
381
|
+
|
|
382
|
+
- Documentation: https://docs.stack0.com
|
|
383
|
+
- Issues: https://github.com/CampbellVentures/stack0/issues
|
|
384
|
+
- Email: support@stack0.com
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
MIT
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { H as HttpClientConfig } from '../http-client-Wr9lXo9_.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions for Stack0 CDN API
|
|
5
|
+
*/
|
|
6
|
+
type AssetStatus = "pending" | "processing" | "ready" | "failed" | "deleted";
|
|
7
|
+
type AssetType = "image" | "video" | "audio" | "document" | "other";
|
|
8
|
+
interface Asset {
|
|
9
|
+
id: string;
|
|
10
|
+
filename: string;
|
|
11
|
+
originalFilename: string;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
size: number;
|
|
14
|
+
type: AssetType;
|
|
15
|
+
s3Key: string;
|
|
16
|
+
cdnUrl: string;
|
|
17
|
+
width: number | null;
|
|
18
|
+
height: number | null;
|
|
19
|
+
duration: number | null;
|
|
20
|
+
status: AssetStatus;
|
|
21
|
+
folder: string | null;
|
|
22
|
+
tags: string[] | null;
|
|
23
|
+
metadata: Record<string, unknown> | null;
|
|
24
|
+
alt: string | null;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
updatedAt: Date | null;
|
|
27
|
+
}
|
|
28
|
+
interface UploadUrlRequest {
|
|
29
|
+
projectSlug: string;
|
|
30
|
+
filename: string;
|
|
31
|
+
mimeType: string;
|
|
32
|
+
size: number;
|
|
33
|
+
folder?: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
interface UploadUrlResponse {
|
|
37
|
+
uploadUrl: string;
|
|
38
|
+
assetId: string;
|
|
39
|
+
cdnUrl: string;
|
|
40
|
+
expiresAt: Date;
|
|
41
|
+
}
|
|
42
|
+
interface ConfirmUploadRequest {
|
|
43
|
+
assetId: string;
|
|
44
|
+
}
|
|
45
|
+
interface ConfirmUploadResponse {
|
|
46
|
+
asset: Asset;
|
|
47
|
+
}
|
|
48
|
+
interface GetAssetRequest {
|
|
49
|
+
id: string;
|
|
50
|
+
}
|
|
51
|
+
interface UpdateAssetRequest {
|
|
52
|
+
id: string;
|
|
53
|
+
filename?: string;
|
|
54
|
+
folder?: string;
|
|
55
|
+
tags?: string[];
|
|
56
|
+
alt?: string;
|
|
57
|
+
metadata?: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
interface DeleteAssetRequest {
|
|
60
|
+
id: string;
|
|
61
|
+
}
|
|
62
|
+
interface DeleteAssetsRequest {
|
|
63
|
+
ids: string[];
|
|
64
|
+
}
|
|
65
|
+
interface DeleteAssetsResponse {
|
|
66
|
+
success: boolean;
|
|
67
|
+
deletedCount: number;
|
|
68
|
+
}
|
|
69
|
+
interface ListAssetsRequest {
|
|
70
|
+
projectSlug: string;
|
|
71
|
+
folder?: string | null;
|
|
72
|
+
type?: AssetType;
|
|
73
|
+
status?: AssetStatus;
|
|
74
|
+
search?: string;
|
|
75
|
+
tags?: string[];
|
|
76
|
+
sortBy?: "createdAt" | "filename" | "size" | "type";
|
|
77
|
+
sortOrder?: "asc" | "desc";
|
|
78
|
+
limit?: number;
|
|
79
|
+
offset?: number;
|
|
80
|
+
}
|
|
81
|
+
interface ListAssetsResponse {
|
|
82
|
+
assets: Asset[];
|
|
83
|
+
total: number;
|
|
84
|
+
hasMore: boolean;
|
|
85
|
+
}
|
|
86
|
+
interface MoveAssetsRequest {
|
|
87
|
+
assetIds: string[];
|
|
88
|
+
folder: string | null;
|
|
89
|
+
}
|
|
90
|
+
interface MoveAssetsResponse {
|
|
91
|
+
success: boolean;
|
|
92
|
+
movedCount: number;
|
|
93
|
+
}
|
|
94
|
+
interface TransformOptions {
|
|
95
|
+
width?: number;
|
|
96
|
+
height?: number;
|
|
97
|
+
fit?: "cover" | "contain" | "fill" | "inside" | "outside";
|
|
98
|
+
format?: "webp" | "jpeg" | "png" | "avif";
|
|
99
|
+
quality?: number;
|
|
100
|
+
}
|
|
101
|
+
interface GetTransformUrlRequest {
|
|
102
|
+
assetId: string;
|
|
103
|
+
options: TransformOptions;
|
|
104
|
+
}
|
|
105
|
+
interface GetTransformUrlResponse {
|
|
106
|
+
url: string;
|
|
107
|
+
originalUrl: string;
|
|
108
|
+
width?: number;
|
|
109
|
+
height?: number;
|
|
110
|
+
format?: string;
|
|
111
|
+
}
|
|
112
|
+
interface FolderTreeNode {
|
|
113
|
+
id: string;
|
|
114
|
+
name: string;
|
|
115
|
+
path: string;
|
|
116
|
+
assetCount: number;
|
|
117
|
+
children: FolderTreeNode[];
|
|
118
|
+
}
|
|
119
|
+
interface GetFolderTreeRequest {
|
|
120
|
+
projectSlug: string;
|
|
121
|
+
maxDepth?: number;
|
|
122
|
+
}
|
|
123
|
+
interface CreateFolderRequest {
|
|
124
|
+
projectSlug: string;
|
|
125
|
+
name: string;
|
|
126
|
+
parentId?: string;
|
|
127
|
+
}
|
|
128
|
+
interface Folder {
|
|
129
|
+
id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
path: string;
|
|
132
|
+
parentId: string | null;
|
|
133
|
+
assetCount: number;
|
|
134
|
+
totalSize: number;
|
|
135
|
+
createdAt: Date;
|
|
136
|
+
updatedAt: Date | null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Stack0 CDN Client
|
|
141
|
+
* Upload, manage, and transform assets
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
declare class CDN {
|
|
145
|
+
private http;
|
|
146
|
+
constructor(config: HttpClientConfig);
|
|
147
|
+
/**
|
|
148
|
+
* Generate a presigned URL for uploading a file
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const { uploadUrl, assetId } = await cdn.getUploadUrl({
|
|
153
|
+
* projectSlug: 'my-project',
|
|
154
|
+
* filename: 'image.jpg',
|
|
155
|
+
* mimeType: 'image/jpeg',
|
|
156
|
+
* size: 1024 * 1024,
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* // Upload file to the presigned URL
|
|
160
|
+
* await fetch(uploadUrl, {
|
|
161
|
+
* method: 'PUT',
|
|
162
|
+
* body: file,
|
|
163
|
+
* headers: { 'Content-Type': 'image/jpeg' },
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* // Confirm the upload
|
|
167
|
+
* const asset = await cdn.confirmUpload(assetId);
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
getUploadUrl(request: UploadUrlRequest): Promise<UploadUrlResponse>;
|
|
171
|
+
/**
|
|
172
|
+
* Confirm that an upload has completed
|
|
173
|
+
*/
|
|
174
|
+
confirmUpload(assetId: string): Promise<Asset>;
|
|
175
|
+
/**
|
|
176
|
+
* Upload a file directly (handles presigned URL flow automatically)
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const asset = await cdn.upload({
|
|
181
|
+
* projectSlug: 'my-project',
|
|
182
|
+
* file: fileBuffer,
|
|
183
|
+
* filename: 'image.jpg',
|
|
184
|
+
* mimeType: 'image/jpeg',
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
upload(options: {
|
|
189
|
+
projectSlug: string;
|
|
190
|
+
file: Blob | Buffer | ArrayBuffer;
|
|
191
|
+
filename: string;
|
|
192
|
+
mimeType: string;
|
|
193
|
+
folder?: string;
|
|
194
|
+
metadata?: Record<string, unknown>;
|
|
195
|
+
}): Promise<Asset>;
|
|
196
|
+
/**
|
|
197
|
+
* Get an asset by ID
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const asset = await cdn.get('asset-id');
|
|
202
|
+
* console.log(asset.cdnUrl);
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
get(id: string): Promise<Asset>;
|
|
206
|
+
/**
|
|
207
|
+
* Update asset metadata
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const asset = await cdn.update({
|
|
212
|
+
* id: 'asset-id',
|
|
213
|
+
* alt: 'A beautiful sunset',
|
|
214
|
+
* tags: ['nature', 'sunset'],
|
|
215
|
+
* });
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
update(request: UpdateAssetRequest): Promise<Asset>;
|
|
219
|
+
/**
|
|
220
|
+
* Delete an asset
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* await cdn.delete('asset-id');
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
delete(id: string): Promise<{
|
|
228
|
+
success: boolean;
|
|
229
|
+
}>;
|
|
230
|
+
/**
|
|
231
|
+
* Delete multiple assets
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const result = await cdn.deleteMany(['asset-1', 'asset-2']);
|
|
236
|
+
* console.log(`Deleted ${result.deletedCount} assets`);
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
deleteMany(ids: string[]): Promise<DeleteAssetsResponse>;
|
|
240
|
+
/**
|
|
241
|
+
* List assets with filters and pagination
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* const { assets, total, hasMore } = await cdn.list({
|
|
246
|
+
* projectSlug: 'my-project',
|
|
247
|
+
* type: 'image',
|
|
248
|
+
* limit: 20,
|
|
249
|
+
* });
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
list(request: ListAssetsRequest): Promise<ListAssetsResponse>;
|
|
253
|
+
/**
|
|
254
|
+
* Move assets to a different folder
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* await cdn.move({
|
|
259
|
+
* assetIds: ['asset-1', 'asset-2'],
|
|
260
|
+
* folder: '/images/archive',
|
|
261
|
+
* });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
move(request: MoveAssetsRequest): Promise<MoveAssetsResponse>;
|
|
265
|
+
/**
|
|
266
|
+
* Get a transformed image URL
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const { url } = await cdn.getTransformUrl({
|
|
271
|
+
* assetId: 'asset-id',
|
|
272
|
+
* options: {
|
|
273
|
+
* width: 800,
|
|
274
|
+
* height: 600,
|
|
275
|
+
* fit: 'cover',
|
|
276
|
+
* format: 'webp',
|
|
277
|
+
* quality: 80,
|
|
278
|
+
* },
|
|
279
|
+
* });
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
getTransformUrl(request: GetTransformUrlRequest): Promise<GetTransformUrlResponse>;
|
|
283
|
+
/**
|
|
284
|
+
* Get folder tree for navigation
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* const tree = await cdn.getFolderTree({
|
|
289
|
+
* projectSlug: 'my-project',
|
|
290
|
+
* maxDepth: 3,
|
|
291
|
+
* });
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
getFolderTree(request: GetFolderTreeRequest): Promise<FolderTreeNode[]>;
|
|
295
|
+
/**
|
|
296
|
+
* Create a new folder
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const folder = await cdn.createFolder({
|
|
301
|
+
* projectSlug: 'my-project',
|
|
302
|
+
* name: 'images',
|
|
303
|
+
* });
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
createFolder(request: CreateFolderRequest): Promise<Folder>;
|
|
307
|
+
/**
|
|
308
|
+
* Delete a folder
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```typescript
|
|
312
|
+
* await cdn.deleteFolder('folder-id');
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
deleteFolder(id: string, deleteContents?: boolean): Promise<{
|
|
316
|
+
success: boolean;
|
|
317
|
+
}>;
|
|
318
|
+
private convertAssetDates;
|
|
319
|
+
private convertFolderDates;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export { type Asset, type AssetStatus, type AssetType, CDN, type ConfirmUploadRequest, type ConfirmUploadResponse, type CreateFolderRequest, type DeleteAssetRequest, type DeleteAssetsRequest, type DeleteAssetsResponse, type Folder, type FolderTreeNode, type GetAssetRequest, type GetFolderTreeRequest, type GetTransformUrlRequest, type GetTransformUrlResponse, type ListAssetsRequest, type ListAssetsResponse, type MoveAssetsRequest, type MoveAssetsResponse, type TransformOptions, type UpdateAssetRequest, type UploadUrlRequest, type UploadUrlResponse };
|