@shipstatic/ship 0.1.5 → 0.1.6

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/env.ts","../src/lib/md5.ts","../src/lib/browser-files.ts","../node_modules/.pnpm/junk@4.0.1/node_modules/junk/index.js","../src/lib/junk.ts"],"sourcesContent":["/**\n * @file Environment detection utilities for the Ship SDK.\n * Helps in determining whether the SDK is running in a Node.js, browser, or unknown environment.\n */\n\n/**\n * Represents the detected or simulated JavaScript execution environment.\n */\nexport type ExecutionEnvironment = 'browser' | 'node' | 'unknown';\n\n/** @internal Environment override for testing. */\nlet _testEnvironment: ExecutionEnvironment | null = null;\n\n/**\n * **FOR TESTING PURPOSES ONLY.**\n *\n * Allows tests to override the detected environment, forcing the SDK to behave\n * as if it's running in the specified environment.\n *\n * @param env - The environment to simulate ('node', 'browser', 'unknown'),\n * or `null` to clear the override and revert to actual environment detection.\n * @internal\n */\nexport function __setTestEnvironment(env: ExecutionEnvironment | null): void {\n _testEnvironment = env;\n}\n\n/**\n * Detects the actual JavaScript execution environment (Node.js, browser, or unknown)\n * by checking for characteristic global objects.\n * @returns The detected environment as {@link ExecutionEnvironment}.\n * @internal\n */\nfunction detectEnvironment(): ExecutionEnvironment {\n // Check for Node.js environment\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return 'node';\n }\n\n // Check for Browser environment (including Web Workers)\n if (typeof window !== 'undefined' || typeof self !== 'undefined') {\n return 'browser';\n }\n\n return 'unknown';\n}\n\n/**\n * Gets the current effective execution environment.\n *\n * This function first checks if a test environment override is active via {@link __setTestEnvironment}.\n * If not, it detects the actual environment (Node.js, browser, or unknown).\n *\n * @returns The current execution environment: 'browser', 'node', or 'unknown'.\n * @public\n */\nexport function getENV(): ExecutionEnvironment {\n // Return test override if set\n if (_testEnvironment) {\n return _testEnvironment;\n }\n \n // Detect actual environment\n return detectEnvironment();\n}\n","/**\n * @file Simplified MD5 calculation utility with separate environment handlers.\n */\nimport { getENV } from './env';\nimport { ShipError } from '@shipstatic/types';\n\nexport interface MD5Result {\n md5: string;\n}\n\n/**\n * Browser-specific MD5 calculation for Blob/File objects\n */\nasync function calculateMD5Browser(blob: Blob): Promise<MD5Result> {\n const SparkMD5 = (await import('spark-md5')).default;\n \n return new Promise((resolve, reject) => {\n const chunkSize = 2097152; // 2MB chunks\n const chunks = Math.ceil(blob.size / chunkSize);\n let currentChunk = 0;\n const spark = new SparkMD5.ArrayBuffer();\n const fileReader = new FileReader();\n\n const loadNext = () => {\n const start = currentChunk * chunkSize;\n const end = Math.min(start + chunkSize, blob.size);\n fileReader.readAsArrayBuffer(blob.slice(start, end));\n };\n\n fileReader.onload = (e) => {\n const result = e.target?.result as ArrayBuffer;\n if (!result) {\n reject(ShipError.business('Failed to read file chunk'));\n return;\n }\n \n spark.append(result);\n currentChunk++;\n \n if (currentChunk < chunks) {\n loadNext();\n } else {\n resolve({ md5: spark.end() });\n }\n };\n\n fileReader.onerror = () => {\n reject(ShipError.business('Failed to calculate MD5: FileReader error'));\n };\n\n loadNext();\n });\n}\n\n/**\n * Node.js-specific MD5 calculation for Buffer or file path\n */\nasync function calculateMD5Node(input: Buffer | string): Promise<MD5Result> {\n const crypto = await import('crypto');\n \n if (Buffer.isBuffer(input)) {\n const hash = crypto.createHash('md5');\n hash.update(input);\n return { md5: hash.digest('hex') };\n }\n \n // Handle file path\n const fs = await import('fs');\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('md5');\n const stream = fs.createReadStream(input);\n \n stream.on('error', err => \n reject(ShipError.business(`Failed to read file for MD5: ${err.message}`))\n );\n stream.on('data', chunk => hash.update(chunk));\n stream.on('end', () => resolve({ md5: hash.digest('hex') }));\n });\n}\n\n/**\n * Unified MD5 calculation that delegates to environment-specific handlers\n */\nexport async function calculateMD5(input: Blob | Buffer | string): Promise<MD5Result> {\n const env = getENV();\n \n if (env === 'browser') {\n if (!(input instanceof Blob)) {\n throw ShipError.business('Invalid input for browser MD5 calculation: Expected Blob or File.');\n }\n return calculateMD5Browser(input);\n }\n \n if (env === 'node') {\n if (!(Buffer.isBuffer(input) || typeof input === 'string')) {\n throw ShipError.business('Invalid input for Node.js MD5 calculation: Expected Buffer or file path string.');\n }\n return calculateMD5Node(input);\n }\n \n throw ShipError.business('Unknown or unsupported execution environment for MD5 calculation.');\n}\n","/**\n * @file Browser-specific file utilities for the Ship SDK.\n * Provides helpers for processing browser files into deploy-ready objects and extracting common directory info.\n */\nimport { getENV } from './env.js';\nimport { StaticFile } from '../types.js';\nimport { calculateMD5 } from './md5.js';\nimport { ShipError } from '@shipstatic/types';\nimport { findCommonParentDirectory, normalizeWebPath } from './path.js';\nimport { filterJunk } from './junk.js';\n\n\n/**\n * Internal structure representing a browser file to be processed for deploy.\n * @internal\n */\ninterface BrowserFileProcessItem {\n file: File;\n relativePath: string;\n}\n\n/**\n * Processes browser files (FileList or File[]) into an array of StaticFile objects ready for deploy.\n * Calculates MD5, filters junk files, and determines relative paths (stripping basePath if provided).\n *\n * @param browserFiles - FileList or File[] to process for deploy.\n * @param options - Optional processing options (basePath for path stripping, stripCommonPrefix).\n * @returns Promise resolving to an array of StaticFile objects.\n * @throws {ShipClientError} If called outside a browser or with invalid input.\n */\nexport async function processFilesForBrowser(\n browserFiles: FileList | File[],\n options: { explicitBaseDirInput?: string; stripCommonPrefix?: boolean } = {}\n): Promise<StaticFile[]> {\n if (getENV() !== 'browser') {\n throw ShipError.business('processFilesForBrowser can only be called in a browser environment.');\n }\n\n const { explicitBaseDirInput, stripCommonPrefix } = options;\n const initialFileInfos: BrowserFileProcessItem[] = [];\n const filesArray = Array.isArray(browserFiles) ? browserFiles : Array.from(browserFiles);\n \n // If stripCommonPrefix is true and no explicit basePath is provided,\n // Determine the parent directory for path stripping if applicable\n let parentDir = '';\n if (stripCommonPrefix) {\n parentDir = findBrowserCommonParentDirectory(browserFiles);\n } else if (explicitBaseDirInput) {\n parentDir = explicitBaseDirInput;\n }\n\n // Prepare the initial file information with appropriate relative paths\n for (const file of filesArray) {\n let relativePath = (file as any).webkitRelativePath || file.name;\n if (parentDir) {\n // Normalize all paths to use forward slashes\n relativePath = normalizeWebPath(relativePath);\n const basePathWithSlash = parentDir.endsWith('/') ? parentDir : `${parentDir}/`;\n // Robustly strip deeply nested basePath prefix\n if (relativePath === parentDir || relativePath === basePathWithSlash || relativePath.startsWith(basePathWithSlash)) {\n relativePath = relativePath.substring(basePathWithSlash.length);\n }\n }\n // Always normalize output path to forward slashes\n relativePath = normalizeWebPath(relativePath);\n initialFileInfos.push({ file, relativePath });\n }\n\n // Filter out junk files\n const allRelativePaths = initialFileInfos.map(info => info.relativePath);\n const nonJunkRelativePathsArray = filterJunk(allRelativePaths);\n const nonJunkRelativePathsSet = new Set(nonJunkRelativePathsArray);\n\n // Create StaticFile objects for each valid file\n const result: StaticFile[] = [];\n for (const fileInfo of initialFileInfos) {\n // Skip junk files and empty files\n if (!nonJunkRelativePathsSet.has(fileInfo.relativePath) || fileInfo.file.size === 0) {\n continue;\n }\n \n // Calculate MD5 hash\n const { md5 } = await calculateMD5(fileInfo.file);\n \n // Create and add the StaticFile\n result.push({\n content: fileInfo.file,\n path: fileInfo.relativePath,\n size: fileInfo.file.size,\n md5,\n });\n }\n \n return result;\n}\n\n/**\n * Finds the common parent directory from a FileList or File[] using webkitRelativePath.\n * Useful for stripping a common prefix if files are selected from a single folder.\n *\n * @param files - FileList or File[] to analyze.\n * @returns Common parent directory string, or empty string if not consistent.\n * @throws {ShipClientError} If called outside a browser.\n */\nexport function findBrowserCommonParentDirectory(files: FileList | File[]): string {\n if (getENV() !== 'browser') {\n throw ShipError.business('findBrowserCommonParentDirectory can only be called in a browser environment.');\n }\n if (!files || files.length === 0) return '';\n \n const paths: (string | null | undefined)[] = Array.from(files)\n .map(file => (file as any).webkitRelativePath);\n\n // If any file is missing webkitRelativePath, we can't determine a common parent.\n if (paths.some(p => !p)) {\n return '';\n }\n\n return findCommonParentDirectory(paths as string[], '/');\n}\n","const ignoreList = [\n\t// # All\n\t'^npm-debug\\\\.log$', // Error log for npm\n\t'^\\\\..*\\\\.swp$', // Swap file for vim state\n\n\t// # macOS\n\t'^\\\\.DS_Store$', // Stores custom folder attributes\n\t'^\\\\.AppleDouble$', // Stores additional file resources\n\t'^\\\\.LSOverride$', // Contains the absolute path to the app to be used\n\t'^Icon\\\\r$', // Custom Finder icon: http://superuser.com/questions/298785/icon-file-on-os-x-desktop\n\t'^\\\\._.*', // Thumbnail\n\t'^\\\\.Spotlight-V100(?:$|\\\\/)', // Directory that might appear on external disk\n\t'\\\\.Trashes', // File that might appear on external disk\n\t'^__MACOSX$', // Resource fork\n\n\t// # Linux\n\t'~$', // Backup file\n\n\t// # Windows\n\t'^Thumbs\\\\.db$', // Image file cache\n\t'^ehthumbs\\\\.db$', // Folder config file\n\t'^[Dd]esktop\\\\.ini$', // Stores custom folder attributes\n\t'@eaDir$', // Synology Diskstation \"hidden\" folder where the server stores thumbnails\n];\n\nexport const junkRegex = new RegExp(ignoreList.join('|'));\n\nexport function isJunk(filename) {\n\treturn junkRegex.test(filename);\n}\n\nexport function isNotJunk(filename) {\n\treturn !isJunk(filename);\n}\n","/**\n * @file Utility for filtering out junk files and directories from file paths\n * \n * This module provides functionality to filter out common system junk files and directories\n * from a list of file paths. It uses the 'junk' package to identify junk filenames and\n * a custom list to filter out common junk directories.\n */\nimport { isJunk } from 'junk';\n\n/**\n * List of directory names considered as junk\n * \n * Files within these directories (at any level in the path hierarchy) will be excluded.\n * The comparison is case-insensitive for cross-platform compatibility.\n * \n * @internal\n */\nexport const JUNK_DIRECTORIES = [\n '__MACOSX',\n '.Trashes',\n '.fseventsd',\n '.Spotlight-V100',\n] as const;\n\n/**\n * Filters an array of file paths, removing those considered junk\n * \n * A path is filtered out if either:\n * 1. The basename is identified as junk by the 'junk' package (e.g., .DS_Store, Thumbs.db)\n * 2. Any directory segment in the path matches an entry in JUNK_DIRECTORIES (case-insensitive)\n *\n * All path separators are normalized to forward slashes for consistent cross-platform behavior.\n * \n * @param filePaths - An array of file path strings to filter\n * @returns A new array containing only non-junk file paths\n */\nexport function filterJunk(filePaths: string[]): string[] {\n if (!filePaths || filePaths.length === 0) {\n return [];\n }\n\n return filePaths.filter(filePath => {\n if (!filePath) {\n return false; // Exclude null or undefined paths\n }\n\n // Normalize path separators to forward slashes and split into segments\n const parts = filePath.replace(/\\\\/g, '/').split('/').filter(Boolean);\n if (parts.length === 0) return true;\n \n // Check if the basename is a junk file (using junk package)\n const basename = parts[parts.length - 1];\n if (isJunk(basename)) {\n return false;\n }\n\n // Check if any directory segment is in our junk directories list\n const directorySegments = parts.slice(0, -1);\n for (const segment of directorySegments) {\n if (JUNK_DIRECTORIES.some(junkDir => \n segment.toLowerCase() === junkDir.toLowerCase())) {\n return false;\n }\n }\n\n return true;\n });\n}\n"],"mappings":"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","names":["_testEnvironment","__setTestEnvironment","env","detectEnvironment","getENV","ShipError","calculateMD5Browser","blob","SparkMD5","resolve","reject","chunks","currentChunk","spark","fileReader","loadNext","start","end","e","result","calculateMD5Node","input","crypto","hash","fs","stream","err","chunk","calculateMD5","env","getENV","ShipError","ignoreList","junkRegex","isJunk","filename","JUNK_DIRECTORIES","filterJunk","filePaths","filePath","parts","basename","isJunk","directorySegments","segment","junkDir","processFilesForBrowser","browserFiles","options","getENV","ShipError","explicitBaseDirInput","stripCommonPrefix","initialFileInfos","filesArray","parentDir","findBrowserCommonParentDirectory","file","relativePath","normalizeWebPath","basePathWithSlash","allRelativePaths","info","nonJunkRelativePathsArray","filterJunk","nonJunkRelativePathsSet","result","fileInfo","md5","calculateMD5","files","paths","p","findCommonParentDirectory"]}