@hammr/cdn 1.0.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 +604 -0
- package/dist/index.cjs +419 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +357 -0
- package/dist/index.d.ts +357 -0
- package/dist/index.js +388 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for CDN storage system
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Metadata for stored artifacts
|
|
6
|
+
*/
|
|
7
|
+
interface ArtifactMetadata {
|
|
8
|
+
/**
|
|
9
|
+
* Content-Type header (e.g., 'image/png', 'application/json')
|
|
10
|
+
*/
|
|
11
|
+
contentType?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Original filename (if provided)
|
|
14
|
+
*/
|
|
15
|
+
filename?: string;
|
|
16
|
+
/**
|
|
17
|
+
* File size in bytes
|
|
18
|
+
*/
|
|
19
|
+
size?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Upload timestamp (Unix milliseconds)
|
|
22
|
+
*/
|
|
23
|
+
uploadedAt?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Custom metadata fields
|
|
26
|
+
*/
|
|
27
|
+
customMetadata?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Stored artifact with content and metadata
|
|
31
|
+
*/
|
|
32
|
+
interface StoredArtifact {
|
|
33
|
+
/**
|
|
34
|
+
* Content-addressable hash (SHA256)
|
|
35
|
+
*/
|
|
36
|
+
hash: string;
|
|
37
|
+
/**
|
|
38
|
+
* Artifact content (raw bytes)
|
|
39
|
+
*/
|
|
40
|
+
body: ArrayBuffer | ReadableStream | Uint8Array;
|
|
41
|
+
/**
|
|
42
|
+
* Metadata about the artifact
|
|
43
|
+
*/
|
|
44
|
+
metadata: ArtifactMetadata;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result from uploading an artifact
|
|
48
|
+
*/
|
|
49
|
+
interface UploadResult {
|
|
50
|
+
/**
|
|
51
|
+
* Content-addressable hash
|
|
52
|
+
*/
|
|
53
|
+
hash: string;
|
|
54
|
+
/**
|
|
55
|
+
* Public URL to access the artifact
|
|
56
|
+
*/
|
|
57
|
+
url: string;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this was a new upload (true) or already existed (false)
|
|
60
|
+
*/
|
|
61
|
+
created: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Artifact metadata
|
|
64
|
+
*/
|
|
65
|
+
metadata: ArtifactMetadata;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Storage adapter interface
|
|
69
|
+
*
|
|
70
|
+
* Implement this to support different storage backends (R2, S3, etc.)
|
|
71
|
+
*/
|
|
72
|
+
interface StorageAdapter {
|
|
73
|
+
/**
|
|
74
|
+
* Store artifact content with hash as key
|
|
75
|
+
*
|
|
76
|
+
* @param hash - Content-addressable hash (SHA256)
|
|
77
|
+
* @param content - Raw bytes to store
|
|
78
|
+
* @param metadata - Optional metadata
|
|
79
|
+
*/
|
|
80
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Retrieve artifact by hash
|
|
83
|
+
*
|
|
84
|
+
* @param hash - Content-addressable hash
|
|
85
|
+
* @returns Artifact or null if not found
|
|
86
|
+
*/
|
|
87
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
88
|
+
/**
|
|
89
|
+
* Delete artifact by hash
|
|
90
|
+
*
|
|
91
|
+
* @param hash - Content-addressable hash
|
|
92
|
+
* @returns true if deleted, false if not found
|
|
93
|
+
*/
|
|
94
|
+
delete(hash: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Check if artifact exists
|
|
97
|
+
*
|
|
98
|
+
* @param hash - Content-addressable hash
|
|
99
|
+
* @returns true if exists, false otherwise
|
|
100
|
+
*/
|
|
101
|
+
exists(hash: string): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* List all artifact hashes (optional, for admin/debugging)
|
|
104
|
+
*
|
|
105
|
+
* @param options - List options (limit, cursor, etc.)
|
|
106
|
+
* @returns Array of hashes
|
|
107
|
+
*/
|
|
108
|
+
list?(options?: {
|
|
109
|
+
limit?: number;
|
|
110
|
+
cursor?: string;
|
|
111
|
+
}): Promise<string[]>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Options for CDN
|
|
115
|
+
*/
|
|
116
|
+
interface CDNOptions {
|
|
117
|
+
/**
|
|
118
|
+
* Storage adapter (R2, S3, Memory, etc.)
|
|
119
|
+
*/
|
|
120
|
+
storage: StorageAdapter;
|
|
121
|
+
/**
|
|
122
|
+
* Base URL for generating artifact URLs
|
|
123
|
+
* @example 'https://cdn.example.com'
|
|
124
|
+
*/
|
|
125
|
+
baseUrl: string;
|
|
126
|
+
/**
|
|
127
|
+
* Cache-Control max-age in seconds
|
|
128
|
+
* @default 31536000 (1 year)
|
|
129
|
+
*/
|
|
130
|
+
cacheMaxAge?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Default content type if not detected
|
|
133
|
+
* @default 'application/octet-stream'
|
|
134
|
+
*/
|
|
135
|
+
defaultContentType?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Enable CORS headers
|
|
138
|
+
* @default true
|
|
139
|
+
*/
|
|
140
|
+
cors?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Content type map for common extensions
|
|
144
|
+
*/
|
|
145
|
+
declare const CONTENT_TYPES: Record<string, string>;
|
|
146
|
+
/**
|
|
147
|
+
* Detect content type from filename extension
|
|
148
|
+
*/
|
|
149
|
+
declare function detectContentType(filename: string, defaultType?: string): string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* CDN - Content-Addressable Storage System
|
|
153
|
+
*
|
|
154
|
+
* Features:
|
|
155
|
+
* - Content-addressable (SHA256 hashing via @sygnl/normalizer)
|
|
156
|
+
* - Storage abstraction (R2, S3, Memory, etc.)
|
|
157
|
+
* - Automatic content-type detection
|
|
158
|
+
* - Immutable artifacts (hash-based URLs)
|
|
159
|
+
* - Cache-friendly headers
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
declare class CDN {
|
|
163
|
+
private storage;
|
|
164
|
+
private baseUrl;
|
|
165
|
+
private cacheMaxAge;
|
|
166
|
+
private defaultContentType;
|
|
167
|
+
private cors;
|
|
168
|
+
constructor(options: CDNOptions);
|
|
169
|
+
/**
|
|
170
|
+
* Upload an artifact and get content-addressable URL
|
|
171
|
+
*
|
|
172
|
+
* @param content - Raw bytes to upload
|
|
173
|
+
* @param metadata - Optional metadata (filename, contentType, etc.)
|
|
174
|
+
* @returns Upload result with hash and URL
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const result = await cdn.put(imageBytes, {
|
|
179
|
+
* filename: 'logo.png',
|
|
180
|
+
* contentType: 'image/png'
|
|
181
|
+
* });
|
|
182
|
+
*
|
|
183
|
+
* console.log(result.url); // https://cdn.example.com/a/5e88489...
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
put(content: ArrayBuffer | Uint8Array, metadata?: Partial<ArtifactMetadata>): Promise<UploadResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Retrieve an artifact by hash
|
|
189
|
+
*
|
|
190
|
+
* @param hash - Content-addressable hash
|
|
191
|
+
* @returns Artifact or null if not found
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const artifact = await cdn.get('5e884898...');
|
|
196
|
+
* if (artifact) {
|
|
197
|
+
* console.log(artifact.metadata.contentType);
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
202
|
+
/**
|
|
203
|
+
* Delete an artifact by hash
|
|
204
|
+
*
|
|
205
|
+
* @param hash - Content-addressable hash
|
|
206
|
+
* @returns true if deleted, false if not found
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* const deleted = await cdn.delete('5e884898...');
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
delete(hash: string): Promise<boolean>;
|
|
214
|
+
/**
|
|
215
|
+
* Check if artifact exists
|
|
216
|
+
*
|
|
217
|
+
* @param hash - Content-addressable hash
|
|
218
|
+
* @returns true if exists
|
|
219
|
+
*/
|
|
220
|
+
exists(hash: string): Promise<boolean>;
|
|
221
|
+
/**
|
|
222
|
+
* List all artifacts (if supported by storage adapter)
|
|
223
|
+
*
|
|
224
|
+
* @param options - List options
|
|
225
|
+
* @returns Array of hashes
|
|
226
|
+
*/
|
|
227
|
+
list(options?: {
|
|
228
|
+
limit?: number;
|
|
229
|
+
cursor?: string;
|
|
230
|
+
}): Promise<string[]>;
|
|
231
|
+
/**
|
|
232
|
+
* Handle HTTP request (for Cloudflare Workers, Express, etc.)
|
|
233
|
+
*
|
|
234
|
+
* Routes:
|
|
235
|
+
* - PUT /artifact - Upload artifact
|
|
236
|
+
* - GET /a/:hash(.ext) - Retrieve artifact
|
|
237
|
+
* - DELETE /a/:hash - Delete artifact
|
|
238
|
+
*
|
|
239
|
+
* @param request - HTTP request
|
|
240
|
+
* @returns HTTP response
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* export default {
|
|
245
|
+
* async fetch(request, env) {
|
|
246
|
+
* const cdn = new CDN({
|
|
247
|
+
* storage: new R2Storage(env.ARTIFACTS),
|
|
248
|
+
* baseUrl: 'https://cdn.example.com'
|
|
249
|
+
* });
|
|
250
|
+
* return cdn.handleRequest(request);
|
|
251
|
+
* }
|
|
252
|
+
* }
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
handleRequest(request: Request): Promise<Response>;
|
|
256
|
+
/**
|
|
257
|
+
* Get CORS headers if enabled
|
|
258
|
+
*/
|
|
259
|
+
private getCORSHeaders;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* In-memory storage adapter
|
|
264
|
+
*
|
|
265
|
+
* Useful for:
|
|
266
|
+
* - Testing
|
|
267
|
+
* - Development
|
|
268
|
+
* - Temporary caching
|
|
269
|
+
*
|
|
270
|
+
* NOT for production (data lost on restart)
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
declare class MemoryStorage implements StorageAdapter {
|
|
274
|
+
private storage;
|
|
275
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
276
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
277
|
+
delete(hash: string): Promise<boolean>;
|
|
278
|
+
exists(hash: string): Promise<boolean>;
|
|
279
|
+
list(options?: {
|
|
280
|
+
limit?: number;
|
|
281
|
+
cursor?: string;
|
|
282
|
+
}): Promise<string[]>;
|
|
283
|
+
/**
|
|
284
|
+
* Clear all stored artifacts (useful for testing)
|
|
285
|
+
*/
|
|
286
|
+
clear(): void;
|
|
287
|
+
/**
|
|
288
|
+
* Get storage size (number of artifacts)
|
|
289
|
+
*/
|
|
290
|
+
size(): number;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Cloudflare R2 storage adapter
|
|
295
|
+
*
|
|
296
|
+
* Uses Cloudflare R2 for artifact storage.
|
|
297
|
+
*
|
|
298
|
+
* Usage:
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const storage = new R2Storage(env.ARTIFACTS);
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Minimal R2 bucket interface
|
|
306
|
+
* (matches Cloudflare Workers R2Bucket type)
|
|
307
|
+
*/
|
|
308
|
+
interface R2Bucket {
|
|
309
|
+
put(key: string, value: ArrayBuffer | Uint8Array | ReadableStream, options?: {
|
|
310
|
+
httpMetadata?: {
|
|
311
|
+
contentType?: string;
|
|
312
|
+
};
|
|
313
|
+
customMetadata?: Record<string, string>;
|
|
314
|
+
}): Promise<any>;
|
|
315
|
+
get(key: string): Promise<{
|
|
316
|
+
body?: ReadableStream | ArrayBuffer;
|
|
317
|
+
httpMetadata?: {
|
|
318
|
+
contentType?: string;
|
|
319
|
+
};
|
|
320
|
+
customMetadata?: Record<string, string>;
|
|
321
|
+
size?: number;
|
|
322
|
+
uploaded?: Date;
|
|
323
|
+
} | null>;
|
|
324
|
+
delete(key: string): Promise<void>;
|
|
325
|
+
head(key: string): Promise<{
|
|
326
|
+
httpMetadata?: {
|
|
327
|
+
contentType?: string;
|
|
328
|
+
};
|
|
329
|
+
customMetadata?: Record<string, string>;
|
|
330
|
+
size?: number;
|
|
331
|
+
uploaded?: Date;
|
|
332
|
+
} | null>;
|
|
333
|
+
list?(options?: {
|
|
334
|
+
limit?: number;
|
|
335
|
+
cursor?: string;
|
|
336
|
+
}): Promise<{
|
|
337
|
+
objects: Array<{
|
|
338
|
+
key: string;
|
|
339
|
+
}>;
|
|
340
|
+
truncated: boolean;
|
|
341
|
+
cursor?: string;
|
|
342
|
+
}>;
|
|
343
|
+
}
|
|
344
|
+
declare class R2Storage implements StorageAdapter {
|
|
345
|
+
private bucket;
|
|
346
|
+
constructor(bucket: R2Bucket);
|
|
347
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
348
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
349
|
+
delete(hash: string): Promise<boolean>;
|
|
350
|
+
exists(hash: string): Promise<boolean>;
|
|
351
|
+
list(options?: {
|
|
352
|
+
limit?: number;
|
|
353
|
+
cursor?: string;
|
|
354
|
+
}): Promise<string[]>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export { type ArtifactMetadata, CDN, type CDNOptions, CONTENT_TYPES, MemoryStorage, type R2Bucket, R2Storage, type StorageAdapter, type StoredArtifact, type UploadResult, detectContentType };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for CDN storage system
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Metadata for stored artifacts
|
|
6
|
+
*/
|
|
7
|
+
interface ArtifactMetadata {
|
|
8
|
+
/**
|
|
9
|
+
* Content-Type header (e.g., 'image/png', 'application/json')
|
|
10
|
+
*/
|
|
11
|
+
contentType?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Original filename (if provided)
|
|
14
|
+
*/
|
|
15
|
+
filename?: string;
|
|
16
|
+
/**
|
|
17
|
+
* File size in bytes
|
|
18
|
+
*/
|
|
19
|
+
size?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Upload timestamp (Unix milliseconds)
|
|
22
|
+
*/
|
|
23
|
+
uploadedAt?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Custom metadata fields
|
|
26
|
+
*/
|
|
27
|
+
customMetadata?: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Stored artifact with content and metadata
|
|
31
|
+
*/
|
|
32
|
+
interface StoredArtifact {
|
|
33
|
+
/**
|
|
34
|
+
* Content-addressable hash (SHA256)
|
|
35
|
+
*/
|
|
36
|
+
hash: string;
|
|
37
|
+
/**
|
|
38
|
+
* Artifact content (raw bytes)
|
|
39
|
+
*/
|
|
40
|
+
body: ArrayBuffer | ReadableStream | Uint8Array;
|
|
41
|
+
/**
|
|
42
|
+
* Metadata about the artifact
|
|
43
|
+
*/
|
|
44
|
+
metadata: ArtifactMetadata;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result from uploading an artifact
|
|
48
|
+
*/
|
|
49
|
+
interface UploadResult {
|
|
50
|
+
/**
|
|
51
|
+
* Content-addressable hash
|
|
52
|
+
*/
|
|
53
|
+
hash: string;
|
|
54
|
+
/**
|
|
55
|
+
* Public URL to access the artifact
|
|
56
|
+
*/
|
|
57
|
+
url: string;
|
|
58
|
+
/**
|
|
59
|
+
* Whether this was a new upload (true) or already existed (false)
|
|
60
|
+
*/
|
|
61
|
+
created: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Artifact metadata
|
|
64
|
+
*/
|
|
65
|
+
metadata: ArtifactMetadata;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Storage adapter interface
|
|
69
|
+
*
|
|
70
|
+
* Implement this to support different storage backends (R2, S3, etc.)
|
|
71
|
+
*/
|
|
72
|
+
interface StorageAdapter {
|
|
73
|
+
/**
|
|
74
|
+
* Store artifact content with hash as key
|
|
75
|
+
*
|
|
76
|
+
* @param hash - Content-addressable hash (SHA256)
|
|
77
|
+
* @param content - Raw bytes to store
|
|
78
|
+
* @param metadata - Optional metadata
|
|
79
|
+
*/
|
|
80
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Retrieve artifact by hash
|
|
83
|
+
*
|
|
84
|
+
* @param hash - Content-addressable hash
|
|
85
|
+
* @returns Artifact or null if not found
|
|
86
|
+
*/
|
|
87
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
88
|
+
/**
|
|
89
|
+
* Delete artifact by hash
|
|
90
|
+
*
|
|
91
|
+
* @param hash - Content-addressable hash
|
|
92
|
+
* @returns true if deleted, false if not found
|
|
93
|
+
*/
|
|
94
|
+
delete(hash: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Check if artifact exists
|
|
97
|
+
*
|
|
98
|
+
* @param hash - Content-addressable hash
|
|
99
|
+
* @returns true if exists, false otherwise
|
|
100
|
+
*/
|
|
101
|
+
exists(hash: string): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* List all artifact hashes (optional, for admin/debugging)
|
|
104
|
+
*
|
|
105
|
+
* @param options - List options (limit, cursor, etc.)
|
|
106
|
+
* @returns Array of hashes
|
|
107
|
+
*/
|
|
108
|
+
list?(options?: {
|
|
109
|
+
limit?: number;
|
|
110
|
+
cursor?: string;
|
|
111
|
+
}): Promise<string[]>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Options for CDN
|
|
115
|
+
*/
|
|
116
|
+
interface CDNOptions {
|
|
117
|
+
/**
|
|
118
|
+
* Storage adapter (R2, S3, Memory, etc.)
|
|
119
|
+
*/
|
|
120
|
+
storage: StorageAdapter;
|
|
121
|
+
/**
|
|
122
|
+
* Base URL for generating artifact URLs
|
|
123
|
+
* @example 'https://cdn.example.com'
|
|
124
|
+
*/
|
|
125
|
+
baseUrl: string;
|
|
126
|
+
/**
|
|
127
|
+
* Cache-Control max-age in seconds
|
|
128
|
+
* @default 31536000 (1 year)
|
|
129
|
+
*/
|
|
130
|
+
cacheMaxAge?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Default content type if not detected
|
|
133
|
+
* @default 'application/octet-stream'
|
|
134
|
+
*/
|
|
135
|
+
defaultContentType?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Enable CORS headers
|
|
138
|
+
* @default true
|
|
139
|
+
*/
|
|
140
|
+
cors?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Content type map for common extensions
|
|
144
|
+
*/
|
|
145
|
+
declare const CONTENT_TYPES: Record<string, string>;
|
|
146
|
+
/**
|
|
147
|
+
* Detect content type from filename extension
|
|
148
|
+
*/
|
|
149
|
+
declare function detectContentType(filename: string, defaultType?: string): string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* CDN - Content-Addressable Storage System
|
|
153
|
+
*
|
|
154
|
+
* Features:
|
|
155
|
+
* - Content-addressable (SHA256 hashing via @sygnl/normalizer)
|
|
156
|
+
* - Storage abstraction (R2, S3, Memory, etc.)
|
|
157
|
+
* - Automatic content-type detection
|
|
158
|
+
* - Immutable artifacts (hash-based URLs)
|
|
159
|
+
* - Cache-friendly headers
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
declare class CDN {
|
|
163
|
+
private storage;
|
|
164
|
+
private baseUrl;
|
|
165
|
+
private cacheMaxAge;
|
|
166
|
+
private defaultContentType;
|
|
167
|
+
private cors;
|
|
168
|
+
constructor(options: CDNOptions);
|
|
169
|
+
/**
|
|
170
|
+
* Upload an artifact and get content-addressable URL
|
|
171
|
+
*
|
|
172
|
+
* @param content - Raw bytes to upload
|
|
173
|
+
* @param metadata - Optional metadata (filename, contentType, etc.)
|
|
174
|
+
* @returns Upload result with hash and URL
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const result = await cdn.put(imageBytes, {
|
|
179
|
+
* filename: 'logo.png',
|
|
180
|
+
* contentType: 'image/png'
|
|
181
|
+
* });
|
|
182
|
+
*
|
|
183
|
+
* console.log(result.url); // https://cdn.example.com/a/5e88489...
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
put(content: ArrayBuffer | Uint8Array, metadata?: Partial<ArtifactMetadata>): Promise<UploadResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Retrieve an artifact by hash
|
|
189
|
+
*
|
|
190
|
+
* @param hash - Content-addressable hash
|
|
191
|
+
* @returns Artifact or null if not found
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const artifact = await cdn.get('5e884898...');
|
|
196
|
+
* if (artifact) {
|
|
197
|
+
* console.log(artifact.metadata.contentType);
|
|
198
|
+
* }
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
202
|
+
/**
|
|
203
|
+
* Delete an artifact by hash
|
|
204
|
+
*
|
|
205
|
+
* @param hash - Content-addressable hash
|
|
206
|
+
* @returns true if deleted, false if not found
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* const deleted = await cdn.delete('5e884898...');
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
delete(hash: string): Promise<boolean>;
|
|
214
|
+
/**
|
|
215
|
+
* Check if artifact exists
|
|
216
|
+
*
|
|
217
|
+
* @param hash - Content-addressable hash
|
|
218
|
+
* @returns true if exists
|
|
219
|
+
*/
|
|
220
|
+
exists(hash: string): Promise<boolean>;
|
|
221
|
+
/**
|
|
222
|
+
* List all artifacts (if supported by storage adapter)
|
|
223
|
+
*
|
|
224
|
+
* @param options - List options
|
|
225
|
+
* @returns Array of hashes
|
|
226
|
+
*/
|
|
227
|
+
list(options?: {
|
|
228
|
+
limit?: number;
|
|
229
|
+
cursor?: string;
|
|
230
|
+
}): Promise<string[]>;
|
|
231
|
+
/**
|
|
232
|
+
* Handle HTTP request (for Cloudflare Workers, Express, etc.)
|
|
233
|
+
*
|
|
234
|
+
* Routes:
|
|
235
|
+
* - PUT /artifact - Upload artifact
|
|
236
|
+
* - GET /a/:hash(.ext) - Retrieve artifact
|
|
237
|
+
* - DELETE /a/:hash - Delete artifact
|
|
238
|
+
*
|
|
239
|
+
* @param request - HTTP request
|
|
240
|
+
* @returns HTTP response
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* export default {
|
|
245
|
+
* async fetch(request, env) {
|
|
246
|
+
* const cdn = new CDN({
|
|
247
|
+
* storage: new R2Storage(env.ARTIFACTS),
|
|
248
|
+
* baseUrl: 'https://cdn.example.com'
|
|
249
|
+
* });
|
|
250
|
+
* return cdn.handleRequest(request);
|
|
251
|
+
* }
|
|
252
|
+
* }
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
handleRequest(request: Request): Promise<Response>;
|
|
256
|
+
/**
|
|
257
|
+
* Get CORS headers if enabled
|
|
258
|
+
*/
|
|
259
|
+
private getCORSHeaders;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* In-memory storage adapter
|
|
264
|
+
*
|
|
265
|
+
* Useful for:
|
|
266
|
+
* - Testing
|
|
267
|
+
* - Development
|
|
268
|
+
* - Temporary caching
|
|
269
|
+
*
|
|
270
|
+
* NOT for production (data lost on restart)
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
declare class MemoryStorage implements StorageAdapter {
|
|
274
|
+
private storage;
|
|
275
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
276
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
277
|
+
delete(hash: string): Promise<boolean>;
|
|
278
|
+
exists(hash: string): Promise<boolean>;
|
|
279
|
+
list(options?: {
|
|
280
|
+
limit?: number;
|
|
281
|
+
cursor?: string;
|
|
282
|
+
}): Promise<string[]>;
|
|
283
|
+
/**
|
|
284
|
+
* Clear all stored artifacts (useful for testing)
|
|
285
|
+
*/
|
|
286
|
+
clear(): void;
|
|
287
|
+
/**
|
|
288
|
+
* Get storage size (number of artifacts)
|
|
289
|
+
*/
|
|
290
|
+
size(): number;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Cloudflare R2 storage adapter
|
|
295
|
+
*
|
|
296
|
+
* Uses Cloudflare R2 for artifact storage.
|
|
297
|
+
*
|
|
298
|
+
* Usage:
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const storage = new R2Storage(env.ARTIFACTS);
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Minimal R2 bucket interface
|
|
306
|
+
* (matches Cloudflare Workers R2Bucket type)
|
|
307
|
+
*/
|
|
308
|
+
interface R2Bucket {
|
|
309
|
+
put(key: string, value: ArrayBuffer | Uint8Array | ReadableStream, options?: {
|
|
310
|
+
httpMetadata?: {
|
|
311
|
+
contentType?: string;
|
|
312
|
+
};
|
|
313
|
+
customMetadata?: Record<string, string>;
|
|
314
|
+
}): Promise<any>;
|
|
315
|
+
get(key: string): Promise<{
|
|
316
|
+
body?: ReadableStream | ArrayBuffer;
|
|
317
|
+
httpMetadata?: {
|
|
318
|
+
contentType?: string;
|
|
319
|
+
};
|
|
320
|
+
customMetadata?: Record<string, string>;
|
|
321
|
+
size?: number;
|
|
322
|
+
uploaded?: Date;
|
|
323
|
+
} | null>;
|
|
324
|
+
delete(key: string): Promise<void>;
|
|
325
|
+
head(key: string): Promise<{
|
|
326
|
+
httpMetadata?: {
|
|
327
|
+
contentType?: string;
|
|
328
|
+
};
|
|
329
|
+
customMetadata?: Record<string, string>;
|
|
330
|
+
size?: number;
|
|
331
|
+
uploaded?: Date;
|
|
332
|
+
} | null>;
|
|
333
|
+
list?(options?: {
|
|
334
|
+
limit?: number;
|
|
335
|
+
cursor?: string;
|
|
336
|
+
}): Promise<{
|
|
337
|
+
objects: Array<{
|
|
338
|
+
key: string;
|
|
339
|
+
}>;
|
|
340
|
+
truncated: boolean;
|
|
341
|
+
cursor?: string;
|
|
342
|
+
}>;
|
|
343
|
+
}
|
|
344
|
+
declare class R2Storage implements StorageAdapter {
|
|
345
|
+
private bucket;
|
|
346
|
+
constructor(bucket: R2Bucket);
|
|
347
|
+
put(hash: string, content: ArrayBuffer | Uint8Array, metadata?: ArtifactMetadata): Promise<void>;
|
|
348
|
+
get(hash: string): Promise<StoredArtifact | null>;
|
|
349
|
+
delete(hash: string): Promise<boolean>;
|
|
350
|
+
exists(hash: string): Promise<boolean>;
|
|
351
|
+
list(options?: {
|
|
352
|
+
limit?: number;
|
|
353
|
+
cursor?: string;
|
|
354
|
+
}): Promise<string[]>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export { type ArtifactMetadata, CDN, type CDNOptions, CONTENT_TYPES, MemoryStorage, type R2Bucket, R2Storage, type StorageAdapter, type StoredArtifact, type UploadResult, detectContentType };
|