@shipstatic/drop 0.3.6 → 1.0.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/dist/index.d.cts CHANGED
@@ -1,16 +1,13 @@
1
- import { P as ProcessedFile } from './useDrop-q3T3LVH0.cjs';
2
- export { C as ClientError, D as DropOptions, a as DropReturn, b as DropState, c as DropStateValue, d as DropStatus, e as DropzonePropsOptions, F as FILE_STATUSES, f as FileStatus, g as FileWithPath, u as useDrop } from './useDrop-q3T3LVH0.cjs';
3
- import { formatFileSize as formatFileSize$1 } from '@shipstatic/ship';
1
+ import { P as ProcessedFile } from './useDrop-BAYclQ_x.cjs';
2
+ export { C as ClientError, D as DropOptions, a as DropReturn, b as DropState, c as DropStateValue, d as DropStatus, e as DropzonePropsOptions, F as FILE_STATUSES, f as FileStatus, u as useDrop } from './useDrop-BAYclQ_x.cjs';
3
+ export { formatFileSize } from '@shipstatic/ship';
4
4
 
5
5
  /**
6
- * Unified file processing utilities
7
- * Converts Files directly to ProcessedFiles
6
+ * Patch a File's `webkitRelativePath` so downstream consumers (the Ship SDK)
7
+ * read our resolved deploy path. Browser-set `webkitRelativePath` is read-only,
8
+ * so we redefine the property — `configurable: true` allows re-patching later.
8
9
  */
9
- /**
10
- * Format file size to human-readable string
11
- * Re-exported from Ship SDK for convenience
12
- */
13
- declare const formatFileSize: typeof formatFileSize$1;
10
+ declare function setRelativePath(file: File, path: string): void;
14
11
  /**
15
12
  * Create a ProcessedFile from a File object
16
13
  * This is the single conversion point from File to ProcessedFile
@@ -28,8 +25,12 @@ declare function createProcessedFile(file: File, options?: {
28
25
  path?: string;
29
26
  }): ProcessedFile;
30
27
  /**
31
- * Strip common directory prefix from file paths
32
- * Only strips if ALL files share the same prefix
28
+ * Strip common directory prefix from file paths.
29
+ *
30
+ * Delegates the path algorithm to Ship SDK's `optimizeDeployPaths` (the single
31
+ * source of truth for deploy-path normalization) and mutates each underlying
32
+ * File's `webkitRelativePath` so downstream consumers (Ship SDK) read the
33
+ * stripped path when given the raw File objects.
33
34
  */
34
35
  declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
35
36
  /**
@@ -70,4 +71,4 @@ declare function isZipFile(file: File): boolean;
70
71
  */
71
72
  declare function getMimeType(path: string): string;
72
73
 
73
- export { ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, getMimeType, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree };
74
+ export { ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, getMimeType, isZipFile, normalizePath, setRelativePath, stripCommonPrefix, traverseFileTree };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,13 @@
1
- import { P as ProcessedFile } from './useDrop-q3T3LVH0.js';
2
- export { C as ClientError, D as DropOptions, a as DropReturn, b as DropState, c as DropStateValue, d as DropStatus, e as DropzonePropsOptions, F as FILE_STATUSES, f as FileStatus, g as FileWithPath, u as useDrop } from './useDrop-q3T3LVH0.js';
3
- import { formatFileSize as formatFileSize$1 } from '@shipstatic/ship';
1
+ import { P as ProcessedFile } from './useDrop-BAYclQ_x.js';
2
+ export { C as ClientError, D as DropOptions, a as DropReturn, b as DropState, c as DropStateValue, d as DropStatus, e as DropzonePropsOptions, F as FILE_STATUSES, f as FileStatus, u as useDrop } from './useDrop-BAYclQ_x.js';
3
+ export { formatFileSize } from '@shipstatic/ship';
4
4
 
5
5
  /**
6
- * Unified file processing utilities
7
- * Converts Files directly to ProcessedFiles
6
+ * Patch a File's `webkitRelativePath` so downstream consumers (the Ship SDK)
7
+ * read our resolved deploy path. Browser-set `webkitRelativePath` is read-only,
8
+ * so we redefine the property — `configurable: true` allows re-patching later.
8
9
  */
9
- /**
10
- * Format file size to human-readable string
11
- * Re-exported from Ship SDK for convenience
12
- */
13
- declare const formatFileSize: typeof formatFileSize$1;
10
+ declare function setRelativePath(file: File, path: string): void;
14
11
  /**
15
12
  * Create a ProcessedFile from a File object
16
13
  * This is the single conversion point from File to ProcessedFile
@@ -28,8 +25,12 @@ declare function createProcessedFile(file: File, options?: {
28
25
  path?: string;
29
26
  }): ProcessedFile;
30
27
  /**
31
- * Strip common directory prefix from file paths
32
- * Only strips if ALL files share the same prefix
28
+ * Strip common directory prefix from file paths.
29
+ *
30
+ * Delegates the path algorithm to Ship SDK's `optimizeDeployPaths` (the single
31
+ * source of truth for deploy-path normalization) and mutates each underlying
32
+ * File's `webkitRelativePath` so downstream consumers (Ship SDK) read the
33
+ * stripped path when given the raw File objects.
33
34
  */
34
35
  declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
35
36
  /**
@@ -70,4 +71,4 @@ declare function isZipFile(file: File): boolean;
70
71
  */
71
72
  declare function getMimeType(path: string): string;
72
73
 
73
- export { ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, getMimeType, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree };
74
+ export { ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, getMimeType, isZipFile, normalizePath, setRelativePath, stripCommonPrefix, traverseFileTree };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { useState, useRef, useMemo, useCallback } from 'react';
2
- import { formatFileSize as formatFileSize$1, filterJunk, validateFiles } from '@shipstatic/ship';
2
+ import { optimizeDeployPaths, filterJunk, pluralize, validateFiles } from '@shipstatic/ship';
3
+ export { formatFileSize } from '@shipstatic/ship';
3
4
 
4
5
  var __create = Object.create;
5
6
  var __defProp = Object.defineProperty;
@@ -29,7 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
30
 
30
31
  // node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json
31
32
  var require_db = __commonJS({
32
- "node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json"(exports$1, module) {
33
+ "node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json"(exports, module) {
33
34
  module.exports = {
34
35
  "application/1d-interleaved-parityfec": {
35
36
  source: "iana"
@@ -9377,10 +9378,43 @@ var require_db = __commonJS({
9377
9378
 
9378
9379
  // node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js
9379
9380
  var require_mime_db = __commonJS({
9380
- "node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js"(exports$1, module) {
9381
+ "node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js"(exports, module) {
9381
9382
  module.exports = require_db();
9382
9383
  }
9383
9384
  });
9385
+
9386
+ // node_modules/.pnpm/@shipstatic+types@1.0.0/node_modules/@shipstatic/types/dist/index.js
9387
+ var ErrorType = {
9388
+ /** Validation failed (400). Input shape is wrong. */
9389
+ Validation: "validation_failed",
9390
+ /** Resource not found (404). */
9391
+ NotFound: "not_found",
9392
+ /** Authenticated but not allowed (403). User lacks permission for this action. */
9393
+ Forbidden: "forbidden",
9394
+ /** Rate limit exceeded (429). */
9395
+ RateLimit: "rate_limit_exceeded",
9396
+ /** Authentication required or failed (401). Missing/invalid credentials. */
9397
+ Authentication: "authentication_failed",
9398
+ /** Business rule violation. Catch-all for 4xx state-rule errors that aren't more specific. */
9399
+ Business: "business_logic_error",
9400
+ /** API server error (500). Generic server-side fault. */
9401
+ Api: "internal_server_error",
9402
+ /** Network/connection error. Client-side only — set by HTTP clients on fetch failure; never produced server-side. */
9403
+ Network: "network_error",
9404
+ /** Operation was cancelled. Client-side only — set on `AbortSignal` abort; never produced server-side. */
9405
+ Cancelled: "operation_cancelled",
9406
+ /** File operation error. Client-side only — set by SDK during local file processing; never produced server-side. */
9407
+ File: "file_error",
9408
+ /** Configuration error. Client-side only — set by SDK during config parsing/validation; never produced server-side. */
9409
+ Config: "config_error"
9410
+ };
9411
+ var CLIENT_ONLY_ERROR_TYPES = /* @__PURE__ */ new Set([
9412
+ ErrorType.Network,
9413
+ ErrorType.Cancelled,
9414
+ ErrorType.File,
9415
+ ErrorType.Config
9416
+ ]);
9417
+ new Set(Object.values(ErrorType).filter((t) => !CLIENT_ONLY_ERROR_TYPES.has(t)));
9384
9418
  function isShipError(error) {
9385
9419
  return error !== null && typeof error === "object" && "name" in error && error.name === "ShipError" && "status" in error;
9386
9420
  }
@@ -9875,71 +9909,18 @@ function getMimeType(path) {
9875
9909
  const extension = path.includes(".") ? path.substring(path.lastIndexOf(".") + 1).toLowerCase() : "";
9876
9910
  return extensionToMimeMap[extension] || "";
9877
9911
  }
9878
-
9879
- // src/utils/zipExtractor.ts
9880
- async function extractZipToFiles(zipFile) {
9881
- try {
9882
- const arrayBuffer = await zipFile.arrayBuffer();
9883
- const entries = unzipSync(new Uint8Array(arrayBuffer));
9884
- const files = [];
9885
- const errors = [];
9886
- for (const [path, data] of Object.entries(entries)) {
9887
- if (path.endsWith("/") && data.length === 0) continue;
9888
- const sanitizedPath = normalizePath(path);
9889
- if (!sanitizedPath) {
9890
- errors.push(`Skipped invalid path: ${path}`);
9891
- continue;
9892
- }
9893
- const mimeType = getMimeType(sanitizedPath);
9894
- const filename = sanitizedPath.split("/").pop() || sanitizedPath;
9895
- const file = new File([new Uint8Array(data)], filename, {
9896
- type: mimeType
9897
- });
9898
- Object.defineProperty(file, "webkitRelativePath", {
9899
- value: sanitizedPath,
9900
- writable: false,
9901
- configurable: true
9902
- });
9903
- files.push(file);
9904
- }
9905
- return { files, errors };
9906
- } catch (error) {
9907
- return {
9908
- files: [],
9909
- errors: [`Failed to load ZIP file: ${error instanceof Error ? error.message : String(error)}`]
9910
- };
9911
- }
9912
- }
9913
- function normalizePath(path) {
9914
- const segments = path.split("/");
9915
- const normalized = [];
9916
- for (const segment of segments) {
9917
- if (segment === "" || segment === ".") {
9918
- continue;
9919
- }
9920
- if (segment === "..") {
9921
- if (normalized.length > 0) {
9922
- normalized.pop();
9923
- }
9924
- continue;
9925
- }
9926
- normalized.push(segment);
9927
- }
9928
- return normalized.join("/");
9929
- }
9930
- function isZipFile(file) {
9931
- return file.type === "application/zip" || file.type === "application/x-zip-compressed" || file.name.toLowerCase().endsWith(".zip");
9912
+ function setRelativePath(file, path) {
9913
+ Object.defineProperty(file, "webkitRelativePath", {
9914
+ value: path,
9915
+ writable: false,
9916
+ configurable: true
9917
+ });
9932
9918
  }
9933
- var formatFileSize = formatFileSize$1;
9934
9919
  function createProcessedFile(file, options) {
9935
- const webkitPath = file.webkitRelativePath || "";
9936
- const path = options?.path || (webkitPath && webkitPath.trim() ? webkitPath : file.name);
9937
- const mimeFromDb = getMimeType(path);
9938
- const mimeFromBrowser = file.type;
9939
- const type = mimeFromDb || mimeFromBrowser;
9920
+ const path = options?.path || file.webkitRelativePath?.trim() || file.name;
9921
+ const type = getMimeType(path) || file.type;
9940
9922
  return {
9941
- // ProcessedFile properties
9942
- // Note: md5 is intentionally undefined - Ship SDK will calculate it during deployment
9923
+ // md5 is intentionally undefined — Ship SDK calculates it during deployment.
9943
9924
  id: crypto.randomUUID(),
9944
9925
  file,
9945
9926
  path,
@@ -9952,32 +9933,11 @@ function createProcessedFile(file, options) {
9952
9933
  }
9953
9934
  function stripCommonPrefix(files) {
9954
9935
  if (files.length === 0) return files;
9955
- const paths = files.map((f) => f.path);
9956
- const segments = paths[0].split("/");
9957
- let commonDepth = 0;
9958
- for (let i = 0; i < segments.length - 1; i++) {
9959
- const segment = segments[i];
9960
- if (paths.every((p) => p.split("/")[i] === segment)) {
9961
- commonDepth = i + 1;
9962
- } else {
9963
- break;
9964
- }
9965
- }
9966
- if (commonDepth === 0) return files;
9967
- const prefix = segments.slice(0, commonDepth).join("/") + "/";
9968
- return files.map((f) => {
9969
- const newPath = f.path.startsWith(prefix) ? f.path.slice(prefix.length) : f.path;
9970
- if (f.file) {
9971
- Object.defineProperty(f.file, "webkitRelativePath", {
9972
- value: newPath,
9973
- writable: false,
9974
- configurable: true
9975
- });
9976
- }
9977
- return {
9978
- ...f,
9979
- path: newPath
9980
- };
9936
+ const deployFiles = optimizeDeployPaths(files.map((f) => f.path));
9937
+ return files.map((f, i) => {
9938
+ const newPath = deployFiles[i].path;
9939
+ setRelativePath(f.file, newPath);
9940
+ return { ...f, path: newPath };
9981
9941
  });
9982
9942
  }
9983
9943
  async function traverseFileTree(entry, files, currentPath = "") {
@@ -9987,11 +9947,7 @@ async function traverseFileTree(entry, files, currentPath = "") {
9987
9947
  entry.file(resolve, reject);
9988
9948
  });
9989
9949
  const relativePath = currentPath ? `${currentPath}/${file.name}` : file.name;
9990
- Object.defineProperty(file, "webkitRelativePath", {
9991
- value: relativePath,
9992
- writable: false,
9993
- configurable: true
9994
- });
9950
+ setRelativePath(file, relativePath);
9995
9951
  files.push(file);
9996
9952
  } else if (entry.isDirectory) {
9997
9953
  const dirReader = entry.createReader();
@@ -10020,6 +9976,57 @@ async function traverseFileTree(entry, files, currentPath = "") {
10020
9976
  console.warn(`Error traversing file tree for entry ${entry.name}:`, error);
10021
9977
  }
10022
9978
  }
9979
+
9980
+ // src/utils/zipExtractor.ts
9981
+ async function extractZipToFiles(zipFile) {
9982
+ try {
9983
+ const arrayBuffer = await zipFile.arrayBuffer();
9984
+ const entries = unzipSync(new Uint8Array(arrayBuffer));
9985
+ const files = [];
9986
+ const errors = [];
9987
+ for (const [path, data] of Object.entries(entries)) {
9988
+ if (path.endsWith("/") && data.length === 0) continue;
9989
+ const sanitizedPath = normalizePath(path);
9990
+ if (!sanitizedPath) {
9991
+ errors.push(`Skipped invalid path: ${path}`);
9992
+ continue;
9993
+ }
9994
+ const mimeType = getMimeType(sanitizedPath);
9995
+ const filename = sanitizedPath.split("/").pop() || sanitizedPath;
9996
+ const file = new File([new Uint8Array(data)], filename, {
9997
+ type: mimeType
9998
+ });
9999
+ setRelativePath(file, sanitizedPath);
10000
+ files.push(file);
10001
+ }
10002
+ return { files, errors };
10003
+ } catch (error) {
10004
+ return {
10005
+ files: [],
10006
+ errors: [`Failed to load ZIP file: ${error instanceof Error ? error.message : String(error)}`]
10007
+ };
10008
+ }
10009
+ }
10010
+ function normalizePath(path) {
10011
+ const segments = path.split("/");
10012
+ const normalized = [];
10013
+ for (const segment of segments) {
10014
+ if (segment === "" || segment === ".") {
10015
+ continue;
10016
+ }
10017
+ if (segment === "..") {
10018
+ if (normalized.length > 0) {
10019
+ normalized.pop();
10020
+ }
10021
+ continue;
10022
+ }
10023
+ normalized.push(segment);
10024
+ }
10025
+ return normalized.join("/");
10026
+ }
10027
+ function isZipFile(file) {
10028
+ return file.type === "application/zip" || file.type === "application/x-zip-compressed" || file.name.toLowerCase().endsWith(".zip");
10029
+ }
10023
10030
  var initialState = {
10024
10031
  value: "idle",
10025
10032
  files: [],
@@ -10089,10 +10096,7 @@ function useDrop(options) {
10089
10096
  } else {
10090
10097
  allFiles.push(...newFiles);
10091
10098
  }
10092
- const getFilePath = (f) => {
10093
- const webkitPath = f.webkitRelativePath;
10094
- return webkitPath && webkitPath.trim() ? webkitPath : f.name;
10095
- };
10099
+ const getFilePath = (f) => f.webkitRelativePath?.trim() || f.name;
10096
10100
  let filePaths = allFiles.map(getFilePath);
10097
10101
  const needsBuild = filePaths.some((p) => hasUnbuiltMarker(p));
10098
10102
  if (needsBuild) {
@@ -10148,7 +10152,7 @@ function useDrop(options) {
10148
10152
  files: filesWithStatus2,
10149
10153
  sourceName: detectedSourceName,
10150
10154
  needsBuild: true,
10151
- status: { title: "Ready", details: `${filesWithStatus2.length} file(s) ready \u2014 project will be built` }
10155
+ status: { title: "Ready", details: `${pluralize(filesWithStatus2.length, "file", "files", true)} ready \u2014 project will be built` }
10152
10156
  });
10153
10157
  onFilesReady?.(filesWithStatus2);
10154
10158
  return;
@@ -10176,20 +10180,20 @@ function useDrop(options) {
10176
10180
  needsBuild: false,
10177
10181
  status: {
10178
10182
  title: "Validation Failed",
10179
- details: `${validation.errors.length} file(s) failed validation`,
10183
+ details: `${pluralize(validation.errors.length, "file", "files", true)} failed validation`,
10180
10184
  errors: errorMessages
10181
10185
  }
10182
10186
  });
10183
10187
  onValidationError?.({
10184
10188
  error: "Validation Failed",
10185
- details: `${validation.errors.length} error(s)`,
10189
+ details: pluralize(validation.errors.length, "error", "errors", true),
10186
10190
  errors: errorMessages,
10187
10191
  isClientError: true
10188
10192
  });
10189
10193
  } else if (validation.validFiles.length > 0) {
10190
- let details = `${validation.validFiles.length} file(s) ready`;
10194
+ let details = `${pluralize(validation.validFiles.length, "file", "files", true)} ready`;
10191
10195
  if (validation.warnings.length > 0) {
10192
- details += ` (${validation.warnings.length} empty file(s) excluded)`;
10196
+ details += ` (${pluralize(validation.warnings.length, "empty file", "empty files", true)} excluded)`;
10193
10197
  }
10194
10198
  setState({
10195
10199
  value: "ready",
@@ -10215,7 +10219,7 @@ function useDrop(options) {
10215
10219
  needsBuild: false,
10216
10220
  status: {
10217
10221
  title: "All files excluded",
10218
- details: `${validation.warnings.length} file(s) excluded (empty files cannot be deployed)`,
10222
+ details: `${pluralize(validation.warnings.length, "file", "files", true)} excluded (empty files cannot be deployed)`,
10219
10223
  warnings: validation.warnings.map((w) => `${w.file}: ${w.message}`)
10220
10224
  }
10221
10225
  });
@@ -10305,11 +10309,7 @@ function useDrop(options) {
10305
10309
  } else {
10306
10310
  const file = item.getAsFile();
10307
10311
  if (file) {
10308
- Object.defineProperty(file, "webkitRelativePath", {
10309
- value: file.name,
10310
- writable: false,
10311
- configurable: true
10312
- });
10312
+ setRelativePath(file, file.name);
10313
10313
  files.push(file);
10314
10314
  }
10315
10315
  }
@@ -10397,6 +10397,6 @@ mime-db/index.js:
10397
10397
  *)
10398
10398
  */
10399
10399
 
10400
- export { FILE_STATUSES, createProcessedFile, extractZipToFiles, formatFileSize, getMimeType, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree, useDrop };
10400
+ export { FILE_STATUSES, createProcessedFile, extractZipToFiles, getMimeType, isZipFile, normalizePath, setRelativePath, stripCommonPrefix, traverseFileTree, useDrop };
10401
10401
  //# sourceMappingURL=index.js.map
10402
10402
  //# sourceMappingURL=index.js.map