@maravilla-labs/platform 0.1.18 → 0.1.21

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/src/types.ts CHANGED
@@ -263,9 +263,247 @@ export interface DbFindOptions {
263
263
  sort?: any;
264
264
  }
265
265
 
266
+ /**
267
+ * Storage interface for object/file storage operations.
268
+ * Provides S3-compatible API for storing and retrieving files.
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * const platform = getPlatform();
273
+ * const storage = platform.env.STORAGE;
274
+ *
275
+ * // Generate presigned upload URL for direct browser upload
276
+ * const uploadUrl = await storage.generateUploadUrl(
277
+ * 'profile-pics/user123.jpg',
278
+ * 'image/jpeg',
279
+ * { sizeLimit: 5 * 1024 * 1024 } // 5MB limit
280
+ * );
281
+ *
282
+ * // Generate download URL
283
+ * const downloadUrl = await storage.generateDownloadUrl(
284
+ * 'profile-pics/user123.jpg',
285
+ * { expiresIn: 3600 } // 1 hour
286
+ * );
287
+ *
288
+ * // Direct storage operations
289
+ * await storage.put('docs/report.pdf', pdfData, { contentType: 'application/pdf' });
290
+ * const file = await storage.get('docs/report.pdf');
291
+ * ```
292
+ */
293
+ /**
294
+ * Source types accepted by Storage.putStream for streaming uploads.
295
+ */
296
+ export type StoragePutStreamSource =
297
+ | Uint8Array
298
+ | ArrayBuffer
299
+ | string
300
+ | Blob
301
+ | ReadableStream<Uint8Array | ArrayBuffer | string | number[]>
302
+ | Iterable<Uint8Array | ArrayBuffer | string | number[]>
303
+ | AsyncIterable<Uint8Array | ArrayBuffer | string | number[]>;
304
+
305
+ export interface Storage {
306
+ /**
307
+ * Generate a presigned URL for uploading a file directly from the browser.
308
+ *
309
+ * @param key - The storage key/path for the file
310
+ * @param contentType - MIME type of the file
311
+ * @param options - Upload options
312
+ * @param options.sizeLimit - Maximum file size in bytes
313
+ * @returns Promise that resolves to upload URL details
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * const upload = await storage.generateUploadUrl(
318
+ * 'uploads/document.pdf',
319
+ * 'application/pdf',
320
+ * { sizeLimit: 10 * 1024 * 1024 } // 10MB
321
+ * );
322
+ *
323
+ * // Use the URL to upload from browser
324
+ * await fetch(upload.url, {
325
+ * method: upload.method,
326
+ * headers: upload.headers,
327
+ * body: fileData
328
+ * });
329
+ * ```
330
+ */
331
+ generateUploadUrl(key: string, contentType: string, options?: { sizeLimit?: number }): Promise<{
332
+ url: string;
333
+ method: string;
334
+ headers: Record<string, string>;
335
+ expiresIn: number;
336
+ }>;
337
+
338
+ /**
339
+ * Generate a presigned URL for downloading a file.
340
+ *
341
+ * @param key - The storage key/path for the file
342
+ * @param options - Download options
343
+ * @param options.expiresIn - URL expiration time in seconds (default: 3600)
344
+ * @returns Promise that resolves to download URL details
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * const download = await storage.generateDownloadUrl(
349
+ * 'uploads/document.pdf',
350
+ * { expiresIn: 7200 } // 2 hours
351
+ * );
352
+ *
353
+ * // Provide URL to client for download
354
+ * return { downloadUrl: download.url };
355
+ * ```
356
+ */
357
+ generateDownloadUrl(key: string, options?: { expiresIn?: number }): Promise<{
358
+ url: string;
359
+ method: string;
360
+ headers: Record<string, string>;
361
+ expiresIn: number;
362
+ }>;
363
+
364
+ /**
365
+ * Retrieve a file from storage.
366
+ *
367
+ * @param key - The storage key/path for the file
368
+ * @returns Promise that resolves to the file data, or null if not found
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * const imageData = await storage.get('profile-pics/user123.jpg');
373
+ * if (imageData) {
374
+ * // Process the image data
375
+ * return new Response(imageData, {
376
+ * headers: { 'Content-Type': 'image/jpeg' }
377
+ * });
378
+ * }
379
+ * ```
380
+ */
381
+ get(key: string): Promise<Uint8Array | null>;
382
+
383
+ /**
384
+ * Store a file in storage.
385
+ *
386
+ * @param key - The storage key/path for the file
387
+ * @param data - The file data to store
388
+ * @param metadata - Optional metadata for the file
389
+ * @returns Promise that resolves when the operation completes
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * // Store an image with metadata
394
+ * await storage.put(
395
+ * 'profile-pics/user123.jpg',
396
+ * imageData,
397
+ * {
398
+ * contentType: 'image/jpeg',
399
+ * userId: 'user123',
400
+ * uploadedAt: new Date().toISOString()
401
+ * }
402
+ * );
403
+ * ```
404
+ */
405
+ put(key: string, data: Uint8Array | string, metadata?: any): Promise<void>;
406
+
407
+ /**
408
+ * Store a file in storage using streaming/chunked data sources.
409
+ *
410
+ * Accepts a variety of source types (ReadableStream, Blob, ArrayBuffer,
411
+ * Uint8Array, string, or (async) iterables of chunks) and efficiently
412
+ * uploads them without requiring the caller to fully buffer the file
413
+ * in memory first when running in the native runtime. In the remote
414
+ * development client this currently buffers in memory as a fallback.
415
+ *
416
+ * Chunk types inside iterables can be Uint8Array, ArrayBuffer, number[]
417
+ * or string; strings are UTF-8 encoded.
418
+ *
419
+ * @param key - The storage key/path for the file
420
+ * @param source - Streaming or buffered data source
421
+ * @param metadata - Optional metadata for the file
422
+ * @returns Promise that resolves when the operation completes
423
+ *
424
+ * @example
425
+ * ```typescript
426
+ * // Upload a Blob (e.g. from a file input in a web app)
427
+ * await storage.putStream('videos/clip.mp4', fileBlob, { contentType: fileBlob.type });
428
+ *
429
+ * // Upload using an async generator that yields chunks
430
+ * async function *generate() {
431
+ * for await (const piece of someAsyncSource) {
432
+ * yield piece; // Uint8Array | string | ArrayBuffer
433
+ * }
434
+ * }
435
+ * await storage.putStream('logs/large.txt', generate(), { contentType: 'text/plain' });
436
+ * ```
437
+ */
438
+ putStream(
439
+ key: string,
440
+ source: StoragePutStreamSource,
441
+ metadata?: any
442
+ ): Promise<void>;
443
+
444
+ /**
445
+ * Delete a file from storage.
446
+ *
447
+ * @param key - The storage key/path for the file
448
+ * @returns Promise that resolves when the operation completes
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * await storage.delete('profile-pics/old-photo.jpg');
453
+ * ```
454
+ */
455
+ delete(key: string): Promise<void>;
456
+
457
+ /**
458
+ * List files in storage with optional prefix filtering.
459
+ *
460
+ * @param options - Listing options
461
+ * @param options.prefix - Only return keys that start with this prefix
462
+ * @param options.limit - Maximum number of keys to return
463
+ * @returns Promise that resolves to list of file keys and metadata
464
+ *
465
+ * @example
466
+ * ```typescript
467
+ * // List all profile pictures
468
+ * const pics = await storage.list({ prefix: 'profile-pics/' });
469
+ *
470
+ * // List with pagination
471
+ * const files = await storage.list({ prefix: 'docs/', limit: 20 });
472
+ * ```
473
+ */
474
+ list(options?: { prefix?: string; limit?: number }): Promise<Array<{
475
+ key: string;
476
+ size: number;
477
+ lastModified: string;
478
+ metadata?: any;
479
+ }>>;
480
+
481
+ /**
482
+ * Get metadata for a file without retrieving its contents.
483
+ *
484
+ * @param key - The storage key/path for the file
485
+ * @returns Promise that resolves to file metadata, or null if not found
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * const meta = await storage.getMetadata('uploads/document.pdf');
490
+ * if (meta) {
491
+ * console.log(`File size: ${meta.size} bytes`);
492
+ * console.log(`Last modified: ${meta.lastModified}`);
493
+ * }
494
+ * ```
495
+ */
496
+ getMetadata(key: string): Promise<{
497
+ size: number;
498
+ contentType?: string;
499
+ lastModified: string;
500
+ metadata?: any;
501
+ } | null>;
502
+ }
503
+
266
504
  /**
267
505
  * Platform environment containing all available services.
268
- * This is the main interface for accessing KV storage and database operations.
506
+ * This is the main interface for accessing KV storage, database, and object storage operations.
269
507
  */
270
508
  export interface PlatformEnv {
271
509
  /**
@@ -280,6 +518,8 @@ export interface PlatformEnv {
280
518
  KV: Record<string, KvNamespace>;
281
519
  /** Database interface for document operations */
282
520
  DB: Database;
521
+ /** Object/file storage interface */
522
+ STORAGE: Storage;
283
523
  }
284
524
 
285
525
  /**
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "target": "ES2022",
4
4
  "module": "ES2022",
5
- "lib": ["ES2022"],
5
+ "lib": ["ES2022", "DOM"],
6
6
  "moduleResolution": "node",
7
7
  "rootDir": "./src",
8
8
  "outDir": "./dist",