@telestack/storage 1.2.0 → 1.3.1

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.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  declare class HttpClient {
2
- private baseUrl;
2
+ readonly baseUrl: string;
3
3
  private tenantId;
4
4
  private headers;
5
+ readonly defaultUploadOptions?: Partial<UploadOptions>;
5
6
  constructor(config: TelestackConfig);
6
7
  private _fetchWithRetry;
7
8
  get<T>(path: string, params?: Record<string, string | undefined>): Promise<T>;
@@ -13,44 +14,92 @@ declare class HttpClient {
13
14
  uploadToPresignedUrl(url: string, data: Blob | ArrayBuffer, contentType: string, onProgress?: (p: number) => void): Promise<void>;
14
15
  private _handle;
15
16
  }
16
- declare class TelestackError extends Error {
17
- readonly status: number;
18
- readonly code?: string | undefined;
19
- constructor(message: string, status: number, code?: string | undefined);
20
- }
21
17
 
22
18
  /**
23
- * A cancellable, resumable, and observable upload task.
24
- * Designed directly after Firebase Storage's UploadTask but optimized for Telestack resumable multipart pipelines.
19
+ * A cancellable, pausable, and observable upload task.
20
+ * Modelled after Firebase Storage UploadTask familiar API, powered by Telestack.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const task = storage.ref('photos/sunset.jpg').put(file, { userId: 'u_123' });
25
+ *
26
+ * task.on('state_changed',
27
+ * snap => console.log(`${Math.round(snap.bytesTransferred / snap.totalBytes * 100)}%`),
28
+ * err => console.error('Upload failed:', err),
29
+ * () => console.log('Upload complete!')
30
+ * );
31
+ *
32
+ * // Pause / Resume
33
+ * task.pause();
34
+ * setTimeout(() => task.resume(), 2000);
35
+ *
36
+ * // Await as a promise
37
+ * const result = await task;
38
+ * console.log('File ID:', result.file_id);
39
+ * ```
25
40
  */
26
41
  declare class UploadTask implements Promise<UploadResult> {
27
42
  private readonly client;
28
43
  private readonly path;
44
+ /** Filename */
29
45
  private readonly name;
30
46
  private readonly contentType;
31
47
  private readonly options;
48
+ /** Tenant ID, inherited from SDK config */
49
+ private readonly tenantId;
50
+ /** Current upload lifecycle state. */
32
51
  private _state;
52
+ /** Bytes confirmed as uploaded so far. */
33
53
  private _bytesTransferred;
54
+ /** Final payload size after optional compression/encryption. */
34
55
  private _totalBytes;
56
+ /** Mutable upload payload (can change after preprocessing). */
35
57
  private _data;
58
+ /** Observer registry for `state_changed` notifications. */
36
59
  private _observers;
60
+ /** Promise facade for `await task`. */
37
61
  private _promise;
62
+ /** Internal promise resolve hook. */
38
63
  private _resolve;
64
+ /** Internal promise reject hook. */
39
65
  private _reject;
66
+ /** Multipart session id returned by the worker. */
40
67
  private _uploadId?;
68
+ /** File record id in metadata DB. */
69
+ private _fileId?;
70
+ /** Current version id in metadata DB (simple uploads). */
71
+ private _versionId?;
72
+ /** Object-store key generated by worker. */
73
+ private _storageKey?;
74
+ /** Uploaded multipart part list used for complete call. */
41
75
  private _parts;
76
+ /** Zero-based multipart part index currently being uploaded. */
42
77
  private _currentPartIndex;
78
+ /** True when payload uses multipart flow. */
79
+ private _isMultipart;
80
+ /** Provider tier returned by control plane. */
81
+ private _tier?;
82
+ /** Active XMLHttpRequest handle for cancellation/pause semantics. */
43
83
  private _activeXhr?;
44
- private _isResumable;
45
- private _simpleFileMetadata?;
46
- constructor(client: HttpClient, path: string, data: Blob, name: string, contentType: string, options: UploadOptions);
47
- /** Register observers for state changes, errors, and completion. */
84
+ constructor(client: HttpClient, path: string, data: Blob,
85
+ /** Filename */
86
+ name: string, contentType: string, options: UploadOptions,
87
+ /** Tenant ID, inherited from SDK config */
88
+ tenantId: string);
89
+ /**
90
+ * Register observers for upload lifecycle events.
91
+ * @param event Only `'state_changed'` is supported.
92
+ * @param nextOrObserver Progress callback or observer object.
93
+ * @param error Error callback.
94
+ * @param complete Completion callback.
95
+ * @returns Unsubscribe function.
96
+ */
48
97
  on(event: 'state_changed', nextOrObserver?: Observer<UploadTaskSnapshot> | ((snap: UploadTaskSnapshot) => void), error?: (err: Error) => void, complete?: () => void): () => void;
49
- /** Suspend the upload. Only works elegantly on resumable uploads, but supported for all. */
98
+ /** Pause the upload. Works natively for multipart; simple uploads will restart on resume. */
50
99
  pause(): boolean;
51
- /** Resume a paused upload. */
100
+ /** Resume a paused upload from where it left off (multipart) or restart (simple). */
52
101
  resume(): boolean;
53
- /** Permanently cancel the upload, cleaning up partial server state if necessary. */
102
+ /** Permanently cancel the upload, cleaning up any in-progress server state. */
54
103
  cancel(): boolean;
55
104
  get snapshot(): UploadTaskSnapshot;
56
105
  then<TResult1 = UploadResult, TResult2 = never>(onfulfilled?: ((value: UploadResult) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
@@ -58,85 +107,271 @@ declare class UploadTask implements Promise<UploadResult> {
58
107
  finally(onfinally?: (() => void) | null): Promise<UploadResult>;
59
108
  readonly [Symbol.toStringTag] = "UploadTask";
60
109
  private _start;
110
+ /**
111
+ * Simple upload path (< 50 MB):
112
+ * 1. Obtain a presigned upload URL from the control plane
113
+ * 2. PUT directly to MinIO/S3 from the browser
114
+ * 3. Confirm via control plane (updates metadata, triggers quota + audit)
115
+ */
61
116
  private _startSimple;
62
- private _startResumable;
63
- private _continueResumable;
64
- private _uploadChunkWithProgress;
117
+ /**
118
+ * Multipart upload path (>= 50 MB) via Tier 1 (S3):
119
+ * 1. Initiate multipart session on control plane
120
+ * 2. Upload each chunk to a separate presigned URL
121
+ * 3. Complete the session (S3 assembles the object)
122
+ */
123
+ private _startMultipart;
124
+ private _continueMultipart;
125
+ private _putToPresignedUrl;
126
+ private _uploadChunkXhr;
127
+ /** Pushes a fresh snapshot to all registered observers. */
65
128
  private _notifyObservers;
129
+ /** Centralized terminal error handler for all upload flows. */
66
130
  private _handleError;
67
131
  }
68
132
 
133
+ /** SDK initialization config */
69
134
  interface TelestackConfig {
135
+ /** Full URL to your TelestackStorage worker, e.g. https://storage.example.com */
70
136
  baseUrl: string;
137
+ /** Tenant ID — scopes all operations to a specific tenant's bucket */
138
+ tenantId: string;
139
+ /** Optional project context used by internal/admin operations */
140
+ projectId?: string;
141
+ /** Optional organization context used by internal/admin operations */
142
+ orgId?: string;
143
+ /** API Key for server-to-server or developer access */
71
144
  apiKey?: string;
145
+ /** JWT Bearer token for end-user auth (from your auth provider) */
72
146
  token?: string;
73
- tenantId: string;
147
+ /** Default upload options applied to all uploads */
74
148
  defaultUploadOptions?: Partial<UploadOptions>;
75
149
  }
150
+ /** Represents a file stored in TelestackStorage */
76
151
  interface FileMetadata {
77
- id: string;
152
+ /** Internal document ID */
153
+ $id: string;
154
+ /** Tenant/project id owning this file. */
78
155
  tenant_id: string;
79
- path: string;
156
+ /** Parent directory id (`root` for root-level files). */
157
+ directory_id: string;
158
+ /** File display name. */
80
159
  name: string;
160
+ /** Canonical hashed path used for lookups. */
161
+ path_hash: string;
162
+ /** Current active version id. */
163
+ current_version_id: string;
164
+ /** Cached file size in bytes. */
165
+ cached_size: number;
166
+ /** Lifecycle status in metadata DB. */
167
+ status: 'pending' | 'active' | 'deleted';
168
+ /** ISO timestamp when metadata row was created. */
169
+ created_at: string;
170
+ /** ISO timestamp when metadata row was last updated. */
171
+ updated_at: string;
172
+ }
173
+ /** Represents a specific version of a stored file */
174
+ interface FileVersionMetadata {
175
+ /** Version row id. */
176
+ $id: string;
177
+ /** Parent file id. */
178
+ file_id: string;
179
+ /** Object storage key for this specific version. */
180
+ storage_key: string;
181
+ /** 'tier1' = S3-compatible (MinIO/R2/S3) */
182
+ provider: 'tier1';
183
+ /** Version size in bytes. */
81
184
  size: number;
185
+ /** MIME type recorded for this version. */
82
186
  content_type: string;
187
+ /** Provider ETag if available. */
188
+ etag?: string;
189
+ /** ISO timestamp when the version row was created. */
190
+ created_at: string;
191
+ }
192
+ /** A bucket record corresponding to a tenant's storage configuration */
193
+ interface BucketMetadata {
194
+ /** Bucket row id. */
195
+ $id: string;
196
+ /** Tenant/project id owning the bucket. */
197
+ tenant_id: string;
198
+ /** Organization/owner id associated with the bucket. */
83
199
  owner_id: string;
84
- status: 'pending' | 'active' | 'deleted';
85
- metadata: Record<string, any>;
200
+ /** Bucket-level public-read toggle. */
201
+ is_public: boolean;
202
+ /** Physical storage tier. */
203
+ tier: 'tier1';
204
+ /** Commercial plan for this bucket. */
205
+ plan: 'free' | 'paid';
206
+ /** Operational status for access control. */
207
+ status: 'active' | 'suspended';
208
+ /** Quota limit in bytes. */
209
+ storage_limit: number;
210
+ /** ISO timestamp when bucket row was created. */
86
211
  created_at: string;
212
+ /** ISO timestamp when bucket row was last updated. */
87
213
  updated_at: string;
88
214
  }
215
+ /** Options for upload operations */
89
216
  interface UploadOptions {
90
- tenantId?: string;
91
- userId: string;
92
- metadata?: Record<string, any>;
217
+ /** User ID to associate with the upload */
218
+ userId?: string;
219
+ /** Directory ID to place the file into (defaults to root) */
220
+ directoryId?: string;
221
+ /** Size of each multipart chunk in bytes (default: 10MB) */
93
222
  chunkSize?: number;
223
+ /** Base64 AES-GCM key for client-side E2EE before upload */
94
224
  encryptionKey?: string;
225
+ /** Image compression settings applied before upload */
95
226
  compressImage?: {
96
227
  maxWidth?: number;
97
228
  maxHeight?: number;
229
+ /** 0.0 (worst) to 1.0 (best), default 0.85 */
98
230
  quality?: number;
99
231
  };
100
232
  }
233
+ /** Options for download operations */
101
234
  interface DownloadOptions {
235
+ /** Retrieve a specific version by its ID */
102
236
  versionId?: string;
237
+ /** Expiry in seconds for the presigned URL (default: 3600) */
238
+ expiresIn?: number;
239
+ /** Download mode for content disposition handling */
240
+ mode?: 'download' | 'inline';
103
241
  }
242
+ /** Options for listing files */
104
243
  interface ListOptions {
105
- prefix?: string;
244
+ /** Parent directory id, or `null` for root. */
245
+ directoryId?: string | null;
246
+ /** Max records to return. */
106
247
  limit?: number;
248
+ /** Pagination offset. */
249
+ offset?: number;
107
250
  }
251
+ /** Options for searching files */
108
252
  interface SearchOptions {
253
+ /** Name prefix or substring filter */
109
254
  query?: string;
110
- metadata?: Record<string, any>;
255
+ /** Filter by file extension, e.g. 'pdf' */
256
+ extension?: string;
257
+ /** Filter by minimum file size in bytes */
258
+ minSize?: number;
111
259
  limit?: number;
260
+ offset?: number;
112
261
  }
262
+ /** Result of a search query */
113
263
  interface SearchResult {
264
+ /** True on successful query execution. */
114
265
  success: boolean;
266
+ /** Matched files after filtering. */
115
267
  files: FileMetadata[];
268
+ /** Total records returned by the current query. */
269
+ total: number;
116
270
  }
271
+ /** Result of a completed upload */
117
272
  interface UploadResult {
118
- file: FileMetadata;
273
+ /** True when upload/confirm flow completed successfully. */
274
+ success: boolean;
275
+ /** File metadata id. */
276
+ file_id: string;
277
+ /** Active version id. */
278
+ version_id: string;
279
+ /** Whether multipart S3 upload was used */
119
280
  resumable: boolean;
120
281
  }
282
+ /** Result of a batch delete */
121
283
  interface BatchDeleteResult {
284
+ /** True when batch request is accepted/completed. */
122
285
  success: boolean;
123
- deletedCount: number;
124
- errors: any[];
286
+ /** Status message (queued or completed). */
287
+ message: string;
125
288
  }
126
- interface BatchCopyResult {
289
+ /** Result of a batch copy/move */
290
+ interface BatchMutationResult {
291
+ /** True when batch request succeeds. */
127
292
  success: boolean;
293
+ /** Provider result payloads per item. */
128
294
  results: any[];
129
295
  }
130
- interface TagSet {
131
- Key: string;
132
- Value: string;
296
+ /** Public path visibility rule for selective anonymous access. */
297
+ interface PublicPathRule {
298
+ /** Rule row id. */
299
+ $id: string;
300
+ /** Tenant/project id owning the rule. */
301
+ tenant_id: string;
302
+ /** Public prefix (no trailing wildcard in DB). */
303
+ path_prefix: string;
304
+ /** Public-read toggle for this prefix. */
305
+ is_public: boolean;
306
+ /** ISO timestamp when rule was created. */
307
+ created_at: string;
308
+ }
309
+ /** Response payload for API key generation. */
310
+ interface GeneratedApiKeyResponse {
311
+ /** True when key creation succeeds. */
312
+ success: boolean;
313
+ /** Plaintext API key. Returned once and must be stored client-side securely. */
314
+ apiKey: string;
315
+ key: {
316
+ /** API key row id. */
317
+ id: string;
318
+ /** Display name assigned to the key. */
319
+ name: string;
320
+ /** Tenant/project id associated with the key. */
321
+ tenant_id: string;
322
+ /** ISO timestamp when the key was created. */
323
+ created_at: string;
324
+ };
325
+ }
326
+ /** Storage usage analytics for a tenant */
327
+ interface TenantUsageStats {
328
+ /** Aggregated stored bytes. */
329
+ total_bytes: number;
330
+ /** Aggregated active file count. */
331
+ total_files: number;
332
+ /** ISO timestamp of last aggregation sync. */
333
+ last_aggregated_at: string;
133
334
  }
134
- /** Upload State Enum exactly like Firebase */
335
+ /** Time-series analytics data point */
336
+ interface UsageAnalytics {
337
+ /** Read operation count. */
338
+ reads: number;
339
+ /** Write operation count. */
340
+ writes: number;
341
+ /** Bandwidth usage in bytes. */
342
+ bandwidth: number;
343
+ /** Aggregation period in days. */
344
+ period_days: number;
345
+ }
346
+ /** A real-time event emitted from the SSE stream */
347
+ interface StorageEvent {
348
+ /** Event row id. */
349
+ $id: string;
350
+ /** Tenant/project id for the event. */
351
+ tenant_id: string;
352
+ /** Event type key (e.g. `file.upload.confirmed`). */
353
+ event_type: string;
354
+ /** Logical resource type affected by the event. */
355
+ resource_type: string;
356
+ /** Resource id affected by the event. */
357
+ resource_id: string;
358
+ /** JSON payload string for event-specific context. */
359
+ payload: string;
360
+ /** Monotonic sequence for event stream ordering. */
361
+ sequence_number: string;
362
+ /** ISO timestamp when event was written. */
363
+ created_at: string;
364
+ }
365
+ /** Upload state, matching Firebase Storage semantics */
135
366
  type UploadState = 'processing' | 'running' | 'paused' | 'success' | 'error' | 'canceled';
136
367
  interface UploadTaskSnapshot {
368
+ /** Uploaded bytes at this observation point. */
137
369
  bytesTransferred: number;
370
+ /** Total bytes for this upload task. */
138
371
  totalBytes: number;
372
+ /** Current upload lifecycle state. */
139
373
  state: UploadState;
374
+ /** Reference to the associated UploadTask instance. */
140
375
  task: UploadTask;
141
376
  }
142
377
  type Observer<T> = {
@@ -146,156 +381,402 @@ type Observer<T> = {
146
381
  };
147
382
 
148
383
  /**
149
- * Base abstract reference to a location in Telestack Storage.
384
+ * Base class for Telestack path references.
150
385
  */
151
386
  declare abstract class StorageRef {
152
387
  protected readonly client: HttpClient;
153
388
  readonly path: string;
154
389
  readonly tenantId: string;
155
390
  constructor(client: HttpClient, path: string, tenantId: string);
156
- /** Navigate to a highly specific child path. Automatically infers File or Directory Ref. */
391
+ /**
392
+ * Navigate to a child path. Returns a FileRef or DirRef based on whether
393
+ * the resulting path ends with a `/`.
394
+ */
157
395
  child(childPath: string): StorageRef;
158
396
  }
159
397
  /**
160
- * Reference exclusively to a Directory (Prefix).
398
+ * Reference to a directory (folder) in Telestack Storage.
161
399
  */
162
400
  declare class DirRef extends StorageRef {
163
- /** Retrieve all files immediately within this directory prefix. */
164
- listAll(limit?: number): Promise<FileMetadata[]>;
401
+ /**
402
+ * List all files in this directory.
403
+ */
404
+ listAll(options?: ListOptions): Promise<{
405
+ files: FileMetadata[];
406
+ directories: any[];
407
+ }>;
408
+ /**
409
+ * Create this directory and get back the directory document.
410
+ */
411
+ create(parentId?: string): Promise<any>;
412
+ /**
413
+ * Delete this directory and all its contents asynchronously (background queue).
414
+ */
415
+ delete(directoryId: string): Promise<{
416
+ success: boolean;
417
+ message: string;
418
+ }>;
419
+ /**
420
+ * Search within this directory's prefix.
421
+ */
422
+ search(options: SearchOptions): Promise<SearchResult>;
165
423
  }
166
424
  /**
167
- * Reference exclusively to a File object.
425
+ * Reference to a specific file in Telestack Storage.
426
+ *
427
+ * @example
428
+ * ```ts
429
+ * const fileRef = storage.ref('documents/report.pdf');
430
+ *
431
+ * // Upload with progress tracking
432
+ * const task = fileRef.put(pdfBlob, { userId: 'u_abc' });
433
+ * task.on('state_changed', snap => console.log(snap.bytesTransferred));
434
+ *
435
+ * // Download URL
436
+ * const url = await fileRef.getDownloadUrl();
437
+ * ```
168
438
  */
169
439
  declare class FileRef extends StorageRef {
440
+ private resolveFileRecord;
170
441
  /**
171
- * Upload a File/Blob, returning an UploadTask that can be observed, paused, and cancelled.
172
- * Functions identically to Firebase Storage.
442
+ * Upload a File or Blob. Returns an UploadTask you can observe, pause,
443
+ * resume, and cancel — just like Firebase Storage.
173
444
  */
174
- put(data: File | Blob, options: UploadOptions): UploadTask;
445
+ put(data: File | Blob, options?: UploadOptions): UploadTask;
175
446
  /**
176
- * Upload raw bytes directly.
447
+ * Upload raw bytes.
177
448
  */
178
- putBytes(data: ArrayBuffer, contentType: string, options: UploadOptions): UploadTask;
179
- /** Get a time-limited presigned download URL. */
180
- getDownloadUrl(options?: DownloadOptions): Promise<string>;
449
+ putBytes(data: ArrayBuffer, contentType: string, options?: UploadOptions): UploadTask;
181
450
  /**
182
- * Securely downloads and decrypts an E2EE file entirely within the browser.
183
- * Requires the exact Base64 AES-GCM key used during `put()`.
451
+ * Get a time-limited presigned download URL (302 redirect to CDN/S3).
184
452
  */
185
- getDecryptedBlob(encryptionKey: string): Promise<Blob>;
186
- /** Get the file's metadata database record. */
187
- getMetadata(): Promise<FileMetadata>;
188
- /** Update custom JSON metadata on the file. */
189
- updateMetadata(metadata: Record<string, any>): Promise<FileMetadata>;
190
- /** Permanently delete this file. */
191
- delete(): Promise<void>;
192
- listVersions(): Promise<{
193
- versions: any[];
194
- deleteMarkers: any[];
195
- }>;
196
- getVersionUrl(versionId: string): Promise<string>;
197
- getTags(): Promise<TagSet[]>;
198
- setTags(tags: TagSet[]): Promise<void>;
199
- setLegalHold(status: 'ON' | 'OFF'): Promise<void>;
453
+ getDownloadUrl(fileId?: string, options?: DownloadOptions): Promise<string>;
454
+ /**
455
+ * Access this file via the public CDN URL (only works if bucket is_public = true).
456
+ * Returns the redirect URL directly.
457
+ */
458
+ getCdnUrl(path: string): string;
459
+ /**
460
+ * Download and decrypt an E2EE-encrypted file entirely in the browser.
461
+ * Requires the same Base64 AES-GCM key used during upload.
462
+ */
463
+ getDecryptedBlob(encryptionKey: string, originalMimeType: string, fileId?: string): Promise<Blob>;
464
+ /**
465
+ * Get the file's metadata record from the database.
466
+ */
467
+ getMetadata(fileId?: string): Promise<FileMetadata>;
468
+ /**
469
+ * Get all versions of this file.
470
+ */
471
+ getVersions(fileId?: string): Promise<FileVersionMetadata[]>;
472
+ /**
473
+ * Soft-delete a file (marks as deleted, preserves versions).
474
+ */
475
+ delete(fileId?: string): Promise<void>;
200
476
  }
201
477
 
202
478
  /**
203
479
  * Fluent builder for batch file operations.
204
- * Operations execute identically as single network requests over the backend API.
480
+ * Each operation compiles to a single API request, handled by the background queue
481
+ * for large datasets to keep the API responsive.
205
482
  *
206
483
  * @example
207
- * await storage.batch().delete(['a.pdf', 'b.pdf']).run();
208
- * await storage.batch().copy(['a.pdf'], 'archive/').run();
209
- * await storage.batch().move(['a.pdf'], 'archive/').run();
484
+ * ```ts
485
+ * // Delete multiple files
486
+ * await storage.batch().delete(['fileId1', 'fileId2']).run();
487
+ *
488
+ * // Copy files to a new directory
489
+ * await storage.batch().copy([{ sourceId: 'id1', destDirId: 'dir2', destName: 'copy.pdf', destPath: 'docs/copy.pdf' }]).run();
490
+ * ```
210
491
  */
211
492
  declare class BatchBuilder {
212
493
  private readonly client;
494
+ private readonly tenantId;
213
495
  private _op;
214
- private _paths;
215
- private _dest;
216
- constructor(client: HttpClient);
217
- delete(paths: string[]): this;
218
- copy(paths: string[], destinationPrefix: string): this;
219
- move(paths: string[], destinationPrefix: string): this;
220
- run(): Promise<BatchDeleteResult | BatchCopyResult>;
496
+ private _fileIds;
497
+ private _mappings;
498
+ constructor(client: HttpClient, tenantId: string);
499
+ /**
500
+ * Queue file IDs for batch deletion. Runs in background queue.
501
+ */
502
+ delete(fileIds: string[]): this;
503
+ /**
504
+ * Queue copy operations (file ID → new directory).
505
+ */
506
+ copy(mappings: {
507
+ sourceId: string;
508
+ destDirId: string;
509
+ destName: string;
510
+ destPath: string;
511
+ }[]): this;
512
+ /**
513
+ * Queue move operations (file ID → new directory/name).
514
+ */
515
+ move(mappings: {
516
+ fileId: string;
517
+ destDirId: string;
518
+ destName: string;
519
+ destPath: string;
520
+ }[]): this;
521
+ /**
522
+ * Execute the queued batch operation.
523
+ */
524
+ run(): Promise<BatchDeleteResult | BatchMutationResult>;
221
525
  }
222
526
 
223
527
  /**
224
528
  * Fluent builder for searching files via Metadata or Full-Text queries.
225
529
  *
226
530
  * @example
531
+ * ```ts
227
532
  * const files = await storage.query()
228
- * .where('project', 'Q1')
229
- * .nameContains('report')
533
+ * .search('report')
534
+ * .withExtension('pdf')
535
+ * .minSize(1024)
230
536
  * .limit(10)
231
537
  * .get();
538
+ * ```
232
539
  */
233
540
  declare class QueryBuilder {
234
541
  private readonly client;
542
+ private readonly tenantId;
235
543
  private _query;
236
- private _metadata;
544
+ private _extension;
545
+ private _minSize;
237
546
  private _limit;
238
- constructor(client: HttpClient);
239
- nameContains(text: string): this;
240
- where(key: string, value: any): this;
547
+ private _offset;
548
+ constructor(client: HttpClient, tenantId: string);
549
+ /** Find files whose names match this text */
550
+ search(text: string): this;
551
+ /** Filter by file extension (e.g., 'pdf', 'png') */
552
+ withExtension(ext: string): this;
553
+ /** Filter by minimum file size in bytes */
554
+ minSize(bytes: number): this;
555
+ /** Set the maximum number of results (default 20, max 100) */
241
556
  limit(n: number): this;
557
+ /** Set the number of results to skip (for pagination) */
558
+ offset(n: number): this;
559
+ /** Execute the search and return the list of matching files */
242
560
  get(): Promise<FileMetadata[]>;
561
+ /** Alias for get() */
562
+ run(): Promise<FileMetadata[]>;
243
563
  }
244
564
 
245
565
  /**
246
- * TelestackStorage — The main SDK client.
247
- * More comprehensive and fluent than Firebase/Appwrite Storage.
566
+ * @class TelestackStorage
567
+ * The main entry point for the Telestack Storage Web SDK.
568
+ *
569
+ * Mirrors Firebase Storage's fluent `.ref()` API while adding enterprise-grade
570
+ * features: tiered storage (Internal + S3), realtime SSE, analytics, search,
571
+ * and batch operations.
248
572
  *
249
573
  * @example
250
574
  * ```ts
575
+ * import { TelestackStorage } from '@telestack/storage-web';
576
+ *
251
577
  * const storage = new TelestackStorage({
252
578
  * baseUrl: 'https://storage.yourdomain.com',
253
- * tenantId: 'your_tenant_id',
254
- * apiKey: 'tk_your_api_key',
579
+ * tenantId: 'tenant_abc',
580
+ * apiKey: 'tk_live_xxx',
255
581
  * });
256
582
  *
257
- * // Upload with progress, pause, and resume
258
- * const task = storage.ref('videos/demo.mp4').put(videoBlob);
259
- * task.on('state_changed',
260
- * (snap) => console.log((snap.bytesTransferred / snap.totalBytes) * 100 + '%'),
261
- * (err) => console.error(err),
262
- * () => console.log('Done!')
263
- * );
583
+ * // Upload a file
584
+ * const task = storage.ref('photos/avatar.png').put(file);
585
+ * task.on('state_changed', snap => {
586
+ * const pct = (snap.bytesTransferred / snap.totalBytes * 100).toFixed(0);
587
+ * console.log(`${pct}% uploaded`);
588
+ * }, console.error, () => console.log('Done!'));
264
589
  *
265
- * // Later...
266
- * task.pause();
267
- * task.resume();
590
+ * // Search files
591
+ * const results = await storage.search({ query: 'report', extension: 'pdf' });
592
+ *
593
+ * // Usage analytics
594
+ * const stats = await storage.getUsageStats(7);
268
595
  * ```
269
596
  */
270
597
  declare class TelestackStorage {
271
598
  private readonly config;
272
- private readonly http;
599
+ /** @internal */
600
+ readonly http: HttpClient;
273
601
  readonly tenantId: string;
274
602
  constructor(config: TelestackConfig);
275
- /** Get a highly-fluent reference to a specific file. */
603
+ /**
604
+ * Create a cloned client with updated tenant/project/org defaults.
605
+ * Helpful in multi-tenant consoles where context changes often.
606
+ */
607
+ withContext(context: {
608
+ tenantId?: string;
609
+ projectId?: string;
610
+ orgId?: string;
611
+ }): TelestackStorage;
612
+ /**
613
+ * Create a cloned client with updated auth credentials.
614
+ * Passing `null` explicitly clears an existing credential.
615
+ */
616
+ withAuth(auth: {
617
+ apiKey?: string | null;
618
+ token?: string | null;
619
+ }): TelestackStorage;
620
+ /**
621
+ * Get a fluent reference to a specific file path.
622
+ * Use this as the starting point for uploads, downloads, and file metadata.
623
+ *
624
+ * @param path - Full path within the tenant bucket, e.g. `'documents/report.pdf'`
625
+ */
276
626
  ref(path: string): FileRef;
277
- /** Get a highly-fluent reference to a directory/prefix. */
627
+ /**
628
+ * Get a fluent reference to a directory (prefix).
629
+ *
630
+ * @param path - Directory path, e.g. `'documents/'` or `'images'`
631
+ */
278
632
  dir(path: string): DirRef;
279
- /** Helper: List files for the entire bucket/tenant or specific prefix. */
280
- list(options?: ListOptions): Promise<FileMetadata[]>;
281
- /** Rename a single file or directory prefix. */
282
- rename(oldPath: string, newName: string): Promise<{
283
- success: boolean;
284
- newPath: string;
633
+ /**
634
+ * Get this tenant's bucket configuration.
635
+ */
636
+ getBucket(): Promise<BucketMetadata>;
637
+ /**
638
+ * List files in a directory. Pass `null` for the root.
639
+ */
640
+ list(options?: ListOptions): Promise<{
641
+ files: FileMetadata[];
642
+ directories: any[];
285
643
  }>;
286
- /** Get a fluent batch operation builder for mass-mutations over the network. */
287
- batch(): BatchBuilder;
288
- /** Get a fluent query builder for metadata and full-text search. */
644
+ /**
645
+ * Search files by name, extension, or minimum size.
646
+ *
647
+ * @example
648
+ * ```ts
649
+ * const { files, total } = await storage.search({ query: 'invoice', extension: 'pdf' });
650
+ * ```
651
+ */
652
+ search(options: SearchOptions): Promise<SearchResult>;
653
+ /**
654
+ * Get a fluent query builder for advanced searching.
655
+ *
656
+ * @example
657
+ * ```ts
658
+ * const files = await storage.query().search('invoice').get();
659
+ * ```
660
+ */
289
661
  query(): QueryBuilder;
290
- /** Generate a new API key (admin only). The key is shown only once. */
291
- generateApiKey(name?: string): Promise<{
292
- apiKey: string;
662
+ /**
663
+ * Get a fluent batch operation builder.
664
+ *
665
+ * @example
666
+ * ```ts
667
+ * await storage.batch()
668
+ * .delete(['id1', 'id2', 'id3'])
669
+ * .commit();
670
+ * ```
671
+ */
672
+ batch(): BatchBuilder;
673
+ /**
674
+ * Bulk delete files by their IDs. Queued in background for large lists.
675
+ */
676
+ batchDelete(fileIds: string[]): Promise<BatchDeleteResult>;
677
+ /**
678
+ * Copy multiple files to new directories simultaneously.
679
+ */
680
+ batchCopy(mappings: {
681
+ sourceId: string;
682
+ destDirId: string;
683
+ destName: string;
684
+ destPath: string;
685
+ }[]): Promise<BatchMutationResult>;
686
+ /**
687
+ * Move multiple files to new directories/names simultaneously.
688
+ */
689
+ batchMove(mappings: {
690
+ fileId: string;
691
+ destDirId: string;
692
+ destName: string;
693
+ destPath: string;
694
+ }[]): Promise<BatchMutationResult>;
695
+ /**
696
+ * Get aggregated storage usage for the tenant.
697
+ *
698
+ * @param days - Number of days to include in the time window (default: 7)
699
+ */
700
+ getUsageStats(days?: number): Promise<UsageAnalytics>;
701
+ /**
702
+ * Subscribe to real-time storage events for this tenant via SSE.
703
+ * Events include file uploads, deletions, and system changes.
704
+ *
705
+ * @returns An `unsubscribe` function — call it to close the connection.
706
+ *
707
+ * @example
708
+ * ```ts
709
+ * const unsubscribe = storage.onEvent((event) => {
710
+ * console.log(event.event_type, event.resource_id);
711
+ * });
712
+ *
713
+ * // Later
714
+ * unsubscribe();
715
+ * ```
716
+ */
717
+ onEvent(callback: (event: StorageEvent) => void): () => void;
718
+ /**
719
+ * Initialize the internal database schema (admin only — run once on bootstrap).
720
+ */
721
+ initDatabase(): Promise<{
722
+ success: boolean;
293
723
  message: string;
294
724
  }>;
295
- /** Revoke an API key by its ID. */
725
+ /**
726
+ * Generate a new API key (admin only). The raw key is returned once — store it securely.
727
+ *
728
+ * @example
729
+ * ```ts
730
+ * const { apiKey } = await storage.generateApiKey('my-backend-service');
731
+ * ```
732
+ */
733
+ generateApiKey(name?: string): Promise<GeneratedApiKeyResponse>;
734
+ /**
735
+ * Revoke an existing API key by its database ID.
736
+ */
296
737
  revokeApiKey(keyId: string): Promise<void>;
297
- /** Get S3 bucket configuration details. */
298
- getBucketInfo(): Promise<any>;
738
+ /**
739
+ * Read analytics from internal admin API for the configured tenant.
740
+ */
741
+ getInternalAnalytics(tenantId?: string): Promise<Array<{
742
+ date: string;
743
+ reads: number;
744
+ writes: number;
745
+ bandwidth: number;
746
+ }>>;
747
+ /**
748
+ * Fetch internal bucket information including effective quota.
749
+ */
750
+ getInternalBucketInfo(tenantId?: string): Promise<{
751
+ tier: string;
752
+ quotaLimit: number;
753
+ bucket: BucketMetadata;
754
+ }>;
755
+ /**
756
+ * Toggle bucket visibility from internal admin API.
757
+ */
758
+ updateBucketVisibility(isPublic: boolean, tenantId?: string): Promise<{
759
+ success: boolean;
760
+ bucket: BucketMetadata;
761
+ }>;
762
+ /**
763
+ * List granular public path rules.
764
+ */
765
+ listPublicPathRules(tenantId?: string): Promise<PublicPathRule[]>;
766
+ /**
767
+ * Add a granular public path rule.
768
+ */
769
+ addPublicPathRule(pathPrefix: string, tenantId?: string): Promise<PublicPathRule>;
770
+ /**
771
+ * Delete a granular public path rule by id.
772
+ */
773
+ deletePublicPathRule(ruleId: string, tenantId?: string): Promise<void>;
774
+ }
775
+
776
+ declare class TelestackError extends Error {
777
+ readonly status: number;
778
+ readonly code?: string | undefined;
779
+ constructor(message: string, status: number, code?: string | undefined);
299
780
  }
300
781
 
301
782
  declare class CryptoHelper {
@@ -331,4 +812,4 @@ declare class ImageHelper {
331
812
  }): Promise<Blob>;
332
813
  }
333
814
 
334
- export { BatchBuilder, type BatchCopyResult, type BatchDeleteResult, CryptoHelper, DirRef, type DownloadOptions, type FileMetadata, FileRef, HttpClient, ImageHelper, type ListOptions, type Observer, QueryBuilder, type SearchOptions, type SearchResult, StorageRef, type TagSet, type TelestackConfig, TelestackError, TelestackStorage, type UploadOptions, type UploadResult, type UploadState, UploadTask, type UploadTaskSnapshot };
815
+ export { BatchBuilder, type BatchDeleteResult, type BatchMutationResult, type BucketMetadata, CryptoHelper, DirRef, type DownloadOptions, type FileMetadata, FileRef, type FileVersionMetadata, type GeneratedApiKeyResponse, HttpClient, ImageHelper, type ListOptions, type Observer, type PublicPathRule, QueryBuilder, type SearchOptions, type SearchResult, type StorageEvent, StorageRef, type TelestackConfig, TelestackError, TelestackStorage, type TenantUsageStats, type UploadOptions, type UploadResult, type UploadState, UploadTask, type UploadTaskSnapshot, type UsageAnalytics };