krisspy-sdk 0.1.0 → 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/dist/index.d.mts CHANGED
@@ -300,6 +300,195 @@ declare class KrisspyAuth {
300
300
  }
301
301
  type AuthChangeEvent = 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED';
302
302
 
303
+ /**
304
+ * Krisspy Storage - File storage client
305
+ *
306
+ * Provides a simple API for uploading, downloading, and managing files
307
+ * in Krisspy Cloud Storage (Azure Blob Storage backend).
308
+ */
309
+
310
+ interface StorageUploadResponse {
311
+ data: {
312
+ path: string;
313
+ url: string;
314
+ bucket: string;
315
+ contentType: string;
316
+ size: number;
317
+ } | null;
318
+ error: KrisspyError | null;
319
+ }
320
+ interface StorageDownloadResponse {
321
+ data: {
322
+ url: string;
323
+ path: string;
324
+ bucket: string;
325
+ } | null;
326
+ error: KrisspyError | null;
327
+ }
328
+ interface StorageListResponse {
329
+ data: FileObject[] | null;
330
+ error: KrisspyError | null;
331
+ }
332
+ interface StorageDeleteResponse {
333
+ data: {
334
+ success: boolean;
335
+ } | null;
336
+ error: KrisspyError | null;
337
+ }
338
+ interface StorageUrlResponse {
339
+ data: {
340
+ signedUrl: string;
341
+ path: string;
342
+ expiresIn: number;
343
+ } | null;
344
+ error: KrisspyError | null;
345
+ }
346
+ /**
347
+ * Storage bucket interface for file operations
348
+ */
349
+ declare class StorageBucket {
350
+ private http;
351
+ private backendId;
352
+ private bucketName;
353
+ constructor(http: HttpClient, backendId: string, bucketName: string);
354
+ /**
355
+ * Upload a file to the bucket
356
+ *
357
+ * @param path - Path/filename for the file (e.g., "images/profile.jpg")
358
+ * @param file - File data as Blob, File, ArrayBuffer, or base64 string
359
+ * @param options - Upload options
360
+ *
361
+ * @example
362
+ * // Upload from file input
363
+ * const file = event.target.files[0]
364
+ * const { data, error } = await krisspy.storage
365
+ * .from('avatars')
366
+ * .upload('profile.jpg', file)
367
+ *
368
+ * // Upload base64 image
369
+ * const { data, error } = await krisspy.storage
370
+ * .from('images')
371
+ * .upload('photo.png', base64Data, { contentType: 'image/png' })
372
+ */
373
+ upload(path: string, file: Blob | File | ArrayBuffer | string, options?: FileUploadOptions): Promise<StorageUploadResponse>;
374
+ /**
375
+ * Get the public URL of a file
376
+ *
377
+ * @param path - Path to the file
378
+ *
379
+ * @example
380
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
381
+ * console.log(data.publicUrl) // https://...
382
+ */
383
+ getPublicUrl(path: string): {
384
+ data: {
385
+ publicUrl: string;
386
+ };
387
+ };
388
+ /**
389
+ * Download a file (get download URL)
390
+ *
391
+ * @param path - Path to the file
392
+ *
393
+ * @example
394
+ * const { data, error } = await krisspy.storage
395
+ * .from('documents')
396
+ * .download('report.pdf')
397
+ */
398
+ download(path: string): Promise<StorageDownloadResponse>;
399
+ /**
400
+ * Delete a file from storage
401
+ *
402
+ * @param paths - Path(s) to delete
403
+ *
404
+ * @example
405
+ * // Delete single file
406
+ * const { error } = await krisspy.storage.from('avatars').remove(['profile.jpg'])
407
+ *
408
+ * // Delete multiple files
409
+ * const { error } = await krisspy.storage.from('images').remove(['a.jpg', 'b.jpg'])
410
+ */
411
+ remove(paths: string[]): Promise<StorageDeleteResponse>;
412
+ /**
413
+ * List files in the bucket
414
+ *
415
+ * @param prefix - Filter files by path prefix
416
+ * @param options - List options
417
+ *
418
+ * @example
419
+ * // List all files
420
+ * const { data, error } = await krisspy.storage.from('uploads').list()
421
+ *
422
+ * // List files in a folder
423
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
424
+ */
425
+ list(prefix?: string, options?: {
426
+ limit?: number;
427
+ offset?: number;
428
+ }): Promise<StorageListResponse>;
429
+ /**
430
+ * Create a signed URL for temporary access
431
+ *
432
+ * @param path - Path to the file
433
+ * @param expiresIn - Expiration time in seconds (default: 3600)
434
+ *
435
+ * @example
436
+ * const { data, error } = await krisspy.storage
437
+ * .from('private')
438
+ * .createSignedUrl('document.pdf', 3600)
439
+ */
440
+ createSignedUrl(path: string, expiresIn?: number): Promise<StorageUrlResponse>;
441
+ private blobToBase64;
442
+ private arrayBufferToBase64;
443
+ private detectMimeType;
444
+ }
445
+ /**
446
+ * Krisspy Storage client
447
+ *
448
+ * @example
449
+ * // Upload a file
450
+ * const { data, error } = await krisspy.storage
451
+ * .from('avatars')
452
+ * .upload('profile.jpg', file)
453
+ *
454
+ * // Get public URL
455
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
456
+ *
457
+ * // Download
458
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
459
+ *
460
+ * // List files
461
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
462
+ *
463
+ * // Delete files
464
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
465
+ */
466
+ declare class KrisspyStorage {
467
+ private http;
468
+ private backendId;
469
+ constructor(http: HttpClient, backendId: string);
470
+ /**
471
+ * Select a storage bucket
472
+ *
473
+ * @param bucket - Bucket name (e.g., 'avatars', 'documents', 'media')
474
+ * @returns StorageBucket instance for file operations
475
+ *
476
+ * @example
477
+ * const bucket = krisspy.storage.from('avatars')
478
+ * await bucket.upload('profile.jpg', file)
479
+ */
480
+ from(bucket: string): StorageBucket;
481
+ /**
482
+ * List all buckets (currently returns predefined buckets)
483
+ */
484
+ listBuckets(): Promise<{
485
+ data: {
486
+ name: string;
487
+ }[] | null;
488
+ error: KrisspyError | null;
489
+ }>;
490
+ }
491
+
303
492
  /**
304
493
  * Query Builder - Supabase-style fluent API for database queries
305
494
  */
@@ -448,6 +637,7 @@ declare class KrisspyClient {
448
637
  private http;
449
638
  private backendId;
450
639
  private _auth;
640
+ private _storage;
451
641
  private useRLS;
452
642
  constructor(options: KrisspyClientOptions);
453
643
  /**
@@ -473,6 +663,28 @@ declare class KrisspyClient {
473
663
  * await krisspy.auth.signOut()
474
664
  */
475
665
  get auth(): KrisspyAuth;
666
+ /**
667
+ * Storage module for file uploads and downloads
668
+ *
669
+ * @example
670
+ * // Upload a file
671
+ * const { data, error } = await krisspy.storage
672
+ * .from('avatars')
673
+ * .upload('profile.jpg', file)
674
+ *
675
+ * // Get public URL
676
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
677
+ *
678
+ * // Download
679
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
680
+ *
681
+ * // List files
682
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
683
+ *
684
+ * // Delete files
685
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
686
+ */
687
+ get storage(): KrisspyStorage;
476
688
  /**
477
689
  * Create a query builder for a table
478
690
  *
@@ -557,7 +769,7 @@ declare class KrisspyClient {
557
769
  /**
558
770
  * @krisspy/sdk - Krisspy Cloud SDK
559
771
  *
560
- * Database, Auth, and Functions for your apps.
772
+ * Database, Auth, Storage, and Functions for your apps.
561
773
  * A simpler alternative to Supabase.
562
774
  *
563
775
  * @example
@@ -583,6 +795,10 @@ declare class KrisspyClient {
583
795
  * // Insert
584
796
  * await krisspy.from('products').insert({ name: 'iPhone', price: 999 })
585
797
  *
798
+ * // Storage
799
+ * await krisspy.storage.from('avatars').upload('profile.jpg', file)
800
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
801
+ *
586
802
  * // Functions
587
803
  * await krisspy.functions.invoke('hello', { body: { name: 'World' } })
588
804
  */
@@ -602,4 +818,4 @@ declare class KrisspyClient {
602
818
  */
603
819
  declare function createClient(options: KrisspyClientOptions): KrisspyClient;
604
820
 
605
- export { type AuthChangeEvent, type AuthResponse, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, type MutationResponse, type OAuthProvider, type OrderBy, QueryBuilder, type QueryOptions, type QueryResponse, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, type User, createClient };
821
+ export { type AuthChangeEvent, type AuthResponse, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, QueryBuilder, type QueryOptions, type QueryResponse, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type User, createClient };
package/dist/index.d.ts CHANGED
@@ -300,6 +300,195 @@ declare class KrisspyAuth {
300
300
  }
301
301
  type AuthChangeEvent = 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED';
302
302
 
303
+ /**
304
+ * Krisspy Storage - File storage client
305
+ *
306
+ * Provides a simple API for uploading, downloading, and managing files
307
+ * in Krisspy Cloud Storage (Azure Blob Storage backend).
308
+ */
309
+
310
+ interface StorageUploadResponse {
311
+ data: {
312
+ path: string;
313
+ url: string;
314
+ bucket: string;
315
+ contentType: string;
316
+ size: number;
317
+ } | null;
318
+ error: KrisspyError | null;
319
+ }
320
+ interface StorageDownloadResponse {
321
+ data: {
322
+ url: string;
323
+ path: string;
324
+ bucket: string;
325
+ } | null;
326
+ error: KrisspyError | null;
327
+ }
328
+ interface StorageListResponse {
329
+ data: FileObject[] | null;
330
+ error: KrisspyError | null;
331
+ }
332
+ interface StorageDeleteResponse {
333
+ data: {
334
+ success: boolean;
335
+ } | null;
336
+ error: KrisspyError | null;
337
+ }
338
+ interface StorageUrlResponse {
339
+ data: {
340
+ signedUrl: string;
341
+ path: string;
342
+ expiresIn: number;
343
+ } | null;
344
+ error: KrisspyError | null;
345
+ }
346
+ /**
347
+ * Storage bucket interface for file operations
348
+ */
349
+ declare class StorageBucket {
350
+ private http;
351
+ private backendId;
352
+ private bucketName;
353
+ constructor(http: HttpClient, backendId: string, bucketName: string);
354
+ /**
355
+ * Upload a file to the bucket
356
+ *
357
+ * @param path - Path/filename for the file (e.g., "images/profile.jpg")
358
+ * @param file - File data as Blob, File, ArrayBuffer, or base64 string
359
+ * @param options - Upload options
360
+ *
361
+ * @example
362
+ * // Upload from file input
363
+ * const file = event.target.files[0]
364
+ * const { data, error } = await krisspy.storage
365
+ * .from('avatars')
366
+ * .upload('profile.jpg', file)
367
+ *
368
+ * // Upload base64 image
369
+ * const { data, error } = await krisspy.storage
370
+ * .from('images')
371
+ * .upload('photo.png', base64Data, { contentType: 'image/png' })
372
+ */
373
+ upload(path: string, file: Blob | File | ArrayBuffer | string, options?: FileUploadOptions): Promise<StorageUploadResponse>;
374
+ /**
375
+ * Get the public URL of a file
376
+ *
377
+ * @param path - Path to the file
378
+ *
379
+ * @example
380
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
381
+ * console.log(data.publicUrl) // https://...
382
+ */
383
+ getPublicUrl(path: string): {
384
+ data: {
385
+ publicUrl: string;
386
+ };
387
+ };
388
+ /**
389
+ * Download a file (get download URL)
390
+ *
391
+ * @param path - Path to the file
392
+ *
393
+ * @example
394
+ * const { data, error } = await krisspy.storage
395
+ * .from('documents')
396
+ * .download('report.pdf')
397
+ */
398
+ download(path: string): Promise<StorageDownloadResponse>;
399
+ /**
400
+ * Delete a file from storage
401
+ *
402
+ * @param paths - Path(s) to delete
403
+ *
404
+ * @example
405
+ * // Delete single file
406
+ * const { error } = await krisspy.storage.from('avatars').remove(['profile.jpg'])
407
+ *
408
+ * // Delete multiple files
409
+ * const { error } = await krisspy.storage.from('images').remove(['a.jpg', 'b.jpg'])
410
+ */
411
+ remove(paths: string[]): Promise<StorageDeleteResponse>;
412
+ /**
413
+ * List files in the bucket
414
+ *
415
+ * @param prefix - Filter files by path prefix
416
+ * @param options - List options
417
+ *
418
+ * @example
419
+ * // List all files
420
+ * const { data, error } = await krisspy.storage.from('uploads').list()
421
+ *
422
+ * // List files in a folder
423
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
424
+ */
425
+ list(prefix?: string, options?: {
426
+ limit?: number;
427
+ offset?: number;
428
+ }): Promise<StorageListResponse>;
429
+ /**
430
+ * Create a signed URL for temporary access
431
+ *
432
+ * @param path - Path to the file
433
+ * @param expiresIn - Expiration time in seconds (default: 3600)
434
+ *
435
+ * @example
436
+ * const { data, error } = await krisspy.storage
437
+ * .from('private')
438
+ * .createSignedUrl('document.pdf', 3600)
439
+ */
440
+ createSignedUrl(path: string, expiresIn?: number): Promise<StorageUrlResponse>;
441
+ private blobToBase64;
442
+ private arrayBufferToBase64;
443
+ private detectMimeType;
444
+ }
445
+ /**
446
+ * Krisspy Storage client
447
+ *
448
+ * @example
449
+ * // Upload a file
450
+ * const { data, error } = await krisspy.storage
451
+ * .from('avatars')
452
+ * .upload('profile.jpg', file)
453
+ *
454
+ * // Get public URL
455
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
456
+ *
457
+ * // Download
458
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
459
+ *
460
+ * // List files
461
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
462
+ *
463
+ * // Delete files
464
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
465
+ */
466
+ declare class KrisspyStorage {
467
+ private http;
468
+ private backendId;
469
+ constructor(http: HttpClient, backendId: string);
470
+ /**
471
+ * Select a storage bucket
472
+ *
473
+ * @param bucket - Bucket name (e.g., 'avatars', 'documents', 'media')
474
+ * @returns StorageBucket instance for file operations
475
+ *
476
+ * @example
477
+ * const bucket = krisspy.storage.from('avatars')
478
+ * await bucket.upload('profile.jpg', file)
479
+ */
480
+ from(bucket: string): StorageBucket;
481
+ /**
482
+ * List all buckets (currently returns predefined buckets)
483
+ */
484
+ listBuckets(): Promise<{
485
+ data: {
486
+ name: string;
487
+ }[] | null;
488
+ error: KrisspyError | null;
489
+ }>;
490
+ }
491
+
303
492
  /**
304
493
  * Query Builder - Supabase-style fluent API for database queries
305
494
  */
@@ -448,6 +637,7 @@ declare class KrisspyClient {
448
637
  private http;
449
638
  private backendId;
450
639
  private _auth;
640
+ private _storage;
451
641
  private useRLS;
452
642
  constructor(options: KrisspyClientOptions);
453
643
  /**
@@ -473,6 +663,28 @@ declare class KrisspyClient {
473
663
  * await krisspy.auth.signOut()
474
664
  */
475
665
  get auth(): KrisspyAuth;
666
+ /**
667
+ * Storage module for file uploads and downloads
668
+ *
669
+ * @example
670
+ * // Upload a file
671
+ * const { data, error } = await krisspy.storage
672
+ * .from('avatars')
673
+ * .upload('profile.jpg', file)
674
+ *
675
+ * // Get public URL
676
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
677
+ *
678
+ * // Download
679
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
680
+ *
681
+ * // List files
682
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
683
+ *
684
+ * // Delete files
685
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
686
+ */
687
+ get storage(): KrisspyStorage;
476
688
  /**
477
689
  * Create a query builder for a table
478
690
  *
@@ -557,7 +769,7 @@ declare class KrisspyClient {
557
769
  /**
558
770
  * @krisspy/sdk - Krisspy Cloud SDK
559
771
  *
560
- * Database, Auth, and Functions for your apps.
772
+ * Database, Auth, Storage, and Functions for your apps.
561
773
  * A simpler alternative to Supabase.
562
774
  *
563
775
  * @example
@@ -583,6 +795,10 @@ declare class KrisspyClient {
583
795
  * // Insert
584
796
  * await krisspy.from('products').insert({ name: 'iPhone', price: 999 })
585
797
  *
798
+ * // Storage
799
+ * await krisspy.storage.from('avatars').upload('profile.jpg', file)
800
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
801
+ *
586
802
  * // Functions
587
803
  * await krisspy.functions.invoke('hello', { body: { name: 'World' } })
588
804
  */
@@ -602,4 +818,4 @@ declare class KrisspyClient {
602
818
  */
603
819
  declare function createClient(options: KrisspyClientOptions): KrisspyClient;
604
820
 
605
- export { type AuthChangeEvent, type AuthResponse, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, type MutationResponse, type OAuthProvider, type OrderBy, QueryBuilder, type QueryOptions, type QueryResponse, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, type User, createClient };
821
+ export { type AuthChangeEvent, type AuthResponse, type FileObject, type FileUploadOptions, type Filter, type FilterOperator, type FunctionInvokeOptions, type FunctionResponse, HttpClient, KrisspyAuth, KrisspyClient, type KrisspyClientOptions, type KrisspyError, KrisspyStorage, type MutationResponse, type OAuthProvider, type OrderBy, QueryBuilder, type QueryOptions, type QueryResponse, type Session, type SignInCredentials, type SignUpCredentials, type SingleResponse, StorageBucket, type User, createClient };
package/dist/index.js CHANGED
@@ -23,7 +23,9 @@ __export(index_exports, {
23
23
  HttpClient: () => HttpClient,
24
24
  KrisspyAuth: () => KrisspyAuth,
25
25
  KrisspyClient: () => KrisspyClient,
26
+ KrisspyStorage: () => KrisspyStorage,
26
27
  QueryBuilder: () => QueryBuilder,
28
+ StorageBucket: () => StorageBucket,
27
29
  createClient: () => createClient
28
30
  });
29
31
  module.exports = __toCommonJS(index_exports);
@@ -478,6 +480,303 @@ var KrisspyAuth = class {
478
480
  }
479
481
  };
480
482
 
483
+ // src/storage.ts
484
+ var StorageBucket = class {
485
+ constructor(http, backendId, bucketName) {
486
+ this.http = http;
487
+ this.backendId = backendId;
488
+ this.bucketName = bucketName;
489
+ }
490
+ /**
491
+ * Upload a file to the bucket
492
+ *
493
+ * @param path - Path/filename for the file (e.g., "images/profile.jpg")
494
+ * @param file - File data as Blob, File, ArrayBuffer, or base64 string
495
+ * @param options - Upload options
496
+ *
497
+ * @example
498
+ * // Upload from file input
499
+ * const file = event.target.files[0]
500
+ * const { data, error } = await krisspy.storage
501
+ * .from('avatars')
502
+ * .upload('profile.jpg', file)
503
+ *
504
+ * // Upload base64 image
505
+ * const { data, error } = await krisspy.storage
506
+ * .from('images')
507
+ * .upload('photo.png', base64Data, { contentType: 'image/png' })
508
+ */
509
+ async upload(path, file, options) {
510
+ try {
511
+ let base64Data;
512
+ let contentType = options?.contentType;
513
+ if (typeof file === "string") {
514
+ base64Data = file;
515
+ } else if (file instanceof Blob || file instanceof File) {
516
+ base64Data = await this.blobToBase64(file);
517
+ if (!contentType && file instanceof File) {
518
+ contentType = file.type;
519
+ }
520
+ } else if (file instanceof ArrayBuffer) {
521
+ base64Data = this.arrayBufferToBase64(file);
522
+ } else {
523
+ throw new Error("Invalid file type. Expected Blob, File, ArrayBuffer, or base64 string.");
524
+ }
525
+ if (!contentType) {
526
+ contentType = this.detectMimeType(path);
527
+ }
528
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/upload`;
529
+ const response = await this.http.post(apiPath, {
530
+ bucket: this.bucketName,
531
+ path,
532
+ data: base64Data,
533
+ contentType
534
+ });
535
+ if (response.error) {
536
+ return { data: null, error: response.error };
537
+ }
538
+ return {
539
+ data: {
540
+ path: response.data?.path || path,
541
+ url: response.data?.url || "",
542
+ bucket: response.data?.bucket || this.bucketName,
543
+ contentType: response.data?.contentType || contentType || "application/octet-stream",
544
+ size: response.data?.size || 0
545
+ },
546
+ error: null
547
+ };
548
+ } catch (error) {
549
+ return {
550
+ data: null,
551
+ error: {
552
+ message: error.message || "Upload failed",
553
+ code: "STORAGE_UPLOAD_ERROR"
554
+ }
555
+ };
556
+ }
557
+ }
558
+ /**
559
+ * Get the public URL of a file
560
+ *
561
+ * @param path - Path to the file
562
+ *
563
+ * @example
564
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
565
+ * console.log(data.publicUrl) // https://...
566
+ */
567
+ getPublicUrl(path) {
568
+ const baseUrl = "https://krisspy.blob.core.windows.net/public";
569
+ const storagePath = `backends/${this.backendId}/${this.bucketName}/${path}`;
570
+ const publicUrl = `${baseUrl}/${storagePath}`;
571
+ return {
572
+ data: { publicUrl }
573
+ };
574
+ }
575
+ /**
576
+ * Download a file (get download URL)
577
+ *
578
+ * @param path - Path to the file
579
+ *
580
+ * @example
581
+ * const { data, error } = await krisspy.storage
582
+ * .from('documents')
583
+ * .download('report.pdf')
584
+ */
585
+ async download(path) {
586
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/download`;
587
+ const response = await this.http.post(apiPath, {
588
+ bucket: this.bucketName,
589
+ path
590
+ });
591
+ if (response.error) {
592
+ return { data: null, error: response.error };
593
+ }
594
+ return {
595
+ data: {
596
+ url: response.data?.url || "",
597
+ path: response.data?.path || path,
598
+ bucket: response.data?.bucket || this.bucketName
599
+ },
600
+ error: null
601
+ };
602
+ }
603
+ /**
604
+ * Delete a file from storage
605
+ *
606
+ * @param paths - Path(s) to delete
607
+ *
608
+ * @example
609
+ * // Delete single file
610
+ * const { error } = await krisspy.storage.from('avatars').remove(['profile.jpg'])
611
+ *
612
+ * // Delete multiple files
613
+ * const { error } = await krisspy.storage.from('images').remove(['a.jpg', 'b.jpg'])
614
+ */
615
+ async remove(paths) {
616
+ const results = [];
617
+ for (const path of paths) {
618
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/delete`;
619
+ const response = await this.http.post(apiPath, {
620
+ bucket: this.bucketName,
621
+ path
622
+ });
623
+ if (response.error) {
624
+ return { data: null, error: response.error };
625
+ }
626
+ results.push({ success: response.data?.success || false });
627
+ }
628
+ return { data: { success: true }, error: null };
629
+ }
630
+ /**
631
+ * List files in the bucket
632
+ *
633
+ * @param prefix - Filter files by path prefix
634
+ * @param options - List options
635
+ *
636
+ * @example
637
+ * // List all files
638
+ * const { data, error } = await krisspy.storage.from('uploads').list()
639
+ *
640
+ * // List files in a folder
641
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
642
+ */
643
+ async list(prefix, options) {
644
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/list`;
645
+ const response = await this.http.post(apiPath, {
646
+ bucket: this.bucketName,
647
+ prefix,
648
+ limit: options?.limit || 100
649
+ });
650
+ if (response.error) {
651
+ return { data: null, error: response.error };
652
+ }
653
+ return { data: response.data?.files || [], error: null };
654
+ }
655
+ /**
656
+ * Create a signed URL for temporary access
657
+ *
658
+ * @param path - Path to the file
659
+ * @param expiresIn - Expiration time in seconds (default: 3600)
660
+ *
661
+ * @example
662
+ * const { data, error } = await krisspy.storage
663
+ * .from('private')
664
+ * .createSignedUrl('document.pdf', 3600)
665
+ */
666
+ async createSignedUrl(path, expiresIn = 3600) {
667
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/signed-url`;
668
+ const response = await this.http.post(apiPath, {
669
+ bucket: this.bucketName,
670
+ path,
671
+ expiresIn
672
+ });
673
+ if (response.error) {
674
+ return { data: null, error: response.error };
675
+ }
676
+ return {
677
+ data: {
678
+ signedUrl: response.data?.url || "",
679
+ path: response.data?.path || path,
680
+ expiresIn: response.data?.expiresIn || expiresIn
681
+ },
682
+ error: null
683
+ };
684
+ }
685
+ // Helper: Convert Blob to base64
686
+ blobToBase64(blob) {
687
+ return new Promise((resolve, reject) => {
688
+ const reader = new FileReader();
689
+ reader.onloadend = () => {
690
+ const result = reader.result;
691
+ const base64 = result.includes(",") ? result.split(",")[1] : result;
692
+ resolve(base64);
693
+ };
694
+ reader.onerror = reject;
695
+ reader.readAsDataURL(blob);
696
+ });
697
+ }
698
+ // Helper: Convert ArrayBuffer to base64
699
+ arrayBufferToBase64(buffer) {
700
+ let binary = "";
701
+ const bytes = new Uint8Array(buffer);
702
+ for (let i = 0; i < bytes.length; i++) {
703
+ binary += String.fromCharCode(bytes[i]);
704
+ }
705
+ return btoa(binary);
706
+ }
707
+ // Helper: Detect MIME type from file extension
708
+ detectMimeType(path) {
709
+ const ext = path.split(".").pop()?.toLowerCase() || "";
710
+ const mimeTypes = {
711
+ // Images
712
+ jpg: "image/jpeg",
713
+ jpeg: "image/jpeg",
714
+ png: "image/png",
715
+ gif: "image/gif",
716
+ webp: "image/webp",
717
+ svg: "image/svg+xml",
718
+ ico: "image/x-icon",
719
+ // Documents
720
+ pdf: "application/pdf",
721
+ doc: "application/msword",
722
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
723
+ xls: "application/vnd.ms-excel",
724
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
725
+ // Text
726
+ txt: "text/plain",
727
+ csv: "text/csv",
728
+ json: "application/json",
729
+ xml: "application/xml",
730
+ html: "text/html",
731
+ css: "text/css",
732
+ js: "application/javascript",
733
+ // Audio/Video
734
+ mp3: "audio/mpeg",
735
+ wav: "audio/wav",
736
+ mp4: "video/mp4",
737
+ webm: "video/webm",
738
+ // Archives
739
+ zip: "application/zip",
740
+ tar: "application/x-tar",
741
+ gz: "application/gzip"
742
+ };
743
+ return mimeTypes[ext] || "application/octet-stream";
744
+ }
745
+ };
746
+ var KrisspyStorage = class {
747
+ constructor(http, backendId) {
748
+ this.http = http;
749
+ this.backendId = backendId;
750
+ }
751
+ /**
752
+ * Select a storage bucket
753
+ *
754
+ * @param bucket - Bucket name (e.g., 'avatars', 'documents', 'media')
755
+ * @returns StorageBucket instance for file operations
756
+ *
757
+ * @example
758
+ * const bucket = krisspy.storage.from('avatars')
759
+ * await bucket.upload('profile.jpg', file)
760
+ */
761
+ from(bucket) {
762
+ return new StorageBucket(this.http, this.backendId, bucket);
763
+ }
764
+ /**
765
+ * List all buckets (currently returns predefined buckets)
766
+ */
767
+ async listBuckets() {
768
+ return {
769
+ data: [
770
+ { name: "media" },
771
+ { name: "avatars" },
772
+ { name: "documents" },
773
+ { name: "uploads" }
774
+ ],
775
+ error: null
776
+ };
777
+ }
778
+ };
779
+
481
780
  // src/query-builder.ts
482
781
  var QueryBuilder = class {
483
782
  constructor(http, backendId, tableName, useRLS = true) {
@@ -769,6 +1068,7 @@ var KrisspyClient = class {
769
1068
  debug: options.debug
770
1069
  });
771
1070
  this._auth = new KrisspyAuth(this.http, this.backendId);
1071
+ this._storage = new KrisspyStorage(this.http, this.backendId);
772
1072
  }
773
1073
  /**
774
1074
  * Auth module for user authentication
@@ -795,6 +1095,30 @@ var KrisspyClient = class {
795
1095
  get auth() {
796
1096
  return this._auth;
797
1097
  }
1098
+ /**
1099
+ * Storage module for file uploads and downloads
1100
+ *
1101
+ * @example
1102
+ * // Upload a file
1103
+ * const { data, error } = await krisspy.storage
1104
+ * .from('avatars')
1105
+ * .upload('profile.jpg', file)
1106
+ *
1107
+ * // Get public URL
1108
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
1109
+ *
1110
+ * // Download
1111
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
1112
+ *
1113
+ * // List files
1114
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
1115
+ *
1116
+ * // Delete files
1117
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
1118
+ */
1119
+ get storage() {
1120
+ return this._storage;
1121
+ }
798
1122
  /**
799
1123
  * Create a query builder for a table
800
1124
  *
@@ -916,6 +1240,8 @@ function createClient(options) {
916
1240
  HttpClient,
917
1241
  KrisspyAuth,
918
1242
  KrisspyClient,
1243
+ KrisspyStorage,
919
1244
  QueryBuilder,
1245
+ StorageBucket,
920
1246
  createClient
921
1247
  });
package/dist/index.mjs CHANGED
@@ -448,6 +448,303 @@ var KrisspyAuth = class {
448
448
  }
449
449
  };
450
450
 
451
+ // src/storage.ts
452
+ var StorageBucket = class {
453
+ constructor(http, backendId, bucketName) {
454
+ this.http = http;
455
+ this.backendId = backendId;
456
+ this.bucketName = bucketName;
457
+ }
458
+ /**
459
+ * Upload a file to the bucket
460
+ *
461
+ * @param path - Path/filename for the file (e.g., "images/profile.jpg")
462
+ * @param file - File data as Blob, File, ArrayBuffer, or base64 string
463
+ * @param options - Upload options
464
+ *
465
+ * @example
466
+ * // Upload from file input
467
+ * const file = event.target.files[0]
468
+ * const { data, error } = await krisspy.storage
469
+ * .from('avatars')
470
+ * .upload('profile.jpg', file)
471
+ *
472
+ * // Upload base64 image
473
+ * const { data, error } = await krisspy.storage
474
+ * .from('images')
475
+ * .upload('photo.png', base64Data, { contentType: 'image/png' })
476
+ */
477
+ async upload(path, file, options) {
478
+ try {
479
+ let base64Data;
480
+ let contentType = options?.contentType;
481
+ if (typeof file === "string") {
482
+ base64Data = file;
483
+ } else if (file instanceof Blob || file instanceof File) {
484
+ base64Data = await this.blobToBase64(file);
485
+ if (!contentType && file instanceof File) {
486
+ contentType = file.type;
487
+ }
488
+ } else if (file instanceof ArrayBuffer) {
489
+ base64Data = this.arrayBufferToBase64(file);
490
+ } else {
491
+ throw new Error("Invalid file type. Expected Blob, File, ArrayBuffer, or base64 string.");
492
+ }
493
+ if (!contentType) {
494
+ contentType = this.detectMimeType(path);
495
+ }
496
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/upload`;
497
+ const response = await this.http.post(apiPath, {
498
+ bucket: this.bucketName,
499
+ path,
500
+ data: base64Data,
501
+ contentType
502
+ });
503
+ if (response.error) {
504
+ return { data: null, error: response.error };
505
+ }
506
+ return {
507
+ data: {
508
+ path: response.data?.path || path,
509
+ url: response.data?.url || "",
510
+ bucket: response.data?.bucket || this.bucketName,
511
+ contentType: response.data?.contentType || contentType || "application/octet-stream",
512
+ size: response.data?.size || 0
513
+ },
514
+ error: null
515
+ };
516
+ } catch (error) {
517
+ return {
518
+ data: null,
519
+ error: {
520
+ message: error.message || "Upload failed",
521
+ code: "STORAGE_UPLOAD_ERROR"
522
+ }
523
+ };
524
+ }
525
+ }
526
+ /**
527
+ * Get the public URL of a file
528
+ *
529
+ * @param path - Path to the file
530
+ *
531
+ * @example
532
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
533
+ * console.log(data.publicUrl) // https://...
534
+ */
535
+ getPublicUrl(path) {
536
+ const baseUrl = "https://krisspy.blob.core.windows.net/public";
537
+ const storagePath = `backends/${this.backendId}/${this.bucketName}/${path}`;
538
+ const publicUrl = `${baseUrl}/${storagePath}`;
539
+ return {
540
+ data: { publicUrl }
541
+ };
542
+ }
543
+ /**
544
+ * Download a file (get download URL)
545
+ *
546
+ * @param path - Path to the file
547
+ *
548
+ * @example
549
+ * const { data, error } = await krisspy.storage
550
+ * .from('documents')
551
+ * .download('report.pdf')
552
+ */
553
+ async download(path) {
554
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/download`;
555
+ const response = await this.http.post(apiPath, {
556
+ bucket: this.bucketName,
557
+ path
558
+ });
559
+ if (response.error) {
560
+ return { data: null, error: response.error };
561
+ }
562
+ return {
563
+ data: {
564
+ url: response.data?.url || "",
565
+ path: response.data?.path || path,
566
+ bucket: response.data?.bucket || this.bucketName
567
+ },
568
+ error: null
569
+ };
570
+ }
571
+ /**
572
+ * Delete a file from storage
573
+ *
574
+ * @param paths - Path(s) to delete
575
+ *
576
+ * @example
577
+ * // Delete single file
578
+ * const { error } = await krisspy.storage.from('avatars').remove(['profile.jpg'])
579
+ *
580
+ * // Delete multiple files
581
+ * const { error } = await krisspy.storage.from('images').remove(['a.jpg', 'b.jpg'])
582
+ */
583
+ async remove(paths) {
584
+ const results = [];
585
+ for (const path of paths) {
586
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/delete`;
587
+ const response = await this.http.post(apiPath, {
588
+ bucket: this.bucketName,
589
+ path
590
+ });
591
+ if (response.error) {
592
+ return { data: null, error: response.error };
593
+ }
594
+ results.push({ success: response.data?.success || false });
595
+ }
596
+ return { data: { success: true }, error: null };
597
+ }
598
+ /**
599
+ * List files in the bucket
600
+ *
601
+ * @param prefix - Filter files by path prefix
602
+ * @param options - List options
603
+ *
604
+ * @example
605
+ * // List all files
606
+ * const { data, error } = await krisspy.storage.from('uploads').list()
607
+ *
608
+ * // List files in a folder
609
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
610
+ */
611
+ async list(prefix, options) {
612
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/list`;
613
+ const response = await this.http.post(apiPath, {
614
+ bucket: this.bucketName,
615
+ prefix,
616
+ limit: options?.limit || 100
617
+ });
618
+ if (response.error) {
619
+ return { data: null, error: response.error };
620
+ }
621
+ return { data: response.data?.files || [], error: null };
622
+ }
623
+ /**
624
+ * Create a signed URL for temporary access
625
+ *
626
+ * @param path - Path to the file
627
+ * @param expiresIn - Expiration time in seconds (default: 3600)
628
+ *
629
+ * @example
630
+ * const { data, error } = await krisspy.storage
631
+ * .from('private')
632
+ * .createSignedUrl('document.pdf', 3600)
633
+ */
634
+ async createSignedUrl(path, expiresIn = 3600) {
635
+ const apiPath = `/api/v1/cloud-backends/${this.backendId}/storage/signed-url`;
636
+ const response = await this.http.post(apiPath, {
637
+ bucket: this.bucketName,
638
+ path,
639
+ expiresIn
640
+ });
641
+ if (response.error) {
642
+ return { data: null, error: response.error };
643
+ }
644
+ return {
645
+ data: {
646
+ signedUrl: response.data?.url || "",
647
+ path: response.data?.path || path,
648
+ expiresIn: response.data?.expiresIn || expiresIn
649
+ },
650
+ error: null
651
+ };
652
+ }
653
+ // Helper: Convert Blob to base64
654
+ blobToBase64(blob) {
655
+ return new Promise((resolve, reject) => {
656
+ const reader = new FileReader();
657
+ reader.onloadend = () => {
658
+ const result = reader.result;
659
+ const base64 = result.includes(",") ? result.split(",")[1] : result;
660
+ resolve(base64);
661
+ };
662
+ reader.onerror = reject;
663
+ reader.readAsDataURL(blob);
664
+ });
665
+ }
666
+ // Helper: Convert ArrayBuffer to base64
667
+ arrayBufferToBase64(buffer) {
668
+ let binary = "";
669
+ const bytes = new Uint8Array(buffer);
670
+ for (let i = 0; i < bytes.length; i++) {
671
+ binary += String.fromCharCode(bytes[i]);
672
+ }
673
+ return btoa(binary);
674
+ }
675
+ // Helper: Detect MIME type from file extension
676
+ detectMimeType(path) {
677
+ const ext = path.split(".").pop()?.toLowerCase() || "";
678
+ const mimeTypes = {
679
+ // Images
680
+ jpg: "image/jpeg",
681
+ jpeg: "image/jpeg",
682
+ png: "image/png",
683
+ gif: "image/gif",
684
+ webp: "image/webp",
685
+ svg: "image/svg+xml",
686
+ ico: "image/x-icon",
687
+ // Documents
688
+ pdf: "application/pdf",
689
+ doc: "application/msword",
690
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
691
+ xls: "application/vnd.ms-excel",
692
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
693
+ // Text
694
+ txt: "text/plain",
695
+ csv: "text/csv",
696
+ json: "application/json",
697
+ xml: "application/xml",
698
+ html: "text/html",
699
+ css: "text/css",
700
+ js: "application/javascript",
701
+ // Audio/Video
702
+ mp3: "audio/mpeg",
703
+ wav: "audio/wav",
704
+ mp4: "video/mp4",
705
+ webm: "video/webm",
706
+ // Archives
707
+ zip: "application/zip",
708
+ tar: "application/x-tar",
709
+ gz: "application/gzip"
710
+ };
711
+ return mimeTypes[ext] || "application/octet-stream";
712
+ }
713
+ };
714
+ var KrisspyStorage = class {
715
+ constructor(http, backendId) {
716
+ this.http = http;
717
+ this.backendId = backendId;
718
+ }
719
+ /**
720
+ * Select a storage bucket
721
+ *
722
+ * @param bucket - Bucket name (e.g., 'avatars', 'documents', 'media')
723
+ * @returns StorageBucket instance for file operations
724
+ *
725
+ * @example
726
+ * const bucket = krisspy.storage.from('avatars')
727
+ * await bucket.upload('profile.jpg', file)
728
+ */
729
+ from(bucket) {
730
+ return new StorageBucket(this.http, this.backendId, bucket);
731
+ }
732
+ /**
733
+ * List all buckets (currently returns predefined buckets)
734
+ */
735
+ async listBuckets() {
736
+ return {
737
+ data: [
738
+ { name: "media" },
739
+ { name: "avatars" },
740
+ { name: "documents" },
741
+ { name: "uploads" }
742
+ ],
743
+ error: null
744
+ };
745
+ }
746
+ };
747
+
451
748
  // src/query-builder.ts
452
749
  var QueryBuilder = class {
453
750
  constructor(http, backendId, tableName, useRLS = true) {
@@ -739,6 +1036,7 @@ var KrisspyClient = class {
739
1036
  debug: options.debug
740
1037
  });
741
1038
  this._auth = new KrisspyAuth(this.http, this.backendId);
1039
+ this._storage = new KrisspyStorage(this.http, this.backendId);
742
1040
  }
743
1041
  /**
744
1042
  * Auth module for user authentication
@@ -765,6 +1063,30 @@ var KrisspyClient = class {
765
1063
  get auth() {
766
1064
  return this._auth;
767
1065
  }
1066
+ /**
1067
+ * Storage module for file uploads and downloads
1068
+ *
1069
+ * @example
1070
+ * // Upload a file
1071
+ * const { data, error } = await krisspy.storage
1072
+ * .from('avatars')
1073
+ * .upload('profile.jpg', file)
1074
+ *
1075
+ * // Get public URL
1076
+ * const { data } = krisspy.storage.from('avatars').getPublicUrl('profile.jpg')
1077
+ *
1078
+ * // Download
1079
+ * const { data, error } = await krisspy.storage.from('docs').download('file.pdf')
1080
+ *
1081
+ * // List files
1082
+ * const { data, error } = await krisspy.storage.from('uploads').list('images/')
1083
+ *
1084
+ * // Delete files
1085
+ * const { error } = await krisspy.storage.from('uploads').remove(['old.jpg'])
1086
+ */
1087
+ get storage() {
1088
+ return this._storage;
1089
+ }
768
1090
  /**
769
1091
  * Create a query builder for a table
770
1092
  *
@@ -885,6 +1207,8 @@ export {
885
1207
  HttpClient,
886
1208
  KrisspyAuth,
887
1209
  KrisspyClient,
1210
+ KrisspyStorage,
888
1211
  QueryBuilder,
1212
+ StorageBucket,
889
1213
  createClient
890
1214
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "krisspy-sdk",
3
- "version": "0.1.0",
4
- "description": "Krisspy Cloud SDK - Database, Auth, and Functions for your apps",
3
+ "version": "0.2.0",
4
+ "description": "Krisspy Cloud SDK - Database, Auth, Storage, and Functions for your apps",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
@@ -24,6 +24,8 @@
24
24
  "baas",
25
25
  "database",
26
26
  "auth",
27
+ "storage",
28
+ "blob",
27
29
  "sdk",
28
30
  "supabase-alternative"
29
31
  ],