@shipstatic/drop 0.3.7 → 1.0.1

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;
@@ -9382,7 +9383,7 @@ var require_mime_db = __commonJS({
9382
9383
  }
9383
9384
  });
9384
9385
 
9385
- // node_modules/.pnpm/@shipstatic+types@0.9.8/node_modules/@shipstatic/types/dist/index.js
9386
+ // node_modules/.pnpm/@shipstatic+types@1.0.0/node_modules/@shipstatic/types/dist/index.js
9386
9387
  var ErrorType = {
9387
9388
  /** Validation failed (400). Input shape is wrong. */
9388
9389
  Validation: "validation_failed",
@@ -9908,71 +9909,18 @@ function getMimeType(path) {
9908
9909
  const extension = path.includes(".") ? path.substring(path.lastIndexOf(".") + 1).toLowerCase() : "";
9909
9910
  return extensionToMimeMap[extension] || "";
9910
9911
  }
9911
-
9912
- // src/utils/zipExtractor.ts
9913
- async function extractZipToFiles(zipFile) {
9914
- try {
9915
- const arrayBuffer = await zipFile.arrayBuffer();
9916
- const entries = unzipSync(new Uint8Array(arrayBuffer));
9917
- const files = [];
9918
- const errors = [];
9919
- for (const [path, data] of Object.entries(entries)) {
9920
- if (path.endsWith("/") && data.length === 0) continue;
9921
- const sanitizedPath = normalizePath(path);
9922
- if (!sanitizedPath) {
9923
- errors.push(`Skipped invalid path: ${path}`);
9924
- continue;
9925
- }
9926
- const mimeType = getMimeType(sanitizedPath);
9927
- const filename = sanitizedPath.split("/").pop() || sanitizedPath;
9928
- const file = new File([new Uint8Array(data)], filename, {
9929
- type: mimeType
9930
- });
9931
- Object.defineProperty(file, "webkitRelativePath", {
9932
- value: sanitizedPath,
9933
- writable: false,
9934
- configurable: true
9935
- });
9936
- files.push(file);
9937
- }
9938
- return { files, errors };
9939
- } catch (error) {
9940
- return {
9941
- files: [],
9942
- errors: [`Failed to load ZIP file: ${error instanceof Error ? error.message : String(error)}`]
9943
- };
9944
- }
9945
- }
9946
- function normalizePath(path) {
9947
- const segments = path.split("/");
9948
- const normalized = [];
9949
- for (const segment of segments) {
9950
- if (segment === "" || segment === ".") {
9951
- continue;
9952
- }
9953
- if (segment === "..") {
9954
- if (normalized.length > 0) {
9955
- normalized.pop();
9956
- }
9957
- continue;
9958
- }
9959
- normalized.push(segment);
9960
- }
9961
- return normalized.join("/");
9962
- }
9963
- function isZipFile(file) {
9964
- 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
+ });
9965
9918
  }
9966
- var formatFileSize = formatFileSize$1;
9967
9919
  function createProcessedFile(file, options) {
9968
- const webkitPath = file.webkitRelativePath || "";
9969
- const path = options?.path || (webkitPath && webkitPath.trim() ? webkitPath : file.name);
9970
- const mimeFromDb = getMimeType(path);
9971
- const mimeFromBrowser = file.type;
9972
- const type = mimeFromDb || mimeFromBrowser;
9920
+ const path = options?.path || file.webkitRelativePath?.trim() || file.name;
9921
+ const type = getMimeType(path) || file.type;
9973
9922
  return {
9974
- // ProcessedFile properties
9975
- // Note: md5 is intentionally undefined - Ship SDK will calculate it during deployment
9923
+ // md5 is intentionally undefined — Ship SDK calculates it during deployment.
9976
9924
  id: crypto.randomUUID(),
9977
9925
  file,
9978
9926
  path,
@@ -9985,32 +9933,11 @@ function createProcessedFile(file, options) {
9985
9933
  }
9986
9934
  function stripCommonPrefix(files) {
9987
9935
  if (files.length === 0) return files;
9988
- const paths = files.map((f) => f.path);
9989
- const segments = paths[0].split("/");
9990
- let commonDepth = 0;
9991
- for (let i = 0; i < segments.length - 1; i++) {
9992
- const segment = segments[i];
9993
- if (paths.every((p) => p.split("/")[i] === segment)) {
9994
- commonDepth = i + 1;
9995
- } else {
9996
- break;
9997
- }
9998
- }
9999
- if (commonDepth === 0) return files;
10000
- const prefix = segments.slice(0, commonDepth).join("/") + "/";
10001
- return files.map((f) => {
10002
- const newPath = f.path.startsWith(prefix) ? f.path.slice(prefix.length) : f.path;
10003
- if (f.file) {
10004
- Object.defineProperty(f.file, "webkitRelativePath", {
10005
- value: newPath,
10006
- writable: false,
10007
- configurable: true
10008
- });
10009
- }
10010
- return {
10011
- ...f,
10012
- path: newPath
10013
- };
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 };
10014
9941
  });
10015
9942
  }
10016
9943
  async function traverseFileTree(entry, files, currentPath = "") {
@@ -10020,11 +9947,7 @@ async function traverseFileTree(entry, files, currentPath = "") {
10020
9947
  entry.file(resolve, reject);
10021
9948
  });
10022
9949
  const relativePath = currentPath ? `${currentPath}/${file.name}` : file.name;
10023
- Object.defineProperty(file, "webkitRelativePath", {
10024
- value: relativePath,
10025
- writable: false,
10026
- configurable: true
10027
- });
9950
+ setRelativePath(file, relativePath);
10028
9951
  files.push(file);
10029
9952
  } else if (entry.isDirectory) {
10030
9953
  const dirReader = entry.createReader();
@@ -10053,6 +9976,57 @@ async function traverseFileTree(entry, files, currentPath = "") {
10053
9976
  console.warn(`Error traversing file tree for entry ${entry.name}:`, error);
10054
9977
  }
10055
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
+ }
10056
10030
  var initialState = {
10057
10031
  value: "idle",
10058
10032
  files: [],
@@ -10122,10 +10096,7 @@ function useDrop(options) {
10122
10096
  } else {
10123
10097
  allFiles.push(...newFiles);
10124
10098
  }
10125
- const getFilePath = (f) => {
10126
- const webkitPath = f.webkitRelativePath;
10127
- return webkitPath && webkitPath.trim() ? webkitPath : f.name;
10128
- };
10099
+ const getFilePath = (f) => f.webkitRelativePath?.trim() || f.name;
10129
10100
  let filePaths = allFiles.map(getFilePath);
10130
10101
  const needsBuild = filePaths.some((p) => hasUnbuiltMarker(p));
10131
10102
  if (needsBuild) {
@@ -10181,7 +10152,7 @@ function useDrop(options) {
10181
10152
  files: filesWithStatus2,
10182
10153
  sourceName: detectedSourceName,
10183
10154
  needsBuild: true,
10184
- 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` }
10185
10156
  });
10186
10157
  onFilesReady?.(filesWithStatus2);
10187
10158
  return;
@@ -10209,20 +10180,20 @@ function useDrop(options) {
10209
10180
  needsBuild: false,
10210
10181
  status: {
10211
10182
  title: "Validation Failed",
10212
- details: `${validation.errors.length} file(s) failed validation`,
10183
+ details: `${pluralize(validation.errors.length, "file", "files", true)} failed validation`,
10213
10184
  errors: errorMessages
10214
10185
  }
10215
10186
  });
10216
10187
  onValidationError?.({
10217
10188
  error: "Validation Failed",
10218
- details: `${validation.errors.length} error(s)`,
10189
+ details: pluralize(validation.errors.length, "error", "errors", true),
10219
10190
  errors: errorMessages,
10220
10191
  isClientError: true
10221
10192
  });
10222
10193
  } else if (validation.validFiles.length > 0) {
10223
- let details = `${validation.validFiles.length} file(s) ready`;
10194
+ let details = `${pluralize(validation.validFiles.length, "file", "files", true)} ready`;
10224
10195
  if (validation.warnings.length > 0) {
10225
- details += ` (${validation.warnings.length} empty file(s) excluded)`;
10196
+ details += ` (${pluralize(validation.warnings.length, "empty file", "empty files", true)} excluded)`;
10226
10197
  }
10227
10198
  setState({
10228
10199
  value: "ready",
@@ -10248,7 +10219,7 @@ function useDrop(options) {
10248
10219
  needsBuild: false,
10249
10220
  status: {
10250
10221
  title: "All files excluded",
10251
- 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)`,
10252
10223
  warnings: validation.warnings.map((w) => `${w.file}: ${w.message}`)
10253
10224
  }
10254
10225
  });
@@ -10275,7 +10246,7 @@ function useDrop(options) {
10275
10246
  const clientError = {
10276
10247
  error: isValidation ? "Validation Failed" : "Processing Failed",
10277
10248
  details: isValidation ? message : `Failed to process files: ${message}`,
10278
- errors: isValidation ? [message] : [],
10249
+ errors: [],
10279
10250
  isClientError: true
10280
10251
  };
10281
10252
  setState({
@@ -10285,8 +10256,7 @@ function useDrop(options) {
10285
10256
  needsBuild: false,
10286
10257
  status: {
10287
10258
  title: clientError.error,
10288
- details: clientError.details,
10289
- ...clientError.errors.length > 0 && { errors: clientError.errors }
10259
+ details: clientError.details
10290
10260
  }
10291
10261
  });
10292
10262
  onValidationError?.(clientError);
@@ -10338,11 +10308,7 @@ function useDrop(options) {
10338
10308
  } else {
10339
10309
  const file = item.getAsFile();
10340
10310
  if (file) {
10341
- Object.defineProperty(file, "webkitRelativePath", {
10342
- value: file.name,
10343
- writable: false,
10344
- configurable: true
10345
- });
10311
+ setRelativePath(file, file.name);
10346
10312
  files.push(file);
10347
10313
  }
10348
10314
  }
@@ -10430,6 +10396,6 @@ mime-db/index.js:
10430
10396
  *)
10431
10397
  */
10432
10398
 
10433
- export { FILE_STATUSES, createProcessedFile, extractZipToFiles, formatFileSize, getMimeType, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree, useDrop };
10399
+ export { FILE_STATUSES, createProcessedFile, extractZipToFiles, getMimeType, isZipFile, normalizePath, setRelativePath, stripCommonPrefix, traverseFileTree, useDrop };
10434
10400
  //# sourceMappingURL=index.js.map
10435
10401
  //# sourceMappingURL=index.js.map