@plyaz/types 1.15.20 → 1.16.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.
Files changed (41) hide show
  1. package/dist/api/aws/index.d.ts +5 -0
  2. package/dist/api/aws/signature.d.ts +42 -0
  3. package/dist/api/endpoints/cdn/endpoints.d.ts +57 -0
  4. package/dist/api/endpoints/cdn/index.d.ts +6 -0
  5. package/dist/api/endpoints/cdn/types.d.ts +151 -0
  6. package/dist/api/endpoints/index.d.ts +2 -0
  7. package/dist/api/endpoints/types.d.ts +3 -1
  8. package/dist/api/endpoints/virustotal/endpoints.d.ts +37 -0
  9. package/dist/api/endpoints/virustotal/index.d.ts +6 -0
  10. package/dist/api/endpoints/virustotal/types.d.ts +202 -0
  11. package/dist/api/index.cjs +1317 -1
  12. package/dist/api/index.cjs.map +1 -1
  13. package/dist/api/index.d.ts +3 -0
  14. package/dist/api/index.js +1317 -1
  15. package/dist/api/index.js.map +1 -1
  16. package/dist/core/idempotency.d.ts +48 -0
  17. package/dist/core/index.d.ts +1 -0
  18. package/dist/errors/codes.d.ts +296 -0
  19. package/dist/errors/enums.d.ts +10 -0
  20. package/dist/errors/index.cjs +1482 -1
  21. package/dist/errors/index.cjs.map +1 -1
  22. package/dist/errors/index.d.ts +1 -0
  23. package/dist/errors/index.js +1482 -2
  24. package/dist/errors/index.js.map +1 -1
  25. package/dist/errors/validation.d.ts +71 -0
  26. package/dist/index.cjs +2268 -132
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +11 -0
  29. package/dist/index.js +2227 -133
  30. package/dist/index.js.map +1 -1
  31. package/dist/logger/enums.d.ts +10 -0
  32. package/dist/notifications/types.d.ts +1 -2
  33. package/dist/storage/compliance.d.ts +247 -0
  34. package/dist/storage/enums.d.ts +527 -0
  35. package/dist/storage/event-handler-mapping.d.ts +69 -0
  36. package/dist/storage/index.d.ts +13 -0
  37. package/dist/storage/interfaces.d.ts +2242 -0
  38. package/dist/storage/plugins.d.ts +1056 -0
  39. package/dist/storage/schemas.d.ts +224 -0
  40. package/dist/storage/webhooks.d.ts +340 -0
  41. package/package.json +6 -1
@@ -0,0 +1,1056 @@
1
+ /**
2
+ * Storage Plugin System Types
3
+ * @module @plyaz/types/storage/plugins
4
+ *
5
+ * Defines the plugin system for extending storage functionality with lifecycle hooks.
6
+ * Plugins are separate from webhooks - they run synchronously during file operations.
7
+ */
8
+ import type { FileMetadata, UploadParams, UploadResult, DownloadParams, DownloadResult, DeleteParams, FileDeleteResult, PresignedUrlOptions, PresignedUrlResult, AdapterHealthCheck, StorageListFilesParams, StorageListFilesResult, StorageCopyFileParams, StorageMoveFileParams, StorageReplaceFileParams } from './interfaces';
9
+ import type { STORAGE_PLUGIN_TYPE } from './enums';
10
+ /**
11
+ * Known plugin names for type safety
12
+ * Use this for skipPlugins/onlyPlugins parameters
13
+ */
14
+ export type StorageKnownPluginName = 'virus-scanner' | 'sharp-image-processor' | 'ffmpeg-video-processor' | 'metadata-extractor' | 'cdn-invalidator' | 'file-size-validator' | 'metadata-enricher' | 'upload-notifier' | 'delete-auditor' | 'access-logger' | string;
15
+ /**
16
+ * Plugin execution options for filtering which plugins to run
17
+ * Used to control plugin execution per operation
18
+ */
19
+ export interface StoragePluginExecutionOptions {
20
+ /** Skip specific plugins by name for this operation */
21
+ skipPlugins?: readonly StorageKnownPluginName[];
22
+ /** Only run these specific plugins for this operation */
23
+ onlyPlugins?: readonly StorageKnownPluginName[];
24
+ }
25
+ /**
26
+ * Base plugin configuration
27
+ */
28
+ export interface BasePluginConfig {
29
+ /** Plugin name */
30
+ name: StorageKnownPluginName;
31
+ /** Plugin type */
32
+ type: STORAGE_PLUGIN_TYPE;
33
+ /** Plugin priority (1-100, lower runs first) */
34
+ priority?: number;
35
+ /** Plugin version */
36
+ version?: string;
37
+ /** Plugin description */
38
+ description?: string;
39
+ /** Whether the plugin is enabled */
40
+ enabled?: boolean;
41
+ /** Logger instance */
42
+ logger?: unknown;
43
+ /** API client configuration (for REST API-based plugins) */
44
+ apiClientConfig?: {
45
+ baseURL: string;
46
+ headers?: Record<string, string>;
47
+ timeout?: number;
48
+ [key: string]: unknown;
49
+ };
50
+ }
51
+ /**
52
+ * Plugin Registry Configuration
53
+ */
54
+ export interface PluginRegistryConfig {
55
+ /** Logger instance */
56
+ logger?: unknown;
57
+ /** Whether to continue execution if a plugin fails */
58
+ continueOnError?: boolean;
59
+ /** Maximum execution time for all plugins (milliseconds) */
60
+ maxExecutionTime?: number;
61
+ }
62
+ /**
63
+ * Storage Adapter Interface for Plugins
64
+ * Provides access to all public storage operations
65
+ * BaseStorageAdapter implements this interface
66
+ *
67
+ * Note: This interface uses structural typing to match BaseStorageAdapter
68
+ * without creating circular dependencies between packages
69
+ */
70
+ export interface PluginStorageAdapterInterface {
71
+ /** Adapter name */
72
+ readonly name: string;
73
+ /** Adapter type */
74
+ readonly type: string;
75
+ /** Adapter priority */
76
+ readonly priority: number;
77
+ /** Whether adapter is enabled */
78
+ readonly enabled: boolean;
79
+ /** Upload a file to storage - uses UploadParams signature */
80
+ upload: (params: UploadParams) => Promise<UploadResult>;
81
+ /** Download a file from storage - uses DownloadParams signature */
82
+ download: (params: DownloadParams) => Promise<DownloadResult>;
83
+ /** Delete a file from storage - uses DeleteParams signature */
84
+ delete: (params: DeleteParams) => Promise<FileDeleteResult>;
85
+ /** Generate a presigned/signed URL for file access */
86
+ getSignedUrl: (options: PresignedUrlOptions) => Promise<PresignedUrlResult>;
87
+ /** Check if adapter is available */
88
+ isAvailable: () => boolean;
89
+ /** Perform health check on adapter */
90
+ healthCheck: () => Promise<AdapterHealthCheck>;
91
+ /** Get file metadata */
92
+ getFileMetadata: (fileId: string, bucket?: string) => Promise<FileMetadata>;
93
+ /** Restore a soft-deleted file */
94
+ restoreFile?: (fileId: string) => Promise<FileMetadata>;
95
+ /** List files with optional filters */
96
+ listFiles?: (params: StorageListFilesParams) => Promise<StorageListFilesResult>;
97
+ /** Copy a file */
98
+ copyFile?: (params: StorageCopyFileParams) => Promise<FileMetadata>;
99
+ /** Move a file */
100
+ moveFile?: (params: StorageMoveFileParams) => Promise<FileMetadata>;
101
+ /** Replace a file */
102
+ replaceFile?: (params: StorageReplaceFileParams) => Promise<FileMetadata>;
103
+ }
104
+ /**
105
+ * Plugin lifecycle hook context
106
+ * Provides information about the current operation to plugins
107
+ */
108
+ export interface StoragePluginContext {
109
+ /** Operation type (upload, delete, access, etc.) */
110
+ operation: 'upload' | 'delete' | 'access' | 'update';
111
+ /** Timestamp when operation started */
112
+ timestamp: Date;
113
+ /** User ID performing the operation (if available) */
114
+ userId?: string;
115
+ /** Request correlation ID for tracing */
116
+ correlationId?: string;
117
+ /** Storage adapter for file operations - provides access to all public storage methods */
118
+ storageAdapter: PluginStorageAdapterInterface;
119
+ /** Additional context metadata */
120
+ metadata?: Record<string, unknown>;
121
+ }
122
+ /**
123
+ * Result from beforeUpload hook
124
+ * Can modify metadata or reject the upload
125
+ */
126
+ export interface BeforeUploadResult {
127
+ /** Whether to allow the upload */
128
+ allowed: boolean;
129
+ /** Reason if upload is rejected */
130
+ reason?: string;
131
+ /** Modified file (if plugin wants to return modified file) */
132
+ file?: StoragePluginFile;
133
+ /** Modified metadata (if plugin wants to add/modify) */
134
+ modifiedMetadata?: Partial<FileMetadata>;
135
+ /** Additional data to pass to afterUpload hooks */
136
+ pluginData?: Record<string, unknown>;
137
+ }
138
+ /**
139
+ * Result from beforeDelete hook
140
+ * Can prevent deletion
141
+ */
142
+ export interface BeforeDeleteResult {
143
+ /** Whether to allow the deletion */
144
+ allowed: boolean;
145
+ /** Reason if deletion is rejected */
146
+ reason?: string;
147
+ /** Additional data to pass to afterDelete hooks */
148
+ pluginData?: Record<string, unknown>;
149
+ }
150
+ /**
151
+ * File buffer with metadata for plugin hooks
152
+ */
153
+ export interface StoragePluginFile {
154
+ /** File buffer */
155
+ buffer: globalThis.Buffer;
156
+ /** File metadata */
157
+ metadata: FileMetadata;
158
+ /** Original filename */
159
+ filename: string;
160
+ /** MIME type */
161
+ mimeType: string;
162
+ /** File size in bytes */
163
+ size: number;
164
+ /** Custom metadata that plugins can add */
165
+ customMetadata?: Record<string, unknown>;
166
+ }
167
+ /**
168
+ * Upload result passed to afterUpload hooks
169
+ */
170
+ export interface StoragePluginUploadResult {
171
+ /** Uploaded file ID */
172
+ fileId: string;
173
+ /** Public URL to access the file */
174
+ url: string;
175
+ /** CDN URL (if applicable) */
176
+ cdnUrl?: string;
177
+ /** File metadata */
178
+ metadata: FileMetadata;
179
+ /** Storage adapter that handled the upload */
180
+ adapter: string;
181
+ /** Upload duration in milliseconds */
182
+ duration: number;
183
+ /** Data passed from beforeUpload hooks */
184
+ pluginData?: Record<string, unknown>;
185
+ }
186
+ /**
187
+ * Delete result passed to afterDelete hooks
188
+ */
189
+ export interface StoragePluginDeleteResult {
190
+ /** Deleted file ID */
191
+ fileId: string;
192
+ /** File metadata (before deletion) */
193
+ metadata: FileMetadata;
194
+ /** Whether it was a soft delete */
195
+ softDelete: boolean;
196
+ /** Deletion timestamp */
197
+ deletedAt: Date;
198
+ /** Data passed from beforeDelete hooks */
199
+ pluginData?: Record<string, unknown>;
200
+ }
201
+ /**
202
+ * Access event passed to onAccess hooks
203
+ */
204
+ export interface StoragePluginAccessEvent {
205
+ /** Accessed file ID */
206
+ fileId: string;
207
+ /** User ID who accessed the file */
208
+ userId: string;
209
+ /** Access type (download, view, preview, etc.) */
210
+ accessType: 'download' | 'view' | 'preview' | 'stream' | 'other';
211
+ /** Access timestamp */
212
+ timestamp: Date;
213
+ /** File metadata */
214
+ metadata?: FileMetadata;
215
+ /** IP address of the accessor */
216
+ ipAddress?: string;
217
+ /** User agent */
218
+ userAgent?: string;
219
+ }
220
+ /**
221
+ * Plugin health status
222
+ */
223
+ export interface StoragePluginHealth {
224
+ /** Plugin name */
225
+ plugin: StorageKnownPluginName;
226
+ /** Whether the plugin is healthy */
227
+ healthy: boolean;
228
+ /** Status message */
229
+ message?: string;
230
+ /** Last check timestamp */
231
+ lastCheck: Date;
232
+ /** Error details if unhealthy */
233
+ error?: {
234
+ code: string;
235
+ message: string;
236
+ stack?: string;
237
+ };
238
+ }
239
+ /**
240
+ * Base Storage Plugin Interface
241
+ * All plugins must implement this interface
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * class VirusScanPlugin implements StoragePlugin {
246
+ * readonly name = 'virus-scan';
247
+ * readonly type = STORAGE_PLUGIN_TYPE.SECURITY;
248
+ * readonly priority = 10; // Run first
249
+ *
250
+ * async beforeUpload(file: StoragePluginFile, context: StoragePluginContext): Promise<BeforeUploadResult> {
251
+ * const scanResult = await this.scanFile(file.buffer);
252
+ * if (scanResult.infected) {
253
+ * return {
254
+ * allowed: false,
255
+ * reason: `Virus detected: ${scanResult.virusName}`,
256
+ * };
257
+ * }
258
+ * return { allowed: true };
259
+ * }
260
+ * }
261
+ * ```
262
+ */
263
+ export interface StoragePlugin {
264
+ /** Unique plugin name (lowercase-with-dashes) */
265
+ readonly name: StorageKnownPluginName;
266
+ /** Plugin type for categorization */
267
+ readonly type: STORAGE_PLUGIN_TYPE;
268
+ /**
269
+ * Plugin priority (1-100)
270
+ * Lower numbers run first
271
+ * Security plugins typically use 1-20
272
+ * Metadata plugins typically use 21-40
273
+ * Other plugins typically use 41-100
274
+ */
275
+ readonly priority: number;
276
+ /** Plugin version */
277
+ readonly version?: string;
278
+ /** Plugin description */
279
+ readonly description?: string;
280
+ /** Whether the plugin is enabled */
281
+ enabled?: boolean;
282
+ /**
283
+ * Initialize the plugin
284
+ * Called once when plugin is registered
285
+ * Use this to setup connections, validate configuration, etc.
286
+ */
287
+ initialize?(): Promise<void>;
288
+ /**
289
+ * Cleanup the plugin
290
+ * Called when plugin is destroyed
291
+ * Use this to close connections, release resources, etc.
292
+ */
293
+ destroy?(): Promise<void>;
294
+ /**
295
+ * Check plugin health
296
+ * Used for monitoring and diagnostics
297
+ */
298
+ healthCheck?(): Promise<StoragePluginHealth>;
299
+ /**
300
+ * PRE-UPLOAD HOOK (BLOCKING)
301
+ * Called BEFORE file is uploaded to storage
302
+ * Can reject upload by returning { allowed: false }
303
+ * Can modify metadata by returning { modifiedMetadata: {...} }
304
+ *
305
+ * @param file - File to be uploaded with metadata
306
+ * @param context - Operation context
307
+ * @returns Result indicating whether to allow upload and any modifications
308
+ */
309
+ beforeUpload?(file: StoragePluginFile, context: StoragePluginContext): Promise<BeforeUploadResult>;
310
+ /**
311
+ * POST-UPLOAD HOOK (ASYNC)
312
+ * Called AFTER file is successfully uploaded to storage
313
+ * Runs asynchronously, doesn't block the upload response
314
+ * Use for metadata extraction, CDN invalidation, audit logging, etc.
315
+ *
316
+ * @param result - Upload result with file ID and metadata
317
+ * @param context - Operation context
318
+ */
319
+ afterUpload?(result: StoragePluginUploadResult, context: StoragePluginContext): Promise<void>;
320
+ /**
321
+ * PRE-DELETE HOOK (BLOCKING)
322
+ * Called BEFORE file is deleted from storage
323
+ * Can prevent deletion by returning { allowed: false }
324
+ *
325
+ * @param fileId - File ID to be deleted
326
+ * @param metadata - File metadata (if available)
327
+ * @param context - Operation context
328
+ * @returns Result indicating whether to allow deletion
329
+ */
330
+ beforeDelete?(fileId: string, metadata: FileMetadata | undefined, context: StoragePluginContext): Promise<BeforeDeleteResult>;
331
+ /**
332
+ * POST-DELETE HOOK (ASYNC)
333
+ * Called AFTER file is deleted from storage
334
+ * Runs asynchronously, doesn't block the delete response
335
+ * Use for CDN cache purging, audit logging, cleanup, etc.
336
+ *
337
+ * @param result - Delete result with file ID and metadata
338
+ * @param context - Operation context
339
+ */
340
+ afterDelete?(result: StoragePluginDeleteResult, context: StoragePluginContext): Promise<void>;
341
+ /**
342
+ * ON-ACCESS HOOK (ASYNC)
343
+ * Called when a file is accessed (downloaded, viewed, etc.)
344
+ * Runs asynchronously, doesn't block the access
345
+ * Use for access logging, analytics, compliance tracking, etc.
346
+ *
347
+ * @param event - Access event details
348
+ * @param context - Operation context
349
+ */
350
+ onAccess?(event: StoragePluginAccessEvent, context: StoragePluginContext): Promise<void>;
351
+ }
352
+ /**
353
+ * Plugin configuration
354
+ * Used to configure a plugin instance
355
+ */
356
+ export interface StoragePluginConfig {
357
+ /** Plugin instance */
358
+ plugin: StoragePlugin;
359
+ /** Whether the plugin is enabled */
360
+ enabled?: boolean;
361
+ /** Override priority */
362
+ priority?: number;
363
+ /** Additional configuration */
364
+ config?: Record<string, unknown>;
365
+ }
366
+ /**
367
+ * Plugin execution result
368
+ * Returned by plugin registry after executing hooks
369
+ */
370
+ export interface StoragePluginExecutionResult {
371
+ /** Whether all plugins allowed the operation */
372
+ allowed: boolean;
373
+ /** Reason if operation was rejected */
374
+ reason?: string;
375
+ /** Plugin that rejected the operation */
376
+ rejectedBy?: string;
377
+ /** Modified metadata from plugins */
378
+ modifiedMetadata?: Partial<FileMetadata>;
379
+ /** Plugin data to pass to subsequent hooks */
380
+ pluginData?: Record<string, unknown>;
381
+ /** Execution duration in milliseconds */
382
+ duration: number;
383
+ /** Number of plugins executed */
384
+ pluginsExecuted: number;
385
+ /** Errors from plugins (non-fatal) */
386
+ errors?: Array<{
387
+ plugin: string;
388
+ error: Error;
389
+ }>;
390
+ }
391
+ /**
392
+ * Virus scan result
393
+ */
394
+ export interface VirusScanResult {
395
+ /** Whether the file is clean (no threats detected) */
396
+ clean: boolean;
397
+ /** Whether the file is infected with malware */
398
+ infected: boolean;
399
+ /** Name of the virus/malware detected (if any) */
400
+ virusName?: string;
401
+ /** Scan duration in milliseconds */
402
+ scanTime: number;
403
+ /** Timestamp when scan was performed */
404
+ scanDate: Date;
405
+ /** Scan confidence score (0-100) */
406
+ confidence?: number;
407
+ /** Additional scan metadata from the provider */
408
+ metadata?: Record<string, unknown>;
409
+ /** Provider-specific scan ID for tracking */
410
+ scanId?: string;
411
+ /** Detailed threat information */
412
+ threats?: VirusThreat[];
413
+ }
414
+ /**
415
+ * Detailed threat information
416
+ */
417
+ export interface VirusThreat {
418
+ /** Threat name/signature */
419
+ name: string;
420
+ /** Threat type (virus, trojan, ransomware, etc.) */
421
+ type?: string;
422
+ /** Threat severity (low, medium, high, critical) */
423
+ severity?: 'low' | 'medium' | 'high' | 'critical';
424
+ /** Detection engine that found this threat */
425
+ engine?: string;
426
+ }
427
+ /**
428
+ * Base virus scan provider configuration
429
+ * Common configuration for all virus scanning providers
430
+ */
431
+ export interface VirusScanProviderConfig {
432
+ /** API key or authentication token */
433
+ apiKey?: string;
434
+ /** Provider API endpoint (baseURL) */
435
+ endpoint?: string;
436
+ /** Request timeout in milliseconds */
437
+ timeout?: number;
438
+ /** Maximum file size to scan (in bytes) */
439
+ maxFileSize?: number;
440
+ /** Enable verbose logging */
441
+ verbose?: boolean;
442
+ /** Additional provider-specific options */
443
+ options?: Record<string, unknown>;
444
+ }
445
+ /**
446
+ * Base virus scan provider interface
447
+ * All virus scan providers must implement this interface
448
+ */
449
+ export interface VirusScanProvider {
450
+ /** Provider name */
451
+ readonly providerName: string;
452
+ /**
453
+ * Scan a file for viruses/malware
454
+ * @param file - File buffer to scan
455
+ * @param filename - Original filename (for context)
456
+ * @returns Scan result with threat information
457
+ */
458
+ scan(file: globalThis.Buffer, filename: string): Promise<VirusScanResult>;
459
+ /**
460
+ * Check if provider is available and healthy
461
+ * @returns True if provider can accept scan requests
462
+ */
463
+ isAvailable(): Promise<boolean>;
464
+ /**
465
+ * Get provider statistics (optional)
466
+ * @returns Provider usage statistics
467
+ */
468
+ getStatistics?(): Promise<{
469
+ scansPerformed: number;
470
+ threatsDetected: number;
471
+ averageScanTime: number;
472
+ }>;
473
+ }
474
+ /**
475
+ * Virus scan plugin configuration
476
+ */
477
+ export interface VirusScanPluginConfig extends Omit<BasePluginConfig, 'name' | 'type'> {
478
+ /** Virus scan provider instance */
479
+ provider: VirusScanProvider;
480
+ /** API key for the provider (for REST-based providers like VirusTotal) */
481
+ apiKey?: string;
482
+ /** Provider API endpoint (for REST-based providers) */
483
+ apiEndpoint?: string;
484
+ /** Reject upload if scan fails (default: true) */
485
+ rejectOnError?: boolean;
486
+ /** Skip scan for files above this size (bytes, default: no limit) */
487
+ skipAboveSize?: number;
488
+ /** File extensions to skip scanning (e.g., ['.txt', '.md']) */
489
+ skipExtensions?: string[];
490
+ }
491
+ /**
492
+ * VirusTotal provider configuration
493
+ * @see VirusTotalProvider in @plyaz/storage/plugins
494
+ * Note: API key and endpoint are configured at the plugin level
495
+ */
496
+ export interface VirusTotalProviderConfig extends VirusScanProviderConfig {
497
+ /** Wait for scan to complete (default: true) */
498
+ waitForResult?: boolean;
499
+ /** Maximum wait time for scan results in milliseconds (default: 60000) */
500
+ maxWaitTime?: number;
501
+ /** Poll interval for checking scan status in milliseconds (default: 5000) */
502
+ pollInterval?: number;
503
+ }
504
+ /**
505
+ * ClamAV provider configuration for virus scanning
506
+ * @see ClamAVProvider in @plyaz/storage/plugins
507
+ */
508
+ export interface ClamAVProviderConfig extends VirusScanProviderConfig {
509
+ /** ClamAV daemon host (default: 'localhost') */
510
+ host?: string;
511
+ /** ClamAV daemon port (default: 3310) */
512
+ port?: number;
513
+ /** Socket path for Unix domain socket (alternative to host/port) */
514
+ socketPath?: string;
515
+ /** Enable quarantine for infected files (default: false) */
516
+ enableQuarantine?: boolean;
517
+ /** Quarantine directory path (default: './quarantine') */
518
+ quarantinePath?: string;
519
+ /** Enable streaming scan mode (default: true for better performance) */
520
+ streamScan?: boolean;
521
+ }
522
+ /**
523
+ * Image variant configuration for Sharp image processing
524
+ * @see SharpImagePlugin in @plyaz/storage/plugins
525
+ */
526
+ export interface ImageVariant {
527
+ /** Variant name (thumbnail, medium, large, etc.) */
528
+ name: string;
529
+ /** Target width in pixels */
530
+ width?: number;
531
+ /** Target height in pixels */
532
+ height?: number;
533
+ /** Resize fit mode */
534
+ fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
535
+ /** Resize position (when fit is 'cover' or 'contain') */
536
+ position?: 'center' | 'top' | 'right top' | 'right' | 'right bottom' | 'bottom' | 'left bottom' | 'left' | 'left top';
537
+ /** Custom quality for this variant (overrides global quality) */
538
+ quality?: number;
539
+ /** Custom format for this variant */
540
+ format?: 'jpeg' | 'png' | 'webp' | 'avif';
541
+ }
542
+ /**
543
+ * Watermark configuration for Sharp image processing
544
+ * @see SharpImagePlugin in @plyaz/storage/plugins
545
+ */
546
+ export interface WatermarkConfig {
547
+ /** Enable watermarking */
548
+ enabled: boolean;
549
+ /** Path to watermark image file */
550
+ imagePath?: string;
551
+ /** Watermark image buffer (alternative to imagePath) */
552
+ imageBuffer?: globalThis.Buffer;
553
+ /** Watermark opacity (0-1) */
554
+ opacity?: number;
555
+ /** Watermark position */
556
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center';
557
+ /** Watermark size as percentage of image (default: 20%) */
558
+ size?: number;
559
+ }
560
+ /**
561
+ * Sharp Image Plugin configuration
562
+ * @see SharpImagePlugin in @plyaz/storage/plugins
563
+ */
564
+ export interface SharpImagePluginConfig {
565
+ /** Image variants to generate */
566
+ variants?: ImageVariant[];
567
+ /** Output formats to generate (default: ['webp', 'jpeg']) */
568
+ formats?: Array<'jpeg' | 'png' | 'webp' | 'avif'>;
569
+ /** JPEG/WEBP quality (1-100, default: 85) */
570
+ quality?: number;
571
+ /** Strip metadata (EXIF) for privacy (default: true) */
572
+ stripMetadata?: boolean;
573
+ /** Watermark configuration */
574
+ watermark?: WatermarkConfig;
575
+ /** Only process these MIME types (default: all image/* types) */
576
+ supportedMimeTypes?: string[];
577
+ /** Upload variants back to storage (default: true) */
578
+ uploadVariants?: boolean;
579
+ /** Preserve original file (default: true) */
580
+ preserveOriginal?: boolean;
581
+ /** Plugin priority (1-100, lower runs first) */
582
+ priority?: number;
583
+ /** Plugin version */
584
+ version?: string;
585
+ /** Plugin description */
586
+ description?: string;
587
+ /** Whether the plugin is enabled */
588
+ enabled?: boolean;
589
+ /** Logger instance */
590
+ logger?: unknown;
591
+ }
592
+ /**
593
+ * Video resolution configuration for FFmpeg video processing
594
+ * @see FFmpegVideoPlugin in @plyaz/storage/plugins
595
+ */
596
+ export interface VideoResolution {
597
+ /** Resolution name (480p, 720p, 1080p, 4k) */
598
+ name: string;
599
+ /** Target width in pixels */
600
+ width: number;
601
+ /** Target height in pixels */
602
+ height: number;
603
+ /** Video bitrate (e.g., '1000k', '2500k') */
604
+ bitrate: string;
605
+ /** Video codec (e.g., 'libx264', 'libx265') */
606
+ codec?: string;
607
+ /** Audio codec (e.g., 'aac', 'mp3') */
608
+ audioCodec?: string;
609
+ /** Audio bitrate (e.g., '128k') */
610
+ audioBitrate?: string;
611
+ }
612
+ /**
613
+ * Thumbnail generation configuration for FFmpeg video processing
614
+ * @see FFmpegVideoPlugin in @plyaz/storage/plugins
615
+ */
616
+ export interface ThumbnailConfig {
617
+ /** Number of thumbnails to generate */
618
+ count: number;
619
+ /** Timestamps as percentage of duration (0-1) */
620
+ timestamps: number[];
621
+ /** Thumbnail format (jpeg, png) */
622
+ format?: 'jpeg' | 'png';
623
+ /** Thumbnail quality (1-100) */
624
+ quality?: number;
625
+ /** Thumbnail width (height auto-calculated) */
626
+ width?: number;
627
+ /** Thumbnail size (width x height) */
628
+ size?: {
629
+ width: number;
630
+ height: number;
631
+ };
632
+ }
633
+ /**
634
+ * HLS streaming configuration for FFmpeg video processing
635
+ * @see FFmpegVideoPlugin in @plyaz/storage/plugins
636
+ */
637
+ export interface HLSConfig {
638
+ /** Enable HLS streaming */
639
+ enabled: boolean;
640
+ /** Segment duration in seconds */
641
+ segmentDuration?: number;
642
+ /** Variant bitrates for adaptive streaming */
643
+ variantBitrates?: string[];
644
+ }
645
+ /**
646
+ * FFmpeg Video Plugin configuration
647
+ * @see FFmpegVideoPlugin in @plyaz/storage/plugins
648
+ */
649
+ export interface FFmpegVideoPluginConfig {
650
+ /** Path to ffmpeg binary */
651
+ ffmpegPath?: string;
652
+ /** Path to ffprobe binary */
653
+ ffprobePath?: string;
654
+ /** Video resolutions to generate */
655
+ resolutions?: VideoResolution[];
656
+ /** Thumbnail configuration */
657
+ thumbnails?: ThumbnailConfig;
658
+ /** HLS streaming configuration */
659
+ hls?: HLSConfig;
660
+ /** Process in background queue */
661
+ useQueue?: boolean;
662
+ /** Only process these MIME types */
663
+ supportedMimeTypes?: string[];
664
+ /** Upload variants back to storage */
665
+ uploadVariants?: boolean;
666
+ /** Plugin priority (1-100, lower runs first) */
667
+ priority?: number;
668
+ /** Plugin version */
669
+ version?: string;
670
+ /** Plugin description */
671
+ description?: string;
672
+ /** Whether the plugin is enabled */
673
+ enabled?: boolean;
674
+ /** Logger instance */
675
+ logger?: unknown;
676
+ }
677
+ /**
678
+ * Extracted metadata structure
679
+ */
680
+ export interface ExtractedMetadata {
681
+ /** File type category */
682
+ category: 'image' | 'audio' | 'video' | 'document' | 'other';
683
+ /** Image EXIF data */
684
+ exif?: {
685
+ make?: string;
686
+ model?: string;
687
+ software?: string;
688
+ dateTime?: string;
689
+ exposureTime?: number;
690
+ fNumber?: number;
691
+ iso?: number;
692
+ focalLength?: number;
693
+ flash?: number;
694
+ whiteBalance?: number;
695
+ orientation?: number;
696
+ xResolution?: number;
697
+ yResolution?: number;
698
+ resolutionUnit?: number;
699
+ gps?: {
700
+ latitude?: number;
701
+ longitude?: number;
702
+ altitude?: number;
703
+ };
704
+ };
705
+ /** Audio ID3 tags */
706
+ id3?: {
707
+ title?: string;
708
+ artist?: string;
709
+ album?: string;
710
+ year?: number;
711
+ genre?: string;
712
+ trackNumber?: number;
713
+ albumArtist?: string;
714
+ composer?: string;
715
+ duration?: number;
716
+ bitrate?: number;
717
+ sampleRate?: number;
718
+ codec?: string;
719
+ };
720
+ /** Video metadata */
721
+ video?: {
722
+ duration?: number;
723
+ width?: number;
724
+ height?: number;
725
+ codec?: string;
726
+ bitrate?: number;
727
+ fps?: number;
728
+ audioCodec?: string;
729
+ format?: string;
730
+ };
731
+ /** Document metadata */
732
+ document?: {
733
+ title?: string;
734
+ author?: string;
735
+ subject?: string;
736
+ creator?: string;
737
+ producer?: string;
738
+ creationDate?: string;
739
+ modificationDate?: string;
740
+ pageCount?: number;
741
+ };
742
+ }
743
+ /**
744
+ * Metadata Extraction Plugin configuration
745
+ */
746
+ export interface MetadataExtractionPluginConfig {
747
+ /** Extract EXIF data from images */
748
+ extractExif?: boolean;
749
+ /** Extract ID3 tags from audio files */
750
+ extractId3?: boolean;
751
+ /** Extract metadata from videos */
752
+ extractVideoMeta?: boolean;
753
+ /** Extract metadata from documents */
754
+ extractDocMeta?: boolean;
755
+ /** Strip sensitive data (GPS, serial numbers) */
756
+ stripSensitiveData?: boolean;
757
+ /** Preserve original metadata in files */
758
+ preserveOriginal?: boolean;
759
+ /** Supported file mime types */
760
+ supportedMimeTypes?: string[];
761
+ priority?: number;
762
+ version?: string;
763
+ description?: string;
764
+ enabled?: boolean;
765
+ logger?: unknown;
766
+ }
767
+ /**
768
+ * CDN Provider Types
769
+ */
770
+ export type CDNProviderType = 'cloudflare' | 'cloudfront' | 'fastly';
771
+ /**
772
+ * Base CDN Provider Configuration
773
+ */
774
+ export interface BaseCDNProviderConfig {
775
+ /** CDN provider type */
776
+ type: CDNProviderType;
777
+ /** Base URL pattern for generating cache URLs */
778
+ baseUrl?: string;
779
+ }
780
+ /**
781
+ * Cloudflare CDN Configuration
782
+ */
783
+ export interface CloudflareCDNConfig extends BaseCDNProviderConfig {
784
+ type: 'cloudflare';
785
+ /** Cloudflare Zone ID */
786
+ zoneId: string;
787
+ /** Cloudflare API Token */
788
+ apiToken: string;
789
+ }
790
+ /**
791
+ * AWS CloudFront Configuration
792
+ */
793
+ export interface CloudFrontCDNConfig extends BaseCDNProviderConfig {
794
+ type: 'cloudfront';
795
+ /** CloudFront Distribution ID */
796
+ distributionId: string;
797
+ /** AWS Access Key ID */
798
+ accessKeyId: string;
799
+ /** AWS Secret Access Key */
800
+ secretAccessKey: string;
801
+ /** AWS Region */
802
+ region?: string;
803
+ }
804
+ /**
805
+ * Fastly CDN Configuration
806
+ */
807
+ export interface FastlyCDNConfig extends BaseCDNProviderConfig {
808
+ type: 'fastly';
809
+ /** Fastly Service ID */
810
+ serviceId: string;
811
+ /** Fastly API Key */
812
+ apiKey: string;
813
+ }
814
+ /**
815
+ * CDN Provider Configuration Union
816
+ */
817
+ export type CDNProviderConfig = CloudflareCDNConfig | CloudFrontCDNConfig | FastlyCDNConfig;
818
+ /**
819
+ * CDN Invalidation Plugin Configuration
820
+ */
821
+ export interface CDNInvalidationPluginConfig {
822
+ /** CDN provider configurations */
823
+ providers: CDNProviderConfig[];
824
+ /** Maximum URLs per invalidation request */
825
+ batchSize?: number;
826
+ /** Number of retry attempts on failure */
827
+ retryAttempts?: number;
828
+ /** Retry delay in milliseconds */
829
+ retryDelay?: number;
830
+ /** Enable invalidation on delete */
831
+ invalidateOnDelete?: boolean;
832
+ /** Enable invalidation on update */
833
+ invalidateOnUpdate?: boolean;
834
+ /** URL pattern generator function */
835
+ urlGenerator?: (fileId: string, filename: string) => string[];
836
+ priority?: number;
837
+ version?: string;
838
+ description?: string;
839
+ enabled?: boolean;
840
+ logger?: unknown;
841
+ }
842
+ /**
843
+ * Cloudflare CDN Plugin Configuration
844
+ */
845
+ export interface CloudflareCDNPluginConfig {
846
+ /** Cloudflare Zone ID */
847
+ zoneId: string;
848
+ /** Cloudflare API Token with Cache Purge permission */
849
+ apiToken: string;
850
+ /** Base URL for CDN (optional) */
851
+ baseUrl?: string;
852
+ /** Maximum URLs per purge request (default: 30) */
853
+ batchSize?: number;
854
+ /** Number of retry attempts on failure (default: 3) */
855
+ retryAttempts?: number;
856
+ /** Retry delay in milliseconds (default: 1000) */
857
+ retryDelay?: number;
858
+ /** Enable invalidation on delete (default: true) */
859
+ invalidateOnDelete?: boolean;
860
+ /** Enable invalidation on update (default: true) */
861
+ invalidateOnUpdate?: boolean;
862
+ /** URL generator function */
863
+ urlGenerator?: (fileId: string, filename: string) => string[];
864
+ priority?: number;
865
+ version?: string;
866
+ description?: string;
867
+ enabled?: boolean;
868
+ logger?: unknown;
869
+ }
870
+ /**
871
+ * CloudFront CDN Plugin Configuration
872
+ */
873
+ export interface CloudFrontCDNPluginConfig {
874
+ /** CloudFront Distribution ID */
875
+ distributionId: string;
876
+ /** AWS Access Key ID */
877
+ accessKeyId: string;
878
+ /** AWS Secret Access Key */
879
+ secretAccessKey: string;
880
+ /** AWS Region (default: us-east-1) */
881
+ region?: string;
882
+ /** Base URL for CDN (optional) */
883
+ baseUrl?: string;
884
+ /** Maximum paths per invalidation (default: 1000) */
885
+ batchSize?: number;
886
+ /** Number of retry attempts on failure (default: 3) */
887
+ retryAttempts?: number;
888
+ /** Retry delay in milliseconds (default: 1000) */
889
+ retryDelay?: number;
890
+ /** Enable invalidation on delete (default: true) */
891
+ invalidateOnDelete?: boolean;
892
+ /** Enable invalidation on update (default: true) */
893
+ invalidateOnUpdate?: boolean;
894
+ /** Path generator function */
895
+ pathGenerator?: (fileId: string, filename: string) => string[];
896
+ priority?: number;
897
+ version?: string;
898
+ description?: string;
899
+ enabled?: boolean;
900
+ logger?: unknown;
901
+ }
902
+ /**
903
+ * Fastly CDN Plugin Configuration
904
+ */
905
+ export interface FastlyCDNPluginConfig {
906
+ /** Fastly Service ID */
907
+ serviceId: string;
908
+ /** Fastly API Token with Purge permission */
909
+ apiToken: string;
910
+ /** Base URL for CDN (optional) */
911
+ baseUrl?: string;
912
+ /** Number of retry attempts on failure (default: 3) */
913
+ retryAttempts?: number;
914
+ /** Retry delay in milliseconds (default: 1000) */
915
+ retryDelay?: number;
916
+ /** Enable invalidation on delete (default: true) */
917
+ invalidateOnDelete?: boolean;
918
+ /** Enable invalidation on update (default: true) */
919
+ invalidateOnUpdate?: boolean;
920
+ /** URL generator function */
921
+ urlGenerator?: (fileId: string, filename: string) => string[];
922
+ priority?: number;
923
+ version?: string;
924
+ description?: string;
925
+ enabled?: boolean;
926
+ logger?: unknown;
927
+ }
928
+ /**
929
+ * CDN Invalidation Result
930
+ */
931
+ export interface CDNInvalidationResult {
932
+ /** CDN provider type */
933
+ provider: CDNProviderType;
934
+ /** Whether invalidation was successful */
935
+ success: boolean;
936
+ /** URLs that were invalidated */
937
+ urls: string[];
938
+ /** Error message if failed */
939
+ error?: string;
940
+ /** Invalidation ID from CDN provider */
941
+ invalidationId?: string;
942
+ }
943
+ /**
944
+ * CDN Plugin Statistics
945
+ * Statistics for CDN invalidation operations
946
+ */
947
+ export interface StorageCDNPluginStatistics {
948
+ /** Total number of successful invalidations performed */
949
+ invalidationsPerformed: number;
950
+ /** Total number of failed invalidations */
951
+ invalidationsFailed: number;
952
+ /** Total number of URLs/paths invalidated (use one or both depending on CDN) */
953
+ urlsInvalidated?: number;
954
+ pathsInvalidated?: number;
955
+ /** Number of queued URLs/paths waiting to be invalidated (use one or both depending on CDN) */
956
+ queuedUrls?: number;
957
+ queuedPaths?: number;
958
+ }
959
+ /**
960
+ * Image Processing Plugin Statistics
961
+ * Statistics for image processing operations
962
+ */
963
+ export interface StorageImageProcessingPluginStatistics {
964
+ /** Total number of images processed */
965
+ imagesProcessed: number;
966
+ /** Total number of variants generated */
967
+ variantsGenerated: number;
968
+ /** Average number of variants generated per image */
969
+ averageVariantsPerImage: number;
970
+ }
971
+ /**
972
+ * Metadata Extraction Plugin Statistics
973
+ * Statistics for metadata extraction operations
974
+ */
975
+ export interface StorageMetadataExtractionPluginStatistics {
976
+ /** Total number of files with metadata extracted */
977
+ filesProcessed: number;
978
+ /** Success rate as a percentage (0-100) */
979
+ successRate: number;
980
+ metadataExtracted?: number;
981
+ }
982
+ /**
983
+ * Video Processing Plugin Statistics
984
+ * Statistics for video processing operations
985
+ */
986
+ export interface StorageVideoProcessingPluginStatistics {
987
+ /** Total number of videos processed */
988
+ videosProcessed: number;
989
+ /** Total number of thumbnails generated */
990
+ thumbnailsGenerated?: number;
991
+ /** Average thumbnails per video */
992
+ averageThumbnailsPerVideo?: number;
993
+ /** Total number of variants generated */
994
+ variantsGenerated: number;
995
+ averageVariantsPerVideo?: number;
996
+ }
997
+ /**
998
+ * FFmpeg/FFprobe Types
999
+ * Types for video processing using FFmpeg
1000
+ */
1001
+ /**
1002
+ * FFprobe stream information
1003
+ */
1004
+ export interface FFprobeStream {
1005
+ codec_type?: string;
1006
+ codec_name?: string;
1007
+ width?: number;
1008
+ height?: number;
1009
+ duration?: string;
1010
+ bit_rate?: string;
1011
+ r_frame_rate?: string;
1012
+ }
1013
+ /**
1014
+ * FFprobe format information
1015
+ */
1016
+ export interface FFprobeFormat {
1017
+ duration?: number;
1018
+ bit_rate?: number | string;
1019
+ size?: string;
1020
+ format_name?: string;
1021
+ }
1022
+ /**
1023
+ * FFprobe output data
1024
+ */
1025
+ export interface FFprobeData {
1026
+ streams: FFprobeStream[];
1027
+ format: FFprobeFormat;
1028
+ }
1029
+ /**
1030
+ * FFmpeg progress information
1031
+ */
1032
+ export interface FFmpegProgress {
1033
+ percent?: number;
1034
+ currentTime?: number;
1035
+ targetSize?: number;
1036
+ timemark?: string;
1037
+ }
1038
+ /**
1039
+ * FFmpeg command options
1040
+ */
1041
+ export interface FFmpegOptions {
1042
+ input: string;
1043
+ output: string;
1044
+ args: string[];
1045
+ onProgress?: (progress: FFmpegProgress) => void;
1046
+ onStart?: (command: string) => void;
1047
+ }
1048
+ /**
1049
+ * Screenshot options for FFmpeg
1050
+ */
1051
+ export interface ScreenshotOptions {
1052
+ timestamps: number[];
1053
+ folder: string;
1054
+ filename: string;
1055
+ size?: string;
1056
+ }