@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.
- package/README.md +444 -0
- package/dist/index.cjs +12548 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +200 -0
- package/dist/index.d.ts +200 -0
- package/dist/index.js +12533 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|