@shipstatic/drop 0.1.11 → 0.1.13
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 +43 -41
- package/dist/index.cjs +49 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -11
- package/dist/index.d.ts +9 -11
- package/dist/index.js +49 -16
- package/dist/index.js.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -85,7 +85,7 @@ function MyUploader() {
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
const handleUpload = async () => {
|
|
88
|
-
//
|
|
88
|
+
// Extract File objects from ProcessedFiles for Ship SDK
|
|
89
89
|
await ship.deployments.create(drop.validFiles.map(f => f.file));
|
|
90
90
|
};
|
|
91
91
|
|
|
@@ -476,32 +476,40 @@ Use `clearAll()` to reset and try again:
|
|
|
476
476
|
|
|
477
477
|
```typescript
|
|
478
478
|
/**
|
|
479
|
-
* ProcessedFile
|
|
480
|
-
* This means it can be passed directly to ship.deployments.create()
|
|
479
|
+
* ProcessedFile - a file processed by Drop, ready for Ship SDK deployment
|
|
481
480
|
*
|
|
481
|
+
* Use the `file` property to pass to ship.deployments.create()
|
|
482
482
|
* Note: md5 is intentionally undefined - Ship SDK calculates it during deployment
|
|
483
483
|
*/
|
|
484
|
-
interface ProcessedFile
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
484
|
+
interface ProcessedFile {
|
|
485
|
+
/** Unique identifier for React keys */
|
|
486
|
+
id: string;
|
|
487
|
+
/** The File object - pass this to ship.deployments.create() */
|
|
488
|
+
file: File;
|
|
489
|
+
/** Relative path for deployment (e.g., "images/photo.jpg") */
|
|
490
|
+
path: string;
|
|
491
|
+
/** File size in bytes */
|
|
492
|
+
size: number;
|
|
493
|
+
/** MD5 hash (optional - Ship SDK calculates during deployment if not provided) */
|
|
494
|
+
md5?: string;
|
|
495
|
+
/** Filename without path */
|
|
496
|
+
name: string;
|
|
497
|
+
/** MIME type for UI icons/previews */
|
|
498
|
+
type: string;
|
|
499
|
+
/** Last modified timestamp */
|
|
496
500
|
lastModified: number;
|
|
501
|
+
/** Current processing/upload status */
|
|
497
502
|
status: FileStatus;
|
|
498
|
-
|
|
499
|
-
|
|
503
|
+
/** Human-readable status message for UI */
|
|
504
|
+
statusMessage?: string;
|
|
505
|
+
/** Upload progress (0-100) - only set during upload */
|
|
506
|
+
progress?: number;
|
|
500
507
|
}
|
|
501
508
|
|
|
502
509
|
interface ClientError {
|
|
503
510
|
error: string;
|
|
504
511
|
details: string;
|
|
512
|
+
errors: string[];
|
|
505
513
|
isClientError: true;
|
|
506
514
|
}
|
|
507
515
|
|
|
@@ -518,36 +526,30 @@ type FileStatus =
|
|
|
518
526
|
|
|
519
527
|
## Direct Ship SDK Integration
|
|
520
528
|
|
|
521
|
-
|
|
529
|
+
Extract the `file` property from ProcessedFiles to pass to Ship SDK:
|
|
522
530
|
|
|
523
531
|
```typescript
|
|
524
|
-
|
|
532
|
+
// Get valid files and extract File objects for deployment
|
|
533
|
+
const filesToDeploy = drop.validFiles.map(f => f.file);
|
|
525
534
|
|
|
526
|
-
//
|
|
527
|
-
await ship.deployments.create(
|
|
535
|
+
// Pass File[] to Ship SDK
|
|
536
|
+
await ship.deployments.create(filesToDeploy);
|
|
528
537
|
```
|
|
529
538
|
|
|
530
|
-
###
|
|
539
|
+
### Why Extract `.file`?
|
|
540
|
+
|
|
541
|
+
Ship SDK's browser `deployments.create()` accepts `File[]`. Drop's `ProcessedFile` wraps the File with additional UI metadata (id, status, progress). The `.file` property gives you the raw File object that Ship SDK expects.
|
|
531
542
|
|
|
532
543
|
```typescript
|
|
533
|
-
//
|
|
534
|
-
interface ProcessedFile
|
|
535
|
-
|
|
536
|
-
path: string; //
|
|
537
|
-
|
|
538
|
-
md5?: string; // Required by StaticFile
|
|
539
|
-
|
|
540
|
-
// Additional UI properties
|
|
541
|
-
id: string;
|
|
542
|
-
file: File; // Alias for 'content' (better DX)
|
|
543
|
-
name: string;
|
|
544
|
-
type: string;
|
|
545
|
-
status: FileStatus;
|
|
546
|
-
// ... etc
|
|
544
|
+
// ProcessedFile structure
|
|
545
|
+
interface ProcessedFile {
|
|
546
|
+
file: File; // ← Pass this to Ship SDK
|
|
547
|
+
path: string; // Normalized path (set on file.webkitRelativePath)
|
|
548
|
+
// ... UI properties (id, status, progress, etc.)
|
|
547
549
|
}
|
|
548
550
|
```
|
|
549
551
|
|
|
550
|
-
**Important**:
|
|
552
|
+
**Important**: Drop automatically sets `webkitRelativePath` on each File to preserve folder structure. Ship SDK reads this property during deployment, so paths are handled correctly.
|
|
551
553
|
|
|
552
554
|
## Architecture Decisions
|
|
553
555
|
|
|
@@ -598,19 +600,19 @@ This is the same pattern used by popular libraries like `react-dropzone`, `downs
|
|
|
598
600
|
**3. Loosely Coupled Integration**
|
|
599
601
|
Following industry standards (Firebase hooks, Supabase utilities), we chose:
|
|
600
602
|
- ✅ **Ship instance as dependency**: Validates using `ship.getConfig()`
|
|
601
|
-
- ✅ **Simple output**: ProcessedFile[]
|
|
603
|
+
- ✅ **Simple output**: Extract `.file` from ProcessedFile[] for Ship SDK
|
|
602
604
|
- ✅ **Testable**: Easy to mock Ship SDK for testing
|
|
603
605
|
- ✅ **Flexible**: Host app controls WHEN to deploy
|
|
604
606
|
|
|
605
607
|
**4. Type System Integration**
|
|
606
608
|
|
|
607
|
-
ProcessedFile
|
|
609
|
+
ProcessedFile wraps File objects with UI-specific metadata:
|
|
608
610
|
|
|
609
611
|
```
|
|
610
|
-
File[] → ProcessedFile[] (
|
|
612
|
+
File[] → ProcessedFile[] → .map(f => f.file) → ship.deployments.create()
|
|
611
613
|
```
|
|
612
614
|
|
|
613
|
-
|
|
615
|
+
ProcessedFile adds UI properties (id, name, status, progress) while preserving the original File object. The `.file` property gives you direct access for Ship SDK deployment.
|
|
614
616
|
|
|
615
617
|
**5. No Visual Components**
|
|
616
618
|
|
package/dist/index.cjs
CHANGED
|
@@ -11702,6 +11702,42 @@ var require_mime_db = __commonJS({
|
|
|
11702
11702
|
}
|
|
11703
11703
|
});
|
|
11704
11704
|
|
|
11705
|
+
// node_modules/.pnpm/@shipstatic+types@0.3.18/node_modules/@shipstatic/types/dist/index.js
|
|
11706
|
+
var ErrorType;
|
|
11707
|
+
(function(ErrorType2) {
|
|
11708
|
+
ErrorType2["Validation"] = "validation_failed";
|
|
11709
|
+
ErrorType2["NotFound"] = "not_found";
|
|
11710
|
+
ErrorType2["RateLimit"] = "rate_limit_exceeded";
|
|
11711
|
+
ErrorType2["Authentication"] = "authentication_failed";
|
|
11712
|
+
ErrorType2["Business"] = "business_logic_error";
|
|
11713
|
+
ErrorType2["Api"] = "internal_server_error";
|
|
11714
|
+
ErrorType2["Network"] = "network_error";
|
|
11715
|
+
ErrorType2["Cancelled"] = "operation_cancelled";
|
|
11716
|
+
ErrorType2["File"] = "file_error";
|
|
11717
|
+
ErrorType2["Config"] = "config_error";
|
|
11718
|
+
})(ErrorType || (ErrorType = {}));
|
|
11719
|
+
({
|
|
11720
|
+
client: /* @__PURE__ */ new Set([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),
|
|
11721
|
+
network: /* @__PURE__ */ new Set([ErrorType.Network]),
|
|
11722
|
+
auth: /* @__PURE__ */ new Set([ErrorType.Authentication])
|
|
11723
|
+
});
|
|
11724
|
+
var FileValidationStatus = {
|
|
11725
|
+
PENDING: "pending",
|
|
11726
|
+
PROCESSING_ERROR: "processing_error",
|
|
11727
|
+
EMPTY_FILE: "empty_file",
|
|
11728
|
+
VALIDATION_FAILED: "validation_failed",
|
|
11729
|
+
READY: "ready"
|
|
11730
|
+
};
|
|
11731
|
+
|
|
11732
|
+
// src/types.ts
|
|
11733
|
+
var FILE_STATUSES = {
|
|
11734
|
+
...FileValidationStatus,
|
|
11735
|
+
PROCESSING: "processing",
|
|
11736
|
+
UPLOADING: "uploading",
|
|
11737
|
+
COMPLETE: "complete",
|
|
11738
|
+
ERROR: "error"
|
|
11739
|
+
};
|
|
11740
|
+
|
|
11705
11741
|
// src/utils/zipExtractor.ts
|
|
11706
11742
|
var import_jszip = __toESM(require_jszip_min());
|
|
11707
11743
|
|
|
@@ -11777,21 +11813,6 @@ function normalizePath(path) {
|
|
|
11777
11813
|
function isZipFile(file) {
|
|
11778
11814
|
return file.type === "application/zip" || file.type === "application/x-zip-compressed" || file.name.toLowerCase().endsWith(".zip");
|
|
11779
11815
|
}
|
|
11780
|
-
|
|
11781
|
-
// src/types.ts
|
|
11782
|
-
var FILE_STATUSES = {
|
|
11783
|
-
PENDING: "pending",
|
|
11784
|
-
PROCESSING: "processing",
|
|
11785
|
-
VALIDATION_FAILED: "validation_failed",
|
|
11786
|
-
PROCESSING_ERROR: "processing_error",
|
|
11787
|
-
EMPTY_FILE: "empty_file",
|
|
11788
|
-
READY: "ready",
|
|
11789
|
-
UPLOADING: "uploading",
|
|
11790
|
-
COMPLETE: "complete",
|
|
11791
|
-
ERROR: "error"
|
|
11792
|
-
};
|
|
11793
|
-
|
|
11794
|
-
// src/utils/fileProcessing.ts
|
|
11795
11816
|
var formatFileSize = ship.formatFileSize;
|
|
11796
11817
|
async function createProcessedFile(file, options) {
|
|
11797
11818
|
const webkitPath = file.webkitRelativePath || "";
|
|
@@ -11980,6 +12001,7 @@ function useDrop(options) {
|
|
|
11980
12001
|
const noValidError = {
|
|
11981
12002
|
error: "No Valid Files",
|
|
11982
12003
|
details: "None of the provided files could be processed.",
|
|
12004
|
+
errors: [],
|
|
11983
12005
|
isClientError: true
|
|
11984
12006
|
};
|
|
11985
12007
|
setState({
|
|
@@ -11994,6 +12016,7 @@ function useDrop(options) {
|
|
|
11994
12016
|
const processingError = {
|
|
11995
12017
|
error: "Processing Failed",
|
|
11996
12018
|
details: `Failed to process files: ${error instanceof Error ? error.message : String(error)}`,
|
|
12019
|
+
errors: [],
|
|
11997
12020
|
isClientError: true
|
|
11998
12021
|
};
|
|
11999
12022
|
setState((prev) => ({
|
|
@@ -12031,7 +12054,17 @@ function useDrop(options) {
|
|
|
12031
12054
|
e.preventDefault();
|
|
12032
12055
|
setState((prev) => {
|
|
12033
12056
|
if (prev.value !== "dragging") return prev;
|
|
12034
|
-
|
|
12057
|
+
if (prev.files.length === 0) {
|
|
12058
|
+
return { ...prev, value: "idle" };
|
|
12059
|
+
}
|
|
12060
|
+
const errorStatuses = [
|
|
12061
|
+
FILE_STATUSES.VALIDATION_FAILED,
|
|
12062
|
+
FILE_STATUSES.PROCESSING_ERROR,
|
|
12063
|
+
FILE_STATUSES.EMPTY_FILE,
|
|
12064
|
+
FILE_STATUSES.ERROR
|
|
12065
|
+
];
|
|
12066
|
+
const hasErrors = prev.files.some((f) => errorStatuses.includes(f.status));
|
|
12067
|
+
const nextValue = hasErrors ? "error" : "ready";
|
|
12035
12068
|
return { ...prev, value: nextValue };
|
|
12036
12069
|
});
|
|
12037
12070
|
}, []);
|