@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 CHANGED
@@ -85,7 +85,7 @@ function MyUploader() {
85
85
  });
86
86
 
87
87
  const handleUpload = async () => {
88
- // ProcessedFile extends StaticFile - no conversion needed!
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 extends StaticFile from @shipstatic/types
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 extends StaticFile {
485
- // StaticFile properties (SDK compatibility)
486
- content: File; // File object (required by SDK)
487
- path: string; // Normalized path (webkitRelativePath or file.name)
488
- size: number; // File size in bytes
489
- md5?: string; // Undefined - Ship SDK calculates during deployment
490
-
491
- // ProcessedFile-specific properties (UI functionality)
492
- id: string; // Unique identifier for React keys
493
- file: File; // Alias for 'content' (better DX)
494
- name: string; // File name without path
495
- type: string; // MIME type
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
- statusMessage?: string; // Per-file error message
499
- progress?: number; // Upload progress (0-100)
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
- **ProcessedFile extends StaticFile** - no conversion needed! Since `ProcessedFile` extends `StaticFile` from `@shipstatic/types`, you can pass the files directly to the Ship SDK:
529
+ Extract the `file` property from ProcessedFiles to pass to Ship SDK:
522
530
 
523
531
  ```typescript
524
- const validFiles = drop.getValidFiles();
532
+ // Get valid files and extract File objects for deployment
533
+ const filesToDeploy = drop.validFiles.map(f => f.file);
525
534
 
526
- // ProcessedFile[] IS StaticFile[] - pass directly!
527
- await ship.deployments.create({ files: validFiles });
535
+ // Pass File[] to Ship SDK
536
+ await ship.deployments.create(filesToDeploy);
528
537
  ```
529
538
 
530
- ### Type Compatibility
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
- // ✅ This works because ProcessedFile extends StaticFile
534
- interface ProcessedFile extends StaticFile {
535
- content: File; // Required by StaticFile
536
- path: string; // Required by StaticFile
537
- size: number; // Required by StaticFile
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**: The drop hook preserves folder structure via `webkitRelativePath` and processes paths with `stripCommonPrefix` automatically. The `path` property is always deployment-ready.
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[] can be passed directly to Ship SDK
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 extends StaticFile from `@shipstatic/types` - the single source of truth for Ship SDK types:
609
+ ProcessedFile wraps File objects with UI-specific metadata:
608
610
 
609
611
  ```
610
- File[] → ProcessedFile[] (which IS StaticFile[]) → ship.deployments.create()
612
+ File[] → ProcessedFile[] → .map(f => f.file) → ship.deployments.create()
611
613
  ```
612
614
 
613
- No conversion needed. ProcessedFile adds UI-specific properties (id, name, status, progress) to StaticFile's base properties (content, path, size, md5).
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
- const nextValue = prev.files.length > 0 ? prev.status?.title === "Ready" ? "ready" : "error" : "idle";
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
  }, []);