@shipstatic/drop 0.1.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.
@@ -0,0 +1,200 @@
1
+ import { ConfigResponse, StaticFile } from '@shipstatic/types';
2
+
3
+ /**
4
+ * Core types for @shipstatic/dropzone
5
+ * Imports types from @shipstatic/types (single source of truth)
6
+ * and defines dropzone-specific types
7
+ */
8
+
9
+ declare const FILE_STATUSES: {
10
+ readonly PENDING: "pending";
11
+ readonly PROCESSING: "processing";
12
+ readonly VALIDATION_FAILED: "validation_failed";
13
+ readonly PROCESSING_ERROR: "processing_error";
14
+ readonly EMPTY_FILE: "empty_file";
15
+ readonly READY: "ready";
16
+ readonly UPLOADING: "uploading";
17
+ readonly COMPLETE: "complete";
18
+ readonly ERROR: "error";
19
+ };
20
+ type FileStatus = (typeof FILE_STATUSES)[keyof typeof FILE_STATUSES];
21
+ /**
22
+ * Client-side error structure
23
+ */
24
+ interface ClientError {
25
+ error: string;
26
+ details: string;
27
+ isClientError: true;
28
+ }
29
+ /**
30
+ * Processed file entry ready for upload
31
+ * Extends StaticFile from SDK, adding UI-specific properties
32
+ * This means ProcessedFile IS a StaticFile - can be passed directly to ship.deployments.create()
33
+ */
34
+ interface ProcessedFile extends StaticFile {
35
+ /** Unique identifier for React keys and tracking */
36
+ id: string;
37
+ /** Original File object (alias for 'content' from StaticFile for better DX) */
38
+ file: File;
39
+ /** Filename without path */
40
+ name: string;
41
+ /** MIME type for UI icons/previews */
42
+ type: string;
43
+ /** Last modified timestamp */
44
+ lastModified: number;
45
+ /** Current processing/upload status */
46
+ status: FileStatus;
47
+ /** Human-readable status message for UI */
48
+ statusMessage?: string;
49
+ /** Upload progress (0-100) - only set during upload */
50
+ progress?: number;
51
+ }
52
+ /**
53
+ * Validation configuration - direct alias to SDK's ConfigResponse
54
+ * This allows passing the config directly from ship.getConfig() to the dropzone
55
+ *
56
+ * Single source of truth: @shipstatic/types
57
+ */
58
+ type ValidationConfig = ConfigResponse;
59
+ /**
60
+ * Default validation limits
61
+ */
62
+ declare const DEFAULT_VALIDATION: ConfigResponse;
63
+
64
+ interface DropzoneManagerOptions {
65
+ /** Validation configuration (from ship.getConfig()) */
66
+ config?: Partial<ValidationConfig>;
67
+ /** Callback when validation fails */
68
+ onValidationError?: (error: ClientError) => void;
69
+ /** Callback when files are ready for upload */
70
+ onFilesReady?: (files: ProcessedFile[]) => void;
71
+ /** Whether to strip common directory prefix from paths (default: true) */
72
+ stripPrefix?: boolean;
73
+ }
74
+ interface DropzoneManagerReturn {
75
+ /** All processed files with their status */
76
+ files: ProcessedFile[];
77
+ /** Current status text */
78
+ statusText: string;
79
+ /** Whether currently processing files (ZIP extraction, etc.) */
80
+ isProcessing: boolean;
81
+ /** Last validation error if any */
82
+ validationError: ClientError | null;
83
+ /** Whether all valid files have MD5 checksums calculated */
84
+ hasChecksums: boolean;
85
+ /** Process files from dropzone (resets and replaces existing files) */
86
+ processFiles: (files: File[]) => Promise<void>;
87
+ /** Remove a specific file */
88
+ removeFile: (fileId: string) => void;
89
+ /** Clear all files and reset state */
90
+ clearAll: () => void;
91
+ /** Get only valid files ready for upload */
92
+ getValidFiles: () => ProcessedFile[];
93
+ /** Update upload state for a specific file (status, progress, message) */
94
+ updateFileStatus: (fileId: string, state: {
95
+ status: FileStatus;
96
+ statusMessage?: string;
97
+ progress?: number;
98
+ }) => void;
99
+ }
100
+ /**
101
+ * Headless dropzone manager hook
102
+ * Handles file processing, ZIP extraction, and validation
103
+ * Does NOT handle uploading - that's the consumer's responsibility
104
+ */
105
+ declare function useDropzoneManager(options?: DropzoneManagerOptions): DropzoneManagerReturn;
106
+
107
+ /**
108
+ * Calculate MD5 hash from ArrayBuffer
109
+ */
110
+ declare function calculateMD5(buffer: ArrayBuffer): Promise<string>;
111
+ /**
112
+ * Format file size to human-readable string
113
+ */
114
+ declare function formatFileSize(bytes: number, decimals?: number): string;
115
+ /**
116
+ * Create a ProcessedFile from a File object
117
+ * This is the single conversion point from File to ProcessedFile
118
+ *
119
+ * Path resolution priority:
120
+ * 1. options.path (if provided)
121
+ * 2. file.webkitRelativePath (if non-empty, preserves folder structure)
122
+ * 3. file.name (fallback)
123
+ */
124
+ declare function createProcessedFile(file: File, options?: {
125
+ /** Custom path (defaults to webkitRelativePath or file.name) */
126
+ path?: string;
127
+ /** Whether to calculate MD5 hash (defaults to true) */
128
+ calculateMD5?: boolean;
129
+ }): Promise<ProcessedFile>;
130
+ /**
131
+ * Validate and update status of ProcessedFiles
132
+ * Returns files with updated status and validation error if any
133
+ */
134
+ interface ValidationResult {
135
+ /** All files with updated status */
136
+ files: ProcessedFile[];
137
+ /** Files that passed validation (status: READY) */
138
+ validFiles: ProcessedFile[];
139
+ /** Validation error if any files failed */
140
+ error: ClientError | null;
141
+ }
142
+ declare function validateFiles(files: ProcessedFile[], config: ValidationConfig): ValidationResult;
143
+ /**
144
+ * Get only the valid files (status: READY) from a list
145
+ */
146
+ declare function getValidFiles(files: ProcessedFile[]): ProcessedFile[];
147
+ /**
148
+ * Check if all valid files have MD5 checksums calculated
149
+ */
150
+ declare function allValidFilesHaveChecksums(files: ProcessedFile[]): boolean;
151
+ /**
152
+ * Strip common directory prefix from file paths
153
+ * Only strips if ALL files share the same prefix
154
+ */
155
+ declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
156
+
157
+ interface ZipExtractionResult {
158
+ /** Extracted files as regular File objects */
159
+ files: File[];
160
+ /** Any errors encountered during extraction */
161
+ errors: string[];
162
+ }
163
+ /**
164
+ * Extracts all files from a ZIP archive
165
+ * Returns regular File objects that can be processed like any other file
166
+ */
167
+ declare function extractZipToFiles(zipFile: File): Promise<ZipExtractionResult>;
168
+ /**
169
+ * Sanitize and normalize a file path to prevent directory traversal attacks
170
+ * Removes: .., ., leading/trailing slashes, absolute paths, and empty segments
171
+ *
172
+ * @example
173
+ * normalizePath('../../etc/passwd') → 'etc/passwd'
174
+ * normalizePath('foo/./bar/../baz.txt') → 'foo/baz.txt'
175
+ * normalizePath('/absolute/path.txt') → 'absolute/path.txt'
176
+ */
177
+ declare function normalizePath(path: string): string;
178
+ /**
179
+ * Check if a file path is a junk file that should be filtered out
180
+ * Filters common system files like .DS_Store, Thumbs.db, desktop.ini,
181
+ * and macOS resource fork metadata in __MACOSX directories
182
+ *
183
+ * Case-insensitive matching to handle files from different operating systems
184
+ * (Windows file systems are case-insensitive, so Thumbs.db === THUMBS.DB)
185
+ *
186
+ * @example
187
+ * isJunkFile('.DS_Store') → true
188
+ * isJunkFile('.ds_store') → true (case-insensitive)
189
+ * isJunkFile('THUMBS.DB') → true (case-insensitive)
190
+ * isJunkFile('folder/.DS_Store') → true
191
+ * isJunkFile('__MACOSX/file.txt') → true
192
+ * isJunkFile('mydsstore.txt') → false
193
+ */
194
+ declare function isJunkFile(path: string): boolean;
195
+ /**
196
+ * Check if a file is a ZIP file based on MIME type or extension
197
+ */
198
+ declare function isZipFile(file: File): boolean;
199
+
200
+ export { type ClientError, DEFAULT_VALIDATION, type DropzoneManagerOptions, type DropzoneManagerReturn, FILE_STATUSES, type FileStatus, type ProcessedFile, type ValidationConfig, type ValidationResult, type ZipExtractionResult, allValidFilesHaveChecksums, calculateMD5, createProcessedFile, extractZipToFiles, formatFileSize, getValidFiles, isJunkFile, isZipFile, normalizePath, stripCommonPrefix, useDropzoneManager, validateFiles };
@@ -0,0 +1,200 @@
1
+ import { ConfigResponse, StaticFile } from '@shipstatic/types';
2
+
3
+ /**
4
+ * Core types for @shipstatic/dropzone
5
+ * Imports types from @shipstatic/types (single source of truth)
6
+ * and defines dropzone-specific types
7
+ */
8
+
9
+ declare const FILE_STATUSES: {
10
+ readonly PENDING: "pending";
11
+ readonly PROCESSING: "processing";
12
+ readonly VALIDATION_FAILED: "validation_failed";
13
+ readonly PROCESSING_ERROR: "processing_error";
14
+ readonly EMPTY_FILE: "empty_file";
15
+ readonly READY: "ready";
16
+ readonly UPLOADING: "uploading";
17
+ readonly COMPLETE: "complete";
18
+ readonly ERROR: "error";
19
+ };
20
+ type FileStatus = (typeof FILE_STATUSES)[keyof typeof FILE_STATUSES];
21
+ /**
22
+ * Client-side error structure
23
+ */
24
+ interface ClientError {
25
+ error: string;
26
+ details: string;
27
+ isClientError: true;
28
+ }
29
+ /**
30
+ * Processed file entry ready for upload
31
+ * Extends StaticFile from SDK, adding UI-specific properties
32
+ * This means ProcessedFile IS a StaticFile - can be passed directly to ship.deployments.create()
33
+ */
34
+ interface ProcessedFile extends StaticFile {
35
+ /** Unique identifier for React keys and tracking */
36
+ id: string;
37
+ /** Original File object (alias for 'content' from StaticFile for better DX) */
38
+ file: File;
39
+ /** Filename without path */
40
+ name: string;
41
+ /** MIME type for UI icons/previews */
42
+ type: string;
43
+ /** Last modified timestamp */
44
+ lastModified: number;
45
+ /** Current processing/upload status */
46
+ status: FileStatus;
47
+ /** Human-readable status message for UI */
48
+ statusMessage?: string;
49
+ /** Upload progress (0-100) - only set during upload */
50
+ progress?: number;
51
+ }
52
+ /**
53
+ * Validation configuration - direct alias to SDK's ConfigResponse
54
+ * This allows passing the config directly from ship.getConfig() to the dropzone
55
+ *
56
+ * Single source of truth: @shipstatic/types
57
+ */
58
+ type ValidationConfig = ConfigResponse;
59
+ /**
60
+ * Default validation limits
61
+ */
62
+ declare const DEFAULT_VALIDATION: ConfigResponse;
63
+
64
+ interface DropzoneManagerOptions {
65
+ /** Validation configuration (from ship.getConfig()) */
66
+ config?: Partial<ValidationConfig>;
67
+ /** Callback when validation fails */
68
+ onValidationError?: (error: ClientError) => void;
69
+ /** Callback when files are ready for upload */
70
+ onFilesReady?: (files: ProcessedFile[]) => void;
71
+ /** Whether to strip common directory prefix from paths (default: true) */
72
+ stripPrefix?: boolean;
73
+ }
74
+ interface DropzoneManagerReturn {
75
+ /** All processed files with their status */
76
+ files: ProcessedFile[];
77
+ /** Current status text */
78
+ statusText: string;
79
+ /** Whether currently processing files (ZIP extraction, etc.) */
80
+ isProcessing: boolean;
81
+ /** Last validation error if any */
82
+ validationError: ClientError | null;
83
+ /** Whether all valid files have MD5 checksums calculated */
84
+ hasChecksums: boolean;
85
+ /** Process files from dropzone (resets and replaces existing files) */
86
+ processFiles: (files: File[]) => Promise<void>;
87
+ /** Remove a specific file */
88
+ removeFile: (fileId: string) => void;
89
+ /** Clear all files and reset state */
90
+ clearAll: () => void;
91
+ /** Get only valid files ready for upload */
92
+ getValidFiles: () => ProcessedFile[];
93
+ /** Update upload state for a specific file (status, progress, message) */
94
+ updateFileStatus: (fileId: string, state: {
95
+ status: FileStatus;
96
+ statusMessage?: string;
97
+ progress?: number;
98
+ }) => void;
99
+ }
100
+ /**
101
+ * Headless dropzone manager hook
102
+ * Handles file processing, ZIP extraction, and validation
103
+ * Does NOT handle uploading - that's the consumer's responsibility
104
+ */
105
+ declare function useDropzoneManager(options?: DropzoneManagerOptions): DropzoneManagerReturn;
106
+
107
+ /**
108
+ * Calculate MD5 hash from ArrayBuffer
109
+ */
110
+ declare function calculateMD5(buffer: ArrayBuffer): Promise<string>;
111
+ /**
112
+ * Format file size to human-readable string
113
+ */
114
+ declare function formatFileSize(bytes: number, decimals?: number): string;
115
+ /**
116
+ * Create a ProcessedFile from a File object
117
+ * This is the single conversion point from File to ProcessedFile
118
+ *
119
+ * Path resolution priority:
120
+ * 1. options.path (if provided)
121
+ * 2. file.webkitRelativePath (if non-empty, preserves folder structure)
122
+ * 3. file.name (fallback)
123
+ */
124
+ declare function createProcessedFile(file: File, options?: {
125
+ /** Custom path (defaults to webkitRelativePath or file.name) */
126
+ path?: string;
127
+ /** Whether to calculate MD5 hash (defaults to true) */
128
+ calculateMD5?: boolean;
129
+ }): Promise<ProcessedFile>;
130
+ /**
131
+ * Validate and update status of ProcessedFiles
132
+ * Returns files with updated status and validation error if any
133
+ */
134
+ interface ValidationResult {
135
+ /** All files with updated status */
136
+ files: ProcessedFile[];
137
+ /** Files that passed validation (status: READY) */
138
+ validFiles: ProcessedFile[];
139
+ /** Validation error if any files failed */
140
+ error: ClientError | null;
141
+ }
142
+ declare function validateFiles(files: ProcessedFile[], config: ValidationConfig): ValidationResult;
143
+ /**
144
+ * Get only the valid files (status: READY) from a list
145
+ */
146
+ declare function getValidFiles(files: ProcessedFile[]): ProcessedFile[];
147
+ /**
148
+ * Check if all valid files have MD5 checksums calculated
149
+ */
150
+ declare function allValidFilesHaveChecksums(files: ProcessedFile[]): boolean;
151
+ /**
152
+ * Strip common directory prefix from file paths
153
+ * Only strips if ALL files share the same prefix
154
+ */
155
+ declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
156
+
157
+ interface ZipExtractionResult {
158
+ /** Extracted files as regular File objects */
159
+ files: File[];
160
+ /** Any errors encountered during extraction */
161
+ errors: string[];
162
+ }
163
+ /**
164
+ * Extracts all files from a ZIP archive
165
+ * Returns regular File objects that can be processed like any other file
166
+ */
167
+ declare function extractZipToFiles(zipFile: File): Promise<ZipExtractionResult>;
168
+ /**
169
+ * Sanitize and normalize a file path to prevent directory traversal attacks
170
+ * Removes: .., ., leading/trailing slashes, absolute paths, and empty segments
171
+ *
172
+ * @example
173
+ * normalizePath('../../etc/passwd') → 'etc/passwd'
174
+ * normalizePath('foo/./bar/../baz.txt') → 'foo/baz.txt'
175
+ * normalizePath('/absolute/path.txt') → 'absolute/path.txt'
176
+ */
177
+ declare function normalizePath(path: string): string;
178
+ /**
179
+ * Check if a file path is a junk file that should be filtered out
180
+ * Filters common system files like .DS_Store, Thumbs.db, desktop.ini,
181
+ * and macOS resource fork metadata in __MACOSX directories
182
+ *
183
+ * Case-insensitive matching to handle files from different operating systems
184
+ * (Windows file systems are case-insensitive, so Thumbs.db === THUMBS.DB)
185
+ *
186
+ * @example
187
+ * isJunkFile('.DS_Store') → true
188
+ * isJunkFile('.ds_store') → true (case-insensitive)
189
+ * isJunkFile('THUMBS.DB') → true (case-insensitive)
190
+ * isJunkFile('folder/.DS_Store') → true
191
+ * isJunkFile('__MACOSX/file.txt') → true
192
+ * isJunkFile('mydsstore.txt') → false
193
+ */
194
+ declare function isJunkFile(path: string): boolean;
195
+ /**
196
+ * Check if a file is a ZIP file based on MIME type or extension
197
+ */
198
+ declare function isZipFile(file: File): boolean;
199
+
200
+ export { type ClientError, DEFAULT_VALIDATION, type DropzoneManagerOptions, type DropzoneManagerReturn, FILE_STATUSES, type FileStatus, type ProcessedFile, type ValidationConfig, type ValidationResult, type ZipExtractionResult, allValidFilesHaveChecksums, calculateMD5, createProcessedFile, extractZipToFiles, formatFileSize, getValidFiles, isJunkFile, isZipFile, normalizePath, stripCommonPrefix, useDropzoneManager, validateFiles };