@shipstatic/ship 0.4.20 → 0.4.21

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/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../node_modules/.pnpm/@shipstatic+types@0.4.21/node_modules/@shipstatic/types/dist/index.js","../src/shared/core/platform-config.ts","../src/shared/lib/env.ts","../src/shared/lib/md5.ts","../src/node/core/config.ts","../src/shared/lib/junk.ts","../src/shared/lib/path.ts","../src/shared/lib/deploy-paths.ts","../src/node/core/node-files.ts","../src/node/cli/index.ts","../src/shared/api/http.ts","../src/shared/events.ts","../src/shared/base-ship.ts","../src/shared/resources.ts","../src/shared/core/config.ts","../src/shared/lib/spa.ts","../src/node/index.ts","../src/node/core/deploy-body.ts","../src/shared/utils/mimeType.ts","../src/node/cli/utils.ts","../src/node/cli/formatters.ts","../src/node/cli/completion.ts","../src/node/cli/error-handling.ts"],"sourcesContent":["/**\n * @file Shared TypeScript types, constants, and utilities for the Shipstatic platform.\n * This package is the single source of truth for all shared data structures.\n */\n// =============================================================================\n// I. CORE ENTITIES\n// =============================================================================\n/**\n * Deployment status constants\n */\nexport const DeploymentStatus = {\n PENDING: 'pending',\n SUCCESS: 'success',\n FAILED: 'failed',\n DELETING: 'deleting'\n};\n// =============================================================================\n// DOMAIN TYPES\n// =============================================================================\n/**\n * Domain status constants\n *\n * - PENDING: DNS not configured\n * - PARTIAL: DNS partially configured\n * - SUCCESS: DNS fully verified\n * - PAUSED: Domain paused due to plan enforcement (billing)\n */\nexport const DomainStatus = {\n PENDING: 'pending',\n PARTIAL: 'partial',\n SUCCESS: 'success',\n PAUSED: 'paused'\n};\n// =============================================================================\n// ACCOUNT TYPES\n// =============================================================================\n/**\n * Account plan constants\n */\nexport const AccountPlan = {\n FREE: 'free',\n STANDARD: 'standard',\n SPONSORED: 'sponsored',\n ENTERPRISE: 'enterprise',\n SUSPENDED: 'suspended',\n TERMINATING: 'terminating',\n TERMINATED: 'terminated'\n};\n// =============================================================================\n// ERROR SYSTEM\n// =============================================================================\n/**\n * All possible error types in the Shipstatic platform\n * Names are developer-friendly while wire format stays consistent\n */\nexport var ErrorType;\n(function (ErrorType) {\n /** Validation failed (400) */\n ErrorType[\"Validation\"] = \"validation_failed\";\n /** Resource not found (404) */\n ErrorType[\"NotFound\"] = \"not_found\";\n /** Rate limit exceeded (429) */\n ErrorType[\"RateLimit\"] = \"rate_limit_exceeded\";\n /** Authentication required (401) */\n ErrorType[\"Authentication\"] = \"authentication_failed\";\n /** Business logic error (400) */\n ErrorType[\"Business\"] = \"business_logic_error\";\n /** API server error (500) - renamed from Internal for clarity */\n ErrorType[\"Api\"] = \"internal_server_error\";\n /** Network/connection error */\n ErrorType[\"Network\"] = \"network_error\";\n /** Operation was cancelled */\n ErrorType[\"Cancelled\"] = \"operation_cancelled\";\n /** File operation error */\n ErrorType[\"File\"] = \"file_error\";\n /** Configuration error */\n ErrorType[\"Config\"] = \"config_error\";\n})(ErrorType || (ErrorType = {}));\n/**\n * Categorizes error types for better type checking\n */\nconst ERROR_CATEGORIES = {\n client: new Set([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),\n network: new Set([ErrorType.Network]),\n auth: new Set([ErrorType.Authentication]),\n};\n/**\n * Simple unified error class for both API and SDK\n */\nexport class ShipError extends Error {\n type;\n status;\n details;\n constructor(type, message, status, details) {\n super(message);\n this.type = type;\n this.status = status;\n this.details = details;\n this.name = 'ShipError';\n }\n /** Convert to wire format */\n toResponse() {\n // For security, exclude internal details from authentication errors in API responses\n const details = this.type === ErrorType.Authentication && this.details?.internal\n ? undefined\n : this.details;\n return {\n error: this.type,\n message: this.message,\n status: this.status,\n details\n };\n }\n /** Create from wire format */\n static fromResponse(response) {\n return new ShipError(response.error, response.message, response.status, response.details);\n }\n // Factory methods for common errors\n static validation(message, details) {\n return new ShipError(ErrorType.Validation, message, 400, details);\n }\n static notFound(resource, id) {\n const message = id ? `${resource} ${id} not found` : `${resource} not found`;\n return new ShipError(ErrorType.NotFound, message, 404);\n }\n static rateLimit(message = \"Too many requests\") {\n return new ShipError(ErrorType.RateLimit, message, 429);\n }\n static authentication(message = \"Authentication required\", details) {\n return new ShipError(ErrorType.Authentication, message, 401, details);\n }\n static business(message, status = 400) {\n return new ShipError(ErrorType.Business, message, status);\n }\n static network(message, cause) {\n return new ShipError(ErrorType.Network, message, undefined, { cause });\n }\n static cancelled(message) {\n return new ShipError(ErrorType.Cancelled, message);\n }\n static file(message, filePath) {\n return new ShipError(ErrorType.File, message, undefined, { filePath });\n }\n static config(message, details) {\n return new ShipError(ErrorType.Config, message, undefined, details);\n }\n static api(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n static database(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n static storage(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n // Helper getter for accessing file path from details\n get filePath() {\n return this.details?.filePath;\n }\n // Helper methods for error type checking using categorization\n isClientError() {\n return ERROR_CATEGORIES.client.has(this.type);\n }\n isNetworkError() {\n return ERROR_CATEGORIES.network.has(this.type);\n }\n isAuthError() {\n return ERROR_CATEGORIES.auth.has(this.type);\n }\n isValidationError() {\n return this.type === ErrorType.Validation;\n }\n isFileError() {\n return this.type === ErrorType.File;\n }\n isConfigError() {\n return this.type === ErrorType.Config;\n }\n // Generic type checker\n isType(errorType) {\n return this.type === errorType;\n }\n}\n/**\n * Type guard to check if an unknown value is a ShipError.\n *\n * Uses structural checking instead of instanceof to handle module duplication\n * in bundled applications where multiple copies of the ShipError class may exist.\n *\n * @example\n * if (isShipError(error)) {\n * console.log(error.status, error.message);\n * }\n */\nexport function isShipError(error) {\n return (error !== null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === 'ShipError' &&\n 'status' in error);\n}\n/**\n * Allowed MIME types for static web hosting.\n *\n * This is a static platform constant, not per-user configuration.\n * Safe to share across frontend/backend due to atomic deploys.\n *\n * Validation rules:\n * - Exact match: 'application/json' allows only 'application/json'\n * - Prefix match: 'image/' allows all image types (png, jpeg, webp, etc.)\n *\n * Coverage: 100% of browser-renderable web content\n * - Core web (HTML, CSS, JS, WASM)\n * - Media (images, audio, video, fonts)\n * - Documents (PDF, Markdown, data formats)\n * - Modern web (PWA, 3D, structured data)\n *\n * ============================================================================\n * INTENTIONALLY EXCLUDED (Security & Platform Integrity)\n * ============================================================================\n *\n * We are a WEB HOSTING platform, not a file distribution service.\n * GitHub Pages-style parity for renderable content, more restrictive for downloads.\n *\n * 1. EXECUTABLES (Malware Distribution)\n * → .exe, .msi, .dmg, .deb, .rpm, .app, .apk, .jar\n * → Reason: Direct malware delivery vector\n * → Alternative: Use GitHub Releases or dedicated software distribution CDN\n *\n * 2. ARCHIVES (Piracy & Abuse)\n * → .zip, .rar, .tar, .gz, .7z, .bz2\n * → Reason: File sharing abuse, can contain executables, no web rendering\n * → Alternative: Use file hosting service (Dropbox, Google Drive) or GitHub Releases\n *\n * 3. SERVER-SIDE SCRIPTS (Credential Leakage)\n * → .php, .asp, .jsp, .cgi\n * → Reason: Source code exposure (database passwords, API keys, secrets)\n * → Alternative: Static hosting only - use serverless functions for backends\n *\n * 4. SHELL SCRIPTS (OS Execution)\n * → .sh, .bash, .bat, .cmd, .ps1, .vbs\n * → Reason: Execute on user's OS outside browser sandbox, social engineering risk\n * → Alternative: Embed code examples in HTML <pre><code> or link to GitHub repo\n *\n * 5. PROGRAMMING LANGUAGE SOURCE (Platform Scope)\n * → .py, .rb, .pl, .java, .c, .cpp, .cs, .go, .rs\n * → Reason: Not web-renderable, better served by GitHub/GitLab/Bitbucket\n * → Alternative: Use GitHub for code hosting, link to repository\n *\n * 6. OFFICE DOCUMENTS (Macro Malware)\n * → .doc, .docx, .xls, .xlsx, .ppt, .pptx\n * → Reason: Can contain VBA macros, active exploits in the wild\n * → Alternative: Use PDF for documents (fully supported)\n *\n * 7. GENERIC BINARIES (Unvalidatable)\n * → application/octet-stream\n * → Reason: Too broad - allows any binary format, cannot moderate effectively\n * → Alternative: Use specific MIME types for known formats\n *\n * ============================================================================\n * Security Model:\n * - Browser sandbox (JS/WASM execute safely in controlled environment)\n * - AI content moderation (scans text/image content for abuse)\n * - No server-side execution (static files only)\n * - Explicit allowlist (only approved formats, reject unknown)\n * ============================================================================\n */\nexport const ALLOWED_MIME_TYPES = [\n // =========================================================================\n // TEXT CONTENT (explicit list - no prefix matching for security)\n // =========================================================================\n // Core web documents\n 'text/html', // HTML pages\n 'text/css', // Stylesheets\n 'text/plain', // Plain text (robots.txt, .well-known/*, LICENSE, README.txt)\n 'text/markdown', // Markdown files (.md)\n 'text/xml', // XML files\n // Data formats\n 'text/csv', // CSV data files\n 'text/yaml', // YAML config files\n // Web-specific formats\n 'text/vtt', // WebVTT video subtitles/captions (accessibility)\n 'text/calendar', // iCalendar (.ics) event files\n // JavaScript (legacy MIME type, still widely used by ~50% of servers)\n 'text/javascript',\n // Modern web development formats (uncompiled source)\n 'text/typescript', // TypeScript source (.ts)\n 'text/tsx', // TypeScript JSX (.tsx)\n 'text/jsx', // React JSX (.jsx)\n 'text/x-scss', // SCSS preprocessor\n 'text/x-sass', // Sass preprocessor\n 'text/x-less', // Less preprocessor\n 'text/stylus', // Stylus preprocessor\n 'text/x-vue', // Vue single-file components (.vue)\n 'text/x-svelte', // Svelte components (.svelte)\n // =========================================================================\n // MEDIA (prefix matching - covers all common subtypes)\n // =========================================================================\n // Images: PNG, JPEG, GIF, SVG, WebP, AVIF, HEIC, BMP, TIFF, ICO, etc.\n 'image/',\n // Audio: MP3, OGG, WAV, WebM, AAC, FLAC, Opus, etc.\n 'audio/',\n // Video: MP4, WebM, OGG, QuickTime, etc.\n 'video/',\n // Modern fonts: WOFF2, WOFF, TTF, OTF\n 'font/',\n // =========================================================================\n // CORE WEB APPLICATION TYPES\n // =========================================================================\n // JavaScript (multiple MIME types for compatibility)\n 'application/javascript', // Modern standard (RFC 9239)\n 'application/ecmascript', // ECMAScript (legacy but still used)\n 'application/x-javascript', // Legacy variant (old CDNs, Apache configs)\n // WebAssembly (modern web apps, games, compute-heavy workloads)\n 'application/wasm',\n // JSON and structured data\n 'application/json',\n 'application/ld+json', // JSON-LD for structured data / SEO (Schema.org, Open Graph)\n 'application/manifest+json', // PWA web app manifests\n // Development tools\n 'application/source-map', // Source maps (.js.map, .css.map) for debugging\n // XML and feeds\n 'application/xml',\n 'application/xhtml+xml', // XHTML - XML-compliant HTML (legacy sites)\n 'application/rss+xml', // RSS feeds (blogs, podcasts)\n 'application/atom+xml', // Atom feeds\n // Configuration formats\n 'application/yaml', // YAML configs (static site generators)\n // Documents\n 'application/pdf', // PDF documents\n // =========================================================================\n // 3D FORMATS (industry standard only)\n // =========================================================================\n // glTF - Khronos standard for 3D web content\n 'model/gltf+json', // glTF JSON format\n 'model/gltf-binary', // GLB binary format\n // =========================================================================\n // LEGACY COMPATIBILITY\n // =========================================================================\n // Video (some tools detect MP4 as application/mp4)\n 'application/mp4',\n // Legacy font MIME types (Bootstrap, Font Awesome, IE compatibility)\n 'application/font-woff',\n 'application/font-woff2',\n 'application/x-font-woff',\n 'application/x-woff',\n 'application/vnd.ms-fontobject', // EOT files (Internet Explorer)\n 'application/x-font-ttf',\n 'application/x-font-truetype',\n 'application/x-font-otf',\n 'application/x-font-opentype',\n];\n/**\n * Check if a MIME type is allowed for upload.\n *\n * Supports both exact matches and prefix matches:\n * - 'application/json' matches 'application/json' exactly\n * - 'text/' matches 'text/plain', 'text/html', etc.\n *\n * @example\n * isAllowedMimeType('text/plain') // true (prefix match)\n * isAllowedMimeType('application/json') // true (exact match)\n * isAllowedMimeType('application/wasm') // false (not allowed)\n */\nexport function isAllowedMimeType(mimeType) {\n return ALLOWED_MIME_TYPES.some(allowed => mimeType === allowed || mimeType.startsWith(allowed));\n}\n// API Key Configuration\nexport const API_KEY_PREFIX = 'ship-';\nexport const API_KEY_HEX_LENGTH = 64;\nexport const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69\n// Deploy Token Configuration\nexport const DEPLOY_TOKEN_PREFIX = 'token-';\nexport const DEPLOY_TOKEN_HEX_LENGTH = 64;\nexport const DEPLOY_TOKEN_TOTAL_LENGTH = DEPLOY_TOKEN_PREFIX.length + DEPLOY_TOKEN_HEX_LENGTH; // 70\n// Authentication Method Constants\nexport const AuthMethod = {\n JWT: 'jwt',\n API_KEY: 'apiKey',\n TOKEN: 'token',\n WEBHOOK: 'webhook',\n SYSTEM: 'system'\n};\n// Deployment Configuration\nexport const DEPLOYMENT_CONFIG_FILENAME = 'ship.json';\n// =============================================================================\n// VALIDATION UTILITIES\n// =============================================================================\n/**\n * Validate API key format\n */\nexport function validateApiKey(apiKey) {\n if (!apiKey.startsWith(API_KEY_PREFIX)) {\n throw ShipError.validation(`API key must start with \"${API_KEY_PREFIX}\"`);\n }\n if (apiKey.length !== API_KEY_TOTAL_LENGTH) {\n throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);\n }\n const hexPart = apiKey.slice(API_KEY_PREFIX.length);\n if (!/^[a-f0-9]{64}$/i.test(hexPart)) {\n throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after \"${API_KEY_PREFIX}\" prefix`);\n }\n}\n/**\n * Validate deploy token format\n */\nexport function validateDeployToken(deployToken) {\n if (!deployToken.startsWith(DEPLOY_TOKEN_PREFIX)) {\n throw ShipError.validation(`Deploy token must start with \"${DEPLOY_TOKEN_PREFIX}\"`);\n }\n if (deployToken.length !== DEPLOY_TOKEN_TOTAL_LENGTH) {\n throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN_TOTAL_LENGTH} characters total (${DEPLOY_TOKEN_PREFIX} + ${DEPLOY_TOKEN_HEX_LENGTH} hex chars)`);\n }\n const hexPart = deployToken.slice(DEPLOY_TOKEN_PREFIX.length);\n if (!/^[a-f0-9]{64}$/i.test(hexPart)) {\n throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN_HEX_LENGTH} hexadecimal characters after \"${DEPLOY_TOKEN_PREFIX}\" prefix`);\n }\n}\n/**\n * Validate API URL format\n */\nexport function validateApiUrl(apiUrl) {\n try {\n const url = new URL(apiUrl);\n if (!['http:', 'https:'].includes(url.protocol)) {\n throw ShipError.validation('API URL must use http:// or https:// protocol');\n }\n if (url.pathname !== '/' && url.pathname !== '') {\n throw ShipError.validation('API URL must not contain a path');\n }\n if (url.search || url.hash) {\n throw ShipError.validation('API URL must not contain query parameters or fragments');\n }\n }\n catch (error) {\n if (isShipError(error)) {\n throw error;\n }\n throw ShipError.validation('API URL must be a valid URL');\n }\n}\n/**\n * Check if a string matches the deployment ID pattern (word-word-alphanumeric7)\n * Example: \"happy-cat-abc1234\"\n */\nexport function isDeployment(input) {\n return /^[a-z]+-[a-z]+-[a-z0-9]{7}$/i.test(input);\n}\n// =============================================================================\n// PLATFORM CONSTANTS\n// =============================================================================\n/** Default API URL if not otherwise configured. */\nexport const DEFAULT_API = 'https://api.shipstatic.com';\n// =============================================================================\n// FILE UPLOAD TYPES\n// =============================================================================\n/**\n * File status constants for validation state tracking\n */\nexport const FileValidationStatus = {\n PENDING: 'pending',\n PROCESSING_ERROR: 'processing_error',\n EMPTY_FILE: 'empty_file',\n VALIDATION_FAILED: 'validation_failed',\n READY: 'ready',\n};\n// =============================================================================\n// DOMAIN UTILITIES\n// =============================================================================\n/**\n * Check if a domain is a platform domain (subdomain of our platform).\n * Platform domains are free and don't require DNS verification.\n *\n * @example isPlatformDomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → true\n * @example isPlatformDomain(\"example.com\", \"shipstatic.dev\") → false\n */\nexport function isPlatformDomain(domain, platformDomain) {\n return domain.endsWith(`.${platformDomain}`);\n}\n/**\n * Check if a domain is a custom domain (not a platform subdomain).\n * Custom domains are billable and require DNS verification.\n *\n * @example isCustomDomain(\"example.com\", \"shipstatic.dev\") → true\n * @example isCustomDomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → false\n */\nexport function isCustomDomain(domain, platformDomain) {\n return !isPlatformDomain(domain, platformDomain);\n}\n/**\n * Extract subdomain from a platform domain.\n * Returns null if not a platform domain.\n *\n * @example extractSubdomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → \"www\"\n * @example extractSubdomain(\"example.com\", \"shipstatic.dev\") → null\n */\nexport function extractSubdomain(domain, platformDomain) {\n if (!isPlatformDomain(domain, platformDomain)) {\n return null;\n }\n return domain.slice(0, -(platformDomain.length + 1)); // +1 for the dot\n}\n/**\n * Generate deployment URL from deployment ID and platform domain\n */\nexport function generateDeploymentUrl(deployment, platformDomain) {\n const domain = platformDomain || 'shipstatic.com';\n return `https://${deployment}.${domain}`;\n}\n/**\n * Generate URL for a domain.\n * Domains are stored as FQDNs, so this just prepends https://\n */\nexport function generateDomainUrl(domain) {\n return `https://${domain}`;\n}\n// =============================================================================\n// TAG UTILITIES\n// =============================================================================\n/**\n * Tag validation constraints shared across UI and API.\n * These rules define the single source of truth for tag validation.\n */\nexport const TAG_CONSTRAINTS = {\n /** Minimum tag length in characters */\n MIN_LENGTH: 3,\n /** Maximum tag length in characters (concise tags, matches Stack Overflow's original limit) */\n MAX_LENGTH: 25,\n /** Maximum number of tags allowed per resource */\n MAX_COUNT: 10,\n /** Allowed separator characters between tag segments */\n SEPARATORS: '._-',\n};\n/**\n * Tag validation pattern.\n * Must start and end with alphanumeric (a-z, 0-9).\n * Can contain separators (. _ -) between segments, but not consecutive.\n *\n * Valid examples: 'production', 'v1.2.3', 'api_v2', 'us-east-1'\n * Invalid examples: 'ab' (too short), '-prod' (starts with separator), 'foo--bar' (consecutive separators)\n */\nexport const TAG_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;\n/**\n * Serialize tags array to JSON string for database storage.\n * Returns null for empty or undefined arrays.\n *\n * @example serializeTags(['web', 'production']) → '[\"web\",\"production\"]'\n * @example serializeTags([]) → null\n * @example serializeTags(undefined) → null\n */\nexport function serializeTags(tags) {\n if (!tags || tags.length === 0)\n return null;\n return JSON.stringify(tags);\n}\n/**\n * Deserialize tags from JSON string to array.\n * Returns undefined for null/empty strings.\n *\n * @example deserializeTags('[\"web\",\"production\"]') → ['web', 'production']\n * @example deserializeTags(null) → undefined\n * @example deserializeTags('') → undefined\n */\nexport function deserializeTags(tagsJson) {\n if (!tagsJson)\n return undefined;\n try {\n const parsed = JSON.parse(tagsJson);\n return Array.isArray(parsed) && parsed.length > 0 ? parsed : undefined;\n }\n catch {\n return undefined;\n }\n}\n","/**\n * @file Platform configuration management for the Ship SDK.\n * Implements fail-fast dynamic configuration with mandatory API fetch.\n */\n\nimport type { ConfigResponse } from '@shipstatic/types';\nimport { ShipError } from '@shipstatic/types';\n\n// Dynamic config - must be fetched from API before operations\nlet _config: ConfigResponse | null = null;\n\n/**\n * Set the current config (called after fetching from API)\n */\nexport function setConfig(config: ConfigResponse): void {\n _config = config;\n}\n\n/**\n * Get current config - throws if not initialized (fail-fast approach)\n * @throws {ShipError.config} If configuration hasn't been fetched from API\n */\nexport function getCurrentConfig(): ConfigResponse {\n if (_config === null) {\n throw ShipError.config(\n 'Platform configuration not initialized. The SDK must fetch configuration from the API before performing operations.'\n );\n }\n return _config;\n}\n\n/**\n * Check if config has been initialized from API\n */\nexport function isConfigInitialized(): boolean {\n return _config !== null;\n}\n\n/**\n * Reset config state (primarily for testing)\n * @internal\n */\nexport function resetConfig(): void {\n _config = null;\n}","/**\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.js';\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 Manages loading and validation of client configuration.\n * This module uses `cosmiconfig` to find and load configuration from various\n * file sources (e.g., `.shiprc`, `package.json`) and environment variables.\n * Configuration values are validated using Zod schemas.\n */\n\nimport { z } from 'zod';\nimport type { ShipClientOptions, DeploymentOptions } from '../../shared/types.js';\nimport { ShipError, isShipError } from '@shipstatic/types';\nimport { getENV } from '../../shared/lib/env.js';\nimport { DEFAULT_API } from '../../shared/core/constants.js';\n\n\n\n/** @internal Name of the module, used by cosmiconfig for config file searching. */\nconst MODULE_NAME = 'ship';\n\n/**\n * Zod schema for validating ship configuration.\n * @internal\n */\nconst ConfigSchema = z.object({\n apiUrl: z.string().url().optional(),\n apiKey: z.string().optional(),\n deployToken: z.string().optional()\n}).strict();\n\n/**\n * Validates configuration using Zod schema.\n * @param config - Configuration object to validate\n * @returns Validated configuration or throws error\n * @internal\n */\nfunction validateConfig(config: unknown): Partial<ShipClientOptions> {\n try {\n return ConfigSchema.parse(config);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const firstError = error.issues[0];\n const path = firstError.path.length > 0 ? ` at ${firstError.path.join('.')}` : '';\n throw ShipError.config(`Configuration validation failed${path}: ${firstError.message}`);\n }\n throw ShipError.config('Configuration validation failed');\n }\n}\n\n/**\n * Loads client configuration from files.\n * Searches for .shiprc and package.json with ship key.\n * First searches from the current directory, then from the home directory.\n * @param configFile - Optional specific config file path to load\n * @returns Configuration object or empty if not found/invalid\n * @internal\n */\nasync function loadConfigFromFile(configFile?: string): Promise<Partial<ShipClientOptions>> {\n try {\n // Only use cosmiconfig in Node.js environments\n if (getENV() !== 'node') {\n return {};\n }\n \n // Dynamically import cosmiconfig and os only in Node.js environments\n const { cosmiconfigSync } = await import('cosmiconfig');\n const os = await import('os');\n \n const explorer = cosmiconfigSync(MODULE_NAME, {\n searchPlaces: [\n `.${MODULE_NAME}rc`,\n 'package.json',\n `${os.homedir()}/.${MODULE_NAME}rc`, // Always include home directory as fallback\n ],\n stopDir: os.homedir(), // Stop searching at home directory\n });\n \n let result;\n \n // If a specific config file is provided, load it directly\n if (configFile) {\n result = explorer.load(configFile);\n } else {\n // cosmiconfig automatically searches up the directory tree\n // from current directory to stopDir (home directory)\n result = explorer.search();\n }\n \n if (result && result.config) {\n return validateConfig(result.config);\n }\n } catch (error) {\n if (isShipError(error)) throw error; // Re-throw all ShipError instances\n // Silently fail for file loading issues - this is optional config\n }\n return {};\n}\n\n/**\n * Simplified configuration loading prioritizing environment variables.\n * Only loads file config if environment variables are not set.\n * Only available in Node.js environments.\n *\n * @param configFile - Optional specific config file path to load\n * @returns Configuration object with loaded values\n * @throws {ShipInvalidConfigError} If the configuration is invalid.\n */\nexport async function loadConfig(configFile?: string): Promise<Partial<ShipClientOptions>> {\n if (getENV() !== 'node') return {};\n\n // Start with environment variables (highest priority)\n const envConfig = {\n apiUrl: process.env.SHIP_API_URL,\n apiKey: process.env.SHIP_API_KEY,\n deployToken: process.env.SHIP_DEPLOY_TOKEN,\n };\n\n // Always try to load file config for fallback values\n const fileConfig = await loadConfigFromFile(configFile);\n\n // Merge with environment variables taking precedence\n const mergedConfig = {\n apiUrl: envConfig.apiUrl ?? fileConfig.apiUrl,\n apiKey: envConfig.apiKey ?? fileConfig.apiKey,\n deployToken: envConfig.deployToken ?? fileConfig.deployToken,\n };\n\n // Validate final config\n return validateConfig(mergedConfig);\n}\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 *\n * @example\n * ```typescript\n * import { filterJunk } from '@shipstatic/ship';\n *\n * // Filter an array of file paths\n * const paths = ['index.html', '.DS_Store', '__MACOSX/file.txt', 'app.js'];\n * const clean = filterJunk(paths);\n * // Result: ['index.html', 'app.js']\n * ```\n *\n * @example\n * ```typescript\n * // Use with browser File objects\n * import { filterJunk } from '@shipstatic/ship';\n *\n * const files: File[] = [...]; // From input or drag-drop\n *\n * // Extract paths from File objects\n * const filePaths = files.map(f => f.webkitRelativePath || f.name);\n *\n * // Filter out junk paths\n * const validPaths = new Set(filterJunk(filePaths));\n *\n * // Filter the original File array\n * const validFiles = files.filter(f =>\n * validPaths.has(f.webkitRelativePath || f.name)\n * );\n * ```\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","/**\n * @file Path helper utilities that work in both browser and Node.js environments.\n * Provides environment-agnostic path manipulation functions.\n */\n\n/**\n * Finds the common parent directory from an array of directory paths.\n * Simple, unified implementation for flattenDirs functionality.\n * \n * @param dirPaths - Array of directory paths (not file paths - directories containing the files)\n * @returns The common parent directory path, or empty string if none found\n */\nexport function findCommonParent(dirPaths: string[]): string {\n if (!dirPaths || dirPaths.length === 0) return '';\n \n const normalizedPaths = dirPaths\n .filter(p => p && typeof p === 'string')\n .map(p => p.replace(/\\\\/g, '/'));\n \n if (normalizedPaths.length === 0) return '';\n if (normalizedPaths.length === 1) return normalizedPaths[0];\n\n const pathSegments = normalizedPaths.map(p => p.split('/').filter(Boolean));\n const commonSegments = [];\n const minLength = Math.min(...pathSegments.map(p => p.length));\n \n for (let i = 0; i < minLength; i++) {\n const segment = pathSegments[0][i];\n if (pathSegments.every(segments => segments[i] === segment)) {\n commonSegments.push(segment);\n } else {\n break;\n }\n }\n \n return commonSegments.join('/');\n}\n\n\n\n/**\n * Converts backslashes to forward slashes for cross-platform compatibility.\n * Does not remove leading slashes (preserves absolute paths).\n * @param path - The path to normalize\n * @returns Path with forward slashes\n */\nexport function normalizeSlashes(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\n/**\n * Normalizes a path for web usage by converting backslashes to forward slashes\n * and removing leading slashes.\n * @param path - The path to normalize\n * @returns Normalized path suitable for web deployment\n */\nexport function normalizeWebPath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\/+/, '');\n}\n\n","/**\n * @file Deploy path optimization - the core logic that makes Ship deployments clean and intuitive.\n * Automatically strips common parent directories to create clean deployment URLs.\n */\n\nimport { normalizeWebPath } from './path.js';\n\n/**\n * Represents a file ready for deployment with its optimized path\n */\nexport interface DeployFile {\n /** The clean deployment path (e.g., \"assets/style.css\") */\n path: string;\n /** Original filename */\n name: string;\n}\n\n/**\n * Core path optimization logic.\n * Transforms messy local paths into clean deployment paths.\n * \n * @example\n * Input: [\"dist/index.html\", \"dist/assets/app.js\"]\n * Output: [\"index.html\", \"assets/app.js\"]\n * \n * @param filePaths - Raw file paths from the local filesystem\n * @param options - Path processing options\n */\nexport function optimizeDeployPaths(\n filePaths: string[], \n options: { flatten?: boolean } = {}\n): DeployFile[] {\n // When flattening is disabled, keep original structure\n if (options.flatten === false) {\n return filePaths.map(path => ({\n path: normalizeWebPath(path),\n name: extractFileName(path)\n }));\n }\n\n // Find the common directory prefix to strip\n const commonPrefix = findCommonDirectory(filePaths);\n \n return filePaths.map(filePath => {\n let deployPath = normalizeWebPath(filePath);\n \n // Strip the common prefix to create clean deployment paths\n if (commonPrefix) {\n const prefixToRemove = commonPrefix.endsWith('/') ? commonPrefix : `${commonPrefix}/`;\n if (deployPath.startsWith(prefixToRemove)) {\n deployPath = deployPath.substring(prefixToRemove.length);\n }\n }\n \n // Fallback to filename if path becomes empty\n if (!deployPath) {\n deployPath = extractFileName(filePath);\n }\n \n return {\n path: deployPath,\n name: extractFileName(filePath)\n };\n });\n}\n\n/**\n * Finds the common directory shared by all file paths.\n * This is what gets stripped to create clean deployment URLs.\n * \n * @example\n * [\"dist/index.html\", \"dist/assets/app.js\"] → \"dist\"\n * [\"src/components/A.tsx\", \"src/utils/B.ts\"] → \"src\"\n * [\"file1.txt\", \"file2.txt\", \"subdir/file3.txt\"] → \"\" (no common directory)\n */\nfunction findCommonDirectory(filePaths: string[]): string {\n if (!filePaths.length) return '';\n \n // Normalize all paths first\n const normalizedPaths = filePaths.map(path => normalizeWebPath(path));\n \n // Find the common prefix among all file paths (not just directories)\n const pathSegments = normalizedPaths.map(path => path.split('/'));\n const commonSegments: string[] = [];\n const minLength = Math.min(...pathSegments.map(segments => segments.length));\n \n // Check each segment level to find the longest common prefix\n for (let i = 0; i < minLength - 1; i++) { // -1 because we don't want to include the filename\n const segment = pathSegments[0][i];\n if (pathSegments.every(segments => segments[i] === segment)) {\n commonSegments.push(segment);\n } else {\n break;\n }\n }\n \n return commonSegments.join('/');\n}\n\n/**\n * Extracts just the filename from a file path\n */\nfunction extractFileName(path: string): string {\n return path.split(/[/\\\\]/).pop() || path;\n}","/**\n * @file Node.js-specific file utilities for the Ship SDK.\n * Provides helpers for recursively discovering, filtering, and preparing files for deploy in Node.js.\n */\nimport { getENV } from '../../shared/lib/env.js';\nimport type { StaticFile, DeploymentOptions } from '../../shared/types.js';\nimport { calculateMD5 } from '../../shared/lib/md5.js';\nimport { filterJunk } from '../../shared/lib/junk.js';\nimport { ShipError, isShipError } from '@shipstatic/types';\nimport { getCurrentConfig } from '../../shared/core/platform-config.js';\nimport { optimizeDeployPaths } from '../../shared/lib/deploy-paths.js';\nimport { findCommonParent } from '../../shared/lib/path.js';\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n\n/**\n * Recursive function to walk directory and return all file paths.\n * Includes symlink loop protection to prevent infinite recursion.\n * @param dirPath - Directory path to traverse\n * @param visited - Set of already visited real paths (for cycle detection)\n * @returns Array of absolute file paths in the directory\n */\nfunction findAllFilePaths(dirPath: string, visited: Set<string> = new Set()): string[] {\n const results: string[] = [];\n\n // Resolve the real path to detect symlink cycles\n const realPath = fs.realpathSync(dirPath);\n if (visited.has(realPath)) {\n // Already visited this directory (symlink cycle) - skip to prevent infinite loop\n return results;\n }\n visited.add(realPath);\n\n const entries = fs.readdirSync(dirPath);\n\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry);\n const stats = fs.statSync(fullPath);\n\n if (stats.isDirectory()) {\n const subFiles = findAllFilePaths(fullPath, visited);\n results.push(...subFiles);\n } else if (stats.isFile()) {\n results.push(fullPath);\n }\n }\n\n return results;\n}\n\n/**\n * Processes Node.js file and directory paths into an array of StaticFile objects ready for deploy.\n * Uses corrected logic to properly handle common parent directory stripping.\n * \n * @param paths - File or directory paths to scan and process.\n * @param options - Processing options (pathDetect, etc.).\n * @returns Promise resolving to an array of StaticFile objects.\n * @throws {ShipClientError} If called outside Node.js or if fs/path modules fail.\n */\nexport async function processFilesForNode(\n paths: string[],\n options: DeploymentOptions = {}\n): Promise<StaticFile[]> {\n if (getENV() !== 'node') {\n throw ShipError.business('processFilesForNode can only be called in Node.js environment.');\n }\n\n // 1. Discover all unique, absolute file paths from the input list\n const absolutePaths = paths.flatMap(p => {\n const absPath = path.resolve(p);\n try {\n const stats = fs.statSync(absPath);\n return stats.isDirectory() ? findAllFilePaths(absPath) : [absPath];\n } catch (error) {\n throw ShipError.file(`Path does not exist: ${p}`, p);\n }\n });\n const uniquePaths = [...new Set(absolutePaths)];\n \n // 2. Filter out junk files from the final list\n const validPaths = filterJunk(uniquePaths);\n if (validPaths.length === 0) {\n return [];\n }\n\n // 3. Determine the base path for calculating relative paths\n // Find the common parent of the INPUT paths (not the discovered file paths)\n const inputAbsolutePaths = paths.map(p => path.resolve(p));\n const inputBasePath = findCommonParent(inputAbsolutePaths.map(p => {\n try {\n const stats = fs.statSync(p);\n return stats.isDirectory() ? p : path.dirname(p);\n } catch {\n return path.dirname(p);\n }\n }));\n\n // 4. Create raw relative paths for optimization\n const relativePaths = validPaths.map(filePath => {\n // If we have a meaningful common base path from inputs, use it\n if (inputBasePath && inputBasePath.length > 0) {\n const rel = path.relative(inputBasePath, filePath);\n if (rel && typeof rel === 'string' && !rel.startsWith('..')) {\n return rel.replace(/\\\\/g, '/');\n }\n }\n \n // Fallback: if no good common parent or relative path goes up, just use basename\n return path.basename(filePath);\n });\n\n // 5. Optimize paths for deployment (flattening)\n const deployFiles = optimizeDeployPaths(relativePaths, {\n flatten: options.pathDetect !== false\n });\n\n // 6. Process files into StaticFile objects\n const results: StaticFile[] = [];\n let totalSize = 0;\n const platformLimits = getCurrentConfig();\n\n for (let i = 0; i < validPaths.length; i++) {\n const filePath = validPaths[i];\n const deployPath = deployFiles[i].path;\n \n try {\n const stats = fs.statSync(filePath);\n if (stats.size === 0) {\n continue;\n }\n\n // Validate file sizes\n if (stats.size > platformLimits.maxFileSize) {\n throw ShipError.business(`File ${filePath} is too large. Maximum allowed size is ${platformLimits.maxFileSize / (1024 * 1024)}MB.`);\n }\n totalSize += stats.size;\n if (totalSize > platformLimits.maxTotalSize) {\n throw ShipError.business(`Total deploy size is too large. Maximum allowed is ${platformLimits.maxTotalSize / (1024 * 1024)}MB.`);\n }\n\n const content = fs.readFileSync(filePath);\n const { md5 } = await calculateMD5(content);\n \n // Security validation: Ensure no dangerous characters in paths\n if (deployPath.includes('\\0') || deployPath.includes('/../') || deployPath.startsWith('../') || deployPath.endsWith('/..')) {\n throw ShipError.business(`Security error: Unsafe file path \"${deployPath}\" for file: ${filePath}`);\n }\n \n results.push({\n path: deployPath,\n content,\n size: content.length,\n md5,\n });\n } catch (error) {\n // Re-throw ShipError instances directly\n if (isShipError(error)) {\n throw error;\n }\n // Convert file system errors to ShipError with clear message\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw ShipError.file(`Failed to read file \"${filePath}\": ${errorMessage}`, filePath);\n }\n }\n\n // Final validation\n if (results.length > platformLimits.maxFilesCount) {\n throw ShipError.business(`Too many files to deploy. Maximum allowed is ${platformLimits.maxFilesCount} files.`);\n }\n \n return results;\n}","/**\n * @file Main entry point for the Ship CLI.\n */\nimport { Command } from 'commander';\nimport { Ship } from '../index.js';\nimport { ShipError, validateApiKey, validateDeployToken, validateApiUrl, isShipError, type Deployment } from '@shipstatic/types';\nimport { readFileSync, existsSync, statSync } from 'fs';\nimport * as path from 'path';\nimport { success, error } from './utils.js';\nimport { formatOutput } from './formatters.js';\nimport { installCompletion, uninstallCompletion } from './completion.js';\nimport { getUserMessage, toShipError, formatErrorJson, type ErrorContext } from './error-handling.js';\nimport { bold, dim } from 'yoctocolors';\nimport type { GlobalOptions, DeployCommandOptions, TagOptions, TokenCreateCommandOptions, ProcessedOptions, CLIResult } from './types.js';\n\n// Load package.json for version\nfunction loadPackageJson(): { version: string } {\n const paths = [\n path.resolve(__dirname, '../package.json'),\n path.resolve(__dirname, '../../package.json')\n ];\n for (const p of paths) {\n try {\n return JSON.parse(readFileSync(p, 'utf-8'));\n } catch {}\n }\n return { version: '0.0.0' };\n}\n\nconst packageJson = loadPackageJson();\n\n\n\nconst program = new Command();\n\n// Override Commander.js error handling while preserving help/version behavior\nprogram\n .exitOverride((err) => {\n // Only override actual errors, not help/version exits\n if (err.code === 'commander.help' || err.code === 'commander.version' || err.exitCode === 0) {\n process.exit(err.exitCode || 0);\n }\n \n const globalOptions = program.opts();\n\n let message = err.message || 'unknown command error';\n message = message\n .replace(/^error: /, '')\n .replace(/\\n.*/, '')\n .replace(/\\.$/, '')\n .toLowerCase();\n\n error(message, globalOptions.json, globalOptions.noColor);\n\n if (!globalOptions.json) {\n displayHelp(globalOptions.noColor);\n }\n \n process.exit(err.exitCode || 1);\n })\n .configureOutput({\n writeErr: (str) => {\n if (!str.startsWith('error:')) {\n process.stderr.write(str);\n }\n },\n writeOut: (str) => process.stdout.write(str)\n });\n\n\n/**\n * Display comprehensive help information for all commands\n */\nfunction displayHelp(noColor?: boolean) {\n const applyBold = (text: string) => noColor ? text : bold(text);\n const applyDim = (text: string) => noColor ? text : dim(text);\n \n const output = `${applyBold('USAGE')}\n ship <path> 🚀 Deploy static sites with simplicity\n\n${applyBold('COMMANDS')}\n 📦 ${applyBold('Deployments')}\n ship deployments list List all deployments\n ship deployments create <path> Create deployment from directory\n ship deployments get <id> Show deployment information\n ship deployments set <id> Set deployment tags\n ship deployments remove <id> Delete deployment permanently\n\n 🌎 ${applyBold('Domains')}\n ship domains list List all domains\n ship domains set <name> [deployment] Point domain to deployment, or update tags\n ship domains get <name> Show domain information\n ship domains validate <name> Check if domain name is valid and available\n ship domains verify <name> Trigger DNS verification for external domain\n ship domains remove <name> Delete domain permanently\n\n 🔑 ${applyBold('Tokens')}\n ship tokens list List all deploy tokens\n ship tokens create Create a new deploy token\n ship tokens remove <token> Delete token permanently\n\n 🦸 ${applyBold('Account')}\n ship whoami Get current account information\n\n 🛠️ ${applyBold('Completion')}\n ship completion install Install shell completion script\n ship completion uninstall Uninstall shell completion script\n\n${applyBold('FLAGS')}\n --api-key <key> API key for authenticated deployments\n --deploy-token <token> Deploy token for single-use deployments\n --config <file> Custom config file path\n --no-path-detect Disable automatic path optimization and flattening\n --no-spa-detect Disable automatic SPA detection and configuration\n --no-color Disable colored output\n --json Output results in JSON format\n --version Show version information\n\n${applyDim('Please report any issues to https://github.com/shipstatic/ship/issues')}\n`;\n\n console.log(output);\n}\n\n/**\n * Collector function for Commander.js to accumulate repeated option values.\n * Used for --tag flag that can be specified multiple times.\n */\nfunction collect(value: string, previous: string[] = []): string[] {\n return previous.concat([value]);\n}\n\n/**\n * Merge tag options from command and program levels.\n * Commander.js sometimes routes --tag to program level instead of command level.\n */\nfunction mergeTagOption(cmdOptions: TagOptions | undefined, programOpts: TagOptions | undefined): string[] | undefined {\n const tags = cmdOptions?.tag?.length ? cmdOptions.tag : programOpts?.tag;\n return tags?.length ? tags : undefined;\n}\n\n/**\n * Handle unknown subcommand for parent commands.\n * Shows error for unknown subcommand, then displays help.\n */\nfunction handleUnknownSubcommand(validSubcommands: string[]): (...args: unknown[]) => void {\n return (...args: unknown[]) => {\n const globalOptions = processOptions(program);\n\n // Get the command object (last argument) - Commander passes it as the final arg\n const commandObj = args[args.length - 1] as { args?: string[] } | undefined;\n\n // Check if an unknown subcommand was provided\n if (commandObj?.args?.length) {\n const unknownArg = commandObj.args.find((arg) => !validSubcommands.includes(arg));\n if (unknownArg) {\n error(`unknown command '${unknownArg}'`, globalOptions.json, globalOptions.noColor);\n }\n }\n\n displayHelp(globalOptions.noColor);\n process.exit(1);\n };\n}\n\n/**\n * Process CLI options using Commander's built-in option merging.\n * Applies CLI-specific transformations (validation is done in preAction hook).\n */\nfunction processOptions(command: Command): ProcessedOptions {\n // Use Commander's built-in option merging\n // optsWithGlobals() gets both command-level and global options\n const options = command.optsWithGlobals ? command.optsWithGlobals() : command.opts();\n\n // Convert Commander.js --no-color flag (color: false) to our convention (noColor: true)\n if (options.color === false) {\n options.noColor = true;\n }\n\n // Note: Validation is handled by the preAction hook to avoid duplication\n return options as ProcessedOptions;\n}\n\n/**\n * Error handler - outputs errors consistently in text or JSON format.\n * Message formatting is delegated to the error-handling module.\n */\nfunction handleError(\n err: unknown,\n context?: ErrorContext\n) {\n const opts = program.opts() as GlobalOptions;\n const shipError = toShipError(err);\n\n // Get user-facing message using the extracted pure function\n const message = getUserMessage(shipError, context, {\n apiKey: opts.apiKey,\n deployToken: opts.deployToken\n });\n\n // Output in appropriate format\n if (opts.json) {\n console.error(formatErrorJson(message, shipError.details) + '\\n');\n } else {\n error(message, opts.json, opts.noColor);\n // Show help only for unknown command errors (user CLI mistake)\n if (shipError.isValidationError() && message.includes('unknown command')) {\n displayHelp(opts.noColor);\n }\n }\n\n process.exit(1);\n}\n\n/**\n * Wrapper for CLI actions that handles errors and client creation consistently.\n * Reduces boilerplate while preserving context for error handling.\n */\nfunction withErrorHandling<T extends unknown[], R extends CLIResult>(\n handler: (client: Ship, ...args: T) => Promise<R>,\n context?: { operation?: string; resourceType?: string; getResourceId?: (...args: T) => string }\n) {\n return async function(this: Command, ...args: T) {\n // Process options once at the start (used by both success and error paths)\n const globalOptions = processOptions(this);\n\n try {\n const client = createClient();\n const result = await handler(client, ...args);\n\n // Build context for output if provided\n const outputContext = context ? {\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.getResourceId ? context.getResourceId(...args) : undefined\n } : {};\n\n output(result, outputContext, globalOptions);\n } catch (err) {\n const errorContext = context ? {\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.getResourceId ? context.getResourceId(...args) : undefined\n } : undefined;\n\n handleError(err, errorContext);\n }\n };\n}\n\n/**\n * Create Ship client from CLI options\n */\nfunction createClient(): Ship {\n const { config, apiUrl, apiKey, deployToken } = program.opts();\n return new Ship({ configFile: config, apiUrl, apiKey, deployToken });\n}\n\n/** Spinner instance type from yocto-spinner */\ninterface Spinner {\n start(): Spinner;\n stop(): void;\n}\n\n/**\n * Common deploy logic used by both shortcut and explicit commands.\n */\nasync function performDeploy(\n client: Ship,\n deployPath: string,\n cmdOptions: DeployCommandOptions | undefined,\n commandContext?: Command\n): Promise<Deployment> {\n if (!existsSync(deployPath)) {\n throw ShipError.file(`${deployPath} path does not exist`, deployPath);\n }\n\n const stats = statSync(deployPath);\n if (!stats.isDirectory() && !stats.isFile()) {\n throw ShipError.file(`${deployPath} path must be a file or directory`, deployPath);\n }\n\n const deployOptions: {\n via: string;\n tags?: string[];\n pathDetect?: boolean;\n spaDetect?: boolean;\n signal?: AbortSignal;\n } = { via: 'cli' };\n\n // Handle tags\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n if (tags) deployOptions.tags = tags;\n\n // Handle detection flags\n if (cmdOptions?.noPathDetect !== undefined) {\n deployOptions.pathDetect = !cmdOptions.noPathDetect;\n }\n if (cmdOptions?.noSpaDetect !== undefined) {\n deployOptions.spaDetect = !cmdOptions.noSpaDetect;\n }\n\n // Cancellation support\n const abortController = new AbortController();\n deployOptions.signal = abortController.signal;\n\n // Spinner (TTY only, not JSON, not --no-color)\n let spinner: Spinner | null = null;\n const globalOptions = commandContext ? processOptions(commandContext) : {} as ProcessedOptions;\n if (process.stdout.isTTY && !globalOptions.json && !globalOptions.noColor) {\n const { default: yoctoSpinner } = await import('yocto-spinner');\n spinner = yoctoSpinner({ text: 'uploading…' }).start();\n }\n\n const sigintHandler = () => {\n abortController.abort();\n if (spinner) spinner.stop();\n process.exit(130);\n };\n process.on('SIGINT', sigintHandler);\n\n try {\n const result = await client.deployments.create(deployPath, deployOptions);\n process.removeListener('SIGINT', sigintHandler);\n if (spinner) spinner.stop();\n return result;\n } catch (err) {\n process.removeListener('SIGINT', sigintHandler);\n if (spinner) spinner.stop();\n throw err;\n }\n}\n\n/**\n * Output result using formatters module.\n */\nfunction output(result: CLIResult, context: { operation?: string; resourceType?: string; resourceId?: string }, options?: ProcessedOptions) {\n const opts = options || (program.opts() as ProcessedOptions);\n formatOutput(result, context, { isJson: opts.json, noColor: opts.noColor });\n}\n\n\n\nprogram\n .name('ship')\n .description('🚀 Deploy static sites with simplicity')\n .version(packageJson.version, '--version', 'Show version information')\n .option('--api-key <key>', 'API key for authenticated deployments')\n .option('--deploy-token <token>', 'Deploy token for single-use deployments')\n .option('--config <file>', 'Custom config file path')\n .option('--api-url <url>', 'API URL (for development)')\n .option('--json', 'Output results in JSON format')\n .option('--no-color', 'Disable colored output')\n .option('--help', 'Display help for command')\n .helpOption(false); // Disable default help\n\n// Handle --help flag manually to show custom help\nprogram.hook('preAction', (thisCommand, actionCommand) => {\n const options = thisCommand.opts();\n if (options.help) {\n const noColor = options.color === false || options.noColor;\n displayHelp(noColor);\n process.exit(0);\n }\n});\n\n// Validate options early - before any action is executed\nprogram.hook('preAction', (thisCommand, actionCommand) => {\n const options = thisCommand.opts();\n \n try {\n if (options.apiKey && typeof options.apiKey === 'string') {\n validateApiKey(options.apiKey);\n }\n \n if (options.deployToken && typeof options.deployToken === 'string') {\n validateDeployToken(options.deployToken);\n }\n \n if (options.apiUrl && typeof options.apiUrl === 'string') {\n validateApiUrl(options.apiUrl);\n }\n } catch (validationError) {\n if (isShipError(validationError)) {\n const noColor = options.color === false || options.noColor;\n error(validationError.message, options.json, noColor);\n process.exit(1);\n }\n throw validationError;\n }\n});\n\n// Ping command\nprogram\n .command('ping')\n .description('Check API connectivity')\n .action(withErrorHandling((client: Ship) => client.ping()));\n\n// Whoami shortcut - alias for account get\nprogram\n .command('whoami')\n .description('Get current account information')\n .action(withErrorHandling(\n (client: Ship) => client.whoami(),\n { operation: 'get', resourceType: 'Account' }\n ));\n\n// Deployments commands\nconst deploymentsCmd = program\n .command('deployments')\n .description('Manage deployments')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'create', 'get', 'set', 'remove']));\n\ndeploymentsCmd\n .command('list')\n .description('List all deployments')\n .action(withErrorHandling((client: Ship) => client.deployments.list()));\n\ndeploymentsCmd\n .command('create <path>')\n .description('Create deployment from file or directory')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to add (can be repeated)', collect, [])\n .option('--no-path-detect', 'Disable automatic path optimization and flattening')\n .option('--no-spa-detect', 'Disable automatic SPA detection and configuration')\n .action(withErrorHandling(\n function(this: Command, client: Ship, deployPath: string, cmdOptions: DeployCommandOptions) {\n return performDeploy(client, deployPath, cmdOptions, this);\n },\n { operation: 'create' }\n ));\n\ndeploymentsCmd\n .command('get <deployment>')\n .description('Show deployment information')\n .action(withErrorHandling(\n (client: Ship, deployment: string) => client.deployments.get(deployment),\n { operation: 'get', resourceType: 'Deployment', getResourceId: (id: string) => id }\n ));\n\ndeploymentsCmd\n .command('set <deployment>')\n .description('Set deployment tags')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n async (client: Ship, deployment: string, cmdOptions: TagOptions) => {\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions) || [];\n return client.deployments.set(deployment, { tags });\n },\n { operation: 'set', resourceType: 'Deployment', getResourceId: (deployment: string) => deployment }\n ));\n\ndeploymentsCmd\n .command('remove <deployment>')\n .description('Delete deployment permanently')\n .action(withErrorHandling(\n (client: Ship, deployment: string) => client.deployments.remove(deployment),\n { operation: 'remove', resourceType: 'Deployment', getResourceId: (deployment: string) => deployment }\n ));\n\n// Domains commands\nconst domainsCmd = program\n .command('domains')\n .description('Manage domains')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'get', 'set', 'validate', 'verify', 'remove']));\n\ndomainsCmd\n .command('list')\n .description('List all domains')\n .action(withErrorHandling((client: Ship) => client.domains.list()));\n\ndomainsCmd\n .command('get <name>')\n .description('Show domain information')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.get(name),\n { operation: 'get', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('validate <name>')\n .description('Check if domain name is valid and available')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.validate(name),\n { operation: 'validate', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('verify <name>')\n .description('Trigger DNS verification for external domain')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.verify(name),\n { operation: 'verify', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('set <name> [deployment]')\n .description('Point domain to deployment, or update tags')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n async (client: Ship, name: string, deployment: string | undefined, cmdOptions: TagOptions) => {\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n\n // Validate: must provide either deployment or tags\n if (!deployment && (!tags || tags.length === 0)) {\n throw ShipError.validation('Must provide deployment or --tag');\n }\n\n const options: { deployment?: string; tags?: string[] } = {};\n if (deployment) options.deployment = deployment;\n if (tags && tags.length > 0) options.tags = tags;\n\n const result = await client.domains.set(name, options);\n\n // Enrich with DNS info for new external domains (pure formatter will display it)\n if (result.isCreate && name.includes('.')) {\n try {\n const [records, share] = await Promise.all([\n client.domains.records(name),\n client.domains.share(name)\n ]);\n return {\n ...result,\n _dnsRecords: records.records,\n _shareHash: share.hash\n };\n } catch {\n // Graceful degradation - return without DNS info\n }\n }\n return result;\n },\n { operation: 'set', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('remove <name>')\n .description('Delete domain permanently')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.remove(name),\n { operation: 'remove', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\n// Tokens commands\nconst tokensCmd = program\n .command('tokens')\n .description('Manage deploy tokens')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'create', 'remove']));\n\ntokensCmd\n .command('list')\n .description('List all tokens')\n .action(withErrorHandling((client: Ship) => client.tokens.list()));\n\ntokensCmd\n .command('create')\n .description('Create a new deploy token')\n .option('--ttl <seconds>', 'Time to live in seconds (default: never expires)', parseInt)\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n (client: Ship, cmdOptions: TokenCreateCommandOptions) => {\n const options: { ttl?: number; tags?: string[] } = {};\n if (cmdOptions?.ttl !== undefined) options.ttl = cmdOptions.ttl;\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n if (tags && tags.length > 0) options.tags = tags;\n return client.tokens.create(options);\n },\n { operation: 'create', resourceType: 'Token' }\n ));\n\ntokensCmd\n .command('remove <token>')\n .description('Delete token permanently')\n .action(withErrorHandling(\n (client: Ship, token: string) => client.tokens.remove(token),\n { operation: 'remove', resourceType: 'Token', getResourceId: (token: string) => token }\n ));\n\n// Account commands\nconst accountCmd = program\n .command('account')\n .description('Manage account')\n .action(handleUnknownSubcommand(['get']));\n\naccountCmd\n .command('get')\n .description('Show account information')\n .action(withErrorHandling(\n (client: Ship) => client.whoami(),\n { operation: 'get', resourceType: 'Account' }\n ));\n\n// Completion commands\nconst completionCmd = program\n .command('completion')\n .description('Setup shell completion')\n .action(handleUnknownSubcommand(['install', 'uninstall']));\n\ncompletionCmd\n .command('install')\n .description('Install shell completion script')\n .action(() => {\n const options = program.opts();\n const scriptDir = path.resolve(__dirname, 'completions');\n installCompletion(scriptDir, { isJson: options.json, noColor: options.noColor });\n });\n\ncompletionCmd\n .command('uninstall')\n .description('Uninstall shell completion script')\n .action(() => {\n const options = program.opts();\n uninstallCompletion({ isJson: options.json, noColor: options.noColor });\n });\n\n\n// Deploy shortcut as default action\nprogram\n .argument('[path]', 'Path to deploy')\n .option('--tag <tag>', 'Tag to add (can be repeated)', collect, [])\n .option('--no-path-detect', 'Disable automatic path optimization and flattening')\n .option('--no-spa-detect', 'Disable automatic SPA detection and configuration')\n .action(withErrorHandling(\n async function(this: Command, client: Ship, deployPath?: string, cmdOptions?: DeployCommandOptions) {\n if (!deployPath) {\n const globalOptions = program.opts() as GlobalOptions;\n // Convert Commander.js --no-color flag (color: false) to our convention (noColor: true)\n const noColor = globalOptions.color === false || globalOptions.noColor;\n displayHelp(noColor);\n process.exit(0);\n }\n\n // Check if the argument is a valid path by checking filesystem\n // This correctly handles paths like \"dist\", \"build\", \"public\" without slashes\n if (!existsSync(deployPath)) {\n // Path doesn't exist - could be unknown command or typo\n // Check if it looks like a command (no path separators, no extension)\n const looksLikeCommand = !deployPath.includes('/') && !deployPath.includes('\\\\') &&\n !deployPath.includes('.') && !deployPath.startsWith('~');\n if (looksLikeCommand) {\n throw ShipError.validation(`unknown command '${deployPath}'`);\n }\n // Otherwise let performDeploy handle the \"path does not exist\" error\n }\n\n return performDeploy(client, deployPath, cmdOptions, this);\n },\n { operation: 'create' }\n ));\n\n\n\n/**\n * Simple completion handler - no self-invocation, just static completions\n */\nfunction handleCompletion() {\n const args = process.argv;\n const isBash = args.includes('--compbash');\n const isZsh = args.includes('--compzsh');\n const isFish = args.includes('--compfish');\n\n if (!isBash && !isZsh && !isFish) return;\n\n const completions = ['ping', 'whoami', 'deployments', 'domains', 'account', 'completion'];\n console.log(completions.join(isFish ? '\\n' : ' '));\n process.exit(0);\n}\n\n// Handle completion requests (before any other processing)\nif (process.env.NODE_ENV !== 'test' && (process.argv.includes('--compbash') || process.argv.includes('--compzsh') || process.argv.includes('--compfish'))) {\n handleCompletion();\n}\n\n// Handle main CLI parsing\nif (process.env.NODE_ENV !== 'test') {\n try {\n program.parse(process.argv);\n } catch (err) {\n // Commander.js errors are already handled by exitOverride above\n // This catch is for safety - check if it's a Commander error\n if (err instanceof Error && 'code' in err) {\n const code = (err as Error & { code?: string }).code;\n const exitCode = (err as Error & { exitCode?: number }).exitCode;\n if (code?.startsWith('commander.')) {\n process.exit(exitCode || 1);\n }\n }\n throw err;\n }\n}","/**\n * @file HTTP client for Ship API.\n */\nimport type {\n Deployment,\n DeploymentListResponse,\n PingResponse,\n ConfigResponse,\n DeploymentRemoveResponse,\n Domain,\n DomainListResponse,\n DomainDnsResponse,\n DomainRecordsResponse,\n DomainValidateResponse,\n Account,\n SPACheckRequest,\n SPACheckResponse,\n StaticFile,\n TokenCreateResponse,\n TokenListResponse\n} from '@shipstatic/types';\nimport type { ApiDeployOptions, ShipClientOptions, ShipEvents, DeployBodyCreator } from '../types.js';\nimport { ShipError, isShipError, DEFAULT_API } from '@shipstatic/types';\nimport { SimpleEvents } from '../events.js';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst ENDPOINTS = {\n DEPLOYMENTS: '/deployments',\n DOMAINS: '/domains',\n TOKENS: '/tokens',\n ACCOUNT: '/account',\n CONFIG: '/config',\n PING: '/ping',\n SPA_CHECK: '/spa-check'\n} as const;\n\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface ApiHttpOptions extends ShipClientOptions {\n getAuthHeaders: () => Record<string, string>;\n createDeployBody: DeployBodyCreator;\n}\n\ninterface RequestResult<T> {\n data: T;\n status: number;\n}\n\n/** Shape of error response from API */\ninterface ApiErrorData {\n message?: string;\n error?: string;\n}\n\n// =============================================================================\n// HTTP CLIENT\n// =============================================================================\n\nexport class ApiHttp extends SimpleEvents {\n private readonly apiUrl: string;\n private readonly getAuthHeadersCallback: () => Record<string, string>;\n private readonly timeout: number;\n private readonly createDeployBody: DeployBodyCreator;\n\n constructor(options: ApiHttpOptions) {\n super();\n this.apiUrl = options.apiUrl || DEFAULT_API;\n this.getAuthHeadersCallback = options.getAuthHeaders;\n this.timeout = options.timeout ?? DEFAULT_REQUEST_TIMEOUT;\n this.createDeployBody = options.createDeployBody;\n }\n\n /**\n * Transfer events to another client\n */\n transferEventsTo(target: ApiHttp): void {\n this.transfer(target);\n }\n\n // ===========================================================================\n // CORE REQUEST INFRASTRUCTURE\n // ===========================================================================\n\n /**\n * Execute HTTP request with timeout, events, and error handling\n */\n private async executeRequest<T>(\n url: string,\n options: RequestInit,\n operationName: string\n ): Promise<RequestResult<T>> {\n const headers = this.mergeHeaders(options.headers as Record<string, string>);\n const { signal, cleanup } = this.createTimeoutSignal(options.signal);\n\n const fetchOptions: RequestInit = {\n ...options,\n headers,\n credentials: !headers.Authorization ? 'include' : undefined,\n signal,\n };\n\n this.emit('request', url, fetchOptions);\n\n try {\n const response = await fetch(url, fetchOptions);\n cleanup();\n\n if (!response.ok) {\n await this.handleResponseError(response, operationName);\n }\n\n this.emit('response', this.safeClone(response), url);\n const data = await this.parseResponse<T>(this.safeClone(response));\n return { data, status: response.status };\n } catch (error) {\n cleanup();\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err, url);\n this.handleFetchError(error, operationName);\n }\n }\n\n /**\n * Simple request - returns data only\n */\n private async request<T>(url: string, options: RequestInit, operationName: string): Promise<T> {\n const { data } = await this.executeRequest<T>(url, options, operationName);\n return data;\n }\n\n /**\n * Request with status - returns data and HTTP status code\n */\n private async requestWithStatus<T>(url: string, options: RequestInit, operationName: string): Promise<RequestResult<T>> {\n return this.executeRequest<T>(url, options, operationName);\n }\n\n // ===========================================================================\n // REQUEST HELPERS\n // ===========================================================================\n\n private mergeHeaders(customHeaders: Record<string, string> = {}): Record<string, string> {\n return { ...customHeaders, ...this.getAuthHeadersCallback() };\n }\n\n private createTimeoutSignal(existingSignal?: AbortSignal | null): { signal: AbortSignal; cleanup: () => void } {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n if (existingSignal) {\n const abort = () => controller.abort();\n existingSignal.addEventListener('abort', abort);\n if (existingSignal.aborted) controller.abort();\n }\n\n return {\n signal: controller.signal,\n cleanup: () => clearTimeout(timeoutId)\n };\n }\n\n private safeClone(response: Response): Response {\n try {\n return response.clone();\n } catch {\n return response;\n }\n }\n\n private async parseResponse<T>(response: Response): Promise<T> {\n if (response.headers.get('Content-Length') === '0' || response.status === 204) {\n return undefined as T;\n }\n return response.json() as Promise<T>;\n }\n\n // ===========================================================================\n // ERROR HANDLING\n // ===========================================================================\n\n private async handleResponseError(response: Response, operationName: string): Promise<never> {\n let errorData: ApiErrorData = {};\n try {\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n const json: unknown = await response.json();\n // Safely extract known fields from response\n if (json && typeof json === 'object') {\n const obj = json as Record<string, unknown>;\n if (typeof obj.message === 'string') errorData.message = obj.message;\n if (typeof obj.error === 'string') errorData.error = obj.error;\n }\n } else {\n errorData = { message: await response.text() };\n }\n } catch {\n errorData = { message: 'Failed to parse error response' };\n }\n\n const message = errorData.message || errorData.error || `${operationName} failed`;\n\n if (response.status === 401) {\n throw ShipError.authentication(message);\n }\n throw ShipError.api(message, response.status);\n }\n\n private handleFetchError(error: unknown, operationName: string): never {\n // Re-throw ShipErrors as-is\n if (isShipError(error)) {\n throw error;\n }\n // Handle abort errors\n if (error instanceof Error && error.name === 'AbortError') {\n throw ShipError.cancelled(`${operationName} was cancelled`);\n }\n // Handle network errors (fetch failures)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n throw ShipError.network(`${operationName} failed: ${error.message}`, error);\n }\n // Handle other Error instances\n if (error instanceof Error) {\n throw ShipError.business(`${operationName} failed: ${error.message}`);\n }\n // Handle non-Error throws\n throw ShipError.business(`${operationName} failed: Unknown error`);\n }\n\n // ===========================================================================\n // PUBLIC API - DEPLOYMENTS\n // ===========================================================================\n\n async deploy(files: StaticFile[], options: ApiDeployOptions = {}): Promise<Deployment> {\n if (!files.length) {\n throw ShipError.business('No files to deploy');\n }\n for (const file of files) {\n if (!file.md5) {\n throw ShipError.file(`MD5 checksum missing for file: ${file.path}`, file.path);\n }\n }\n\n const { body, headers: bodyHeaders } = await this.createDeployBody(files, options.tags, options.via);\n\n const authHeaders: Record<string, string> = {};\n if (options.deployToken) {\n authHeaders['Authorization'] = `Bearer ${options.deployToken}`;\n } else if (options.apiKey) {\n authHeaders['Authorization'] = `Bearer ${options.apiKey}`;\n }\n if (options.caller) {\n authHeaders['X-Caller'] = options.caller;\n }\n\n return this.request<Deployment>(\n `${options.apiUrl || this.apiUrl}${ENDPOINTS.DEPLOYMENTS}`,\n { method: 'POST', body, headers: { ...bodyHeaders, ...authHeaders }, signal: options.signal || null },\n 'Deploy'\n );\n }\n\n async listDeployments(): Promise<DeploymentListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}`, { method: 'GET' }, 'List deployments');\n }\n\n async getDeployment(id: string): Promise<Deployment> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`, { method: 'GET' }, 'Get deployment');\n }\n\n async updateDeploymentTags(id: string, tags: string[]): Promise<Deployment> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`,\n { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tags }) },\n 'Update deployment tags'\n );\n }\n\n async removeDeployment(id: string): Promise<void> {\n await this.request<DeploymentRemoveResponse>(\n `${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`,\n { method: 'DELETE' },\n 'Remove deployment'\n );\n }\n\n // ===========================================================================\n // PUBLIC API - DOMAINS\n // ===========================================================================\n // All domain methods accept FQDN (Fully Qualified Domain Name) as the `name` parameter.\n // The SDK does not validate or normalize - the API handles all domain semantics.\n\n async setDomain(name: string, deployment?: string, tags?: string[]): Promise<Domain> {\n const body: { deployment?: string; tags?: string[] } = {};\n if (deployment) body.deployment = deployment;\n if (tags !== undefined) body.tags = tags;\n\n const { data, status } = await this.requestWithStatus<Domain>(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`,\n { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'Set domain'\n );\n\n return { ...data, isCreate: status === 201 };\n }\n\n async listDomains(): Promise<DomainListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}`, { method: 'GET' }, 'List domains');\n }\n\n async getDomain(name: string): Promise<Domain> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`, { method: 'GET' }, 'Get domain');\n }\n\n async updateDomainTags(name: string, tags: string[]): Promise<Domain> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`,\n { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tags }) },\n 'Update domain tags'\n );\n }\n\n async removeDomain(name: string): Promise<void> {\n await this.request<void>(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`, { method: 'DELETE' }, 'Remove domain');\n }\n\n async verifyDomain(name: string): Promise<{ message: string }> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/verify`, { method: 'POST' }, 'Verify domain');\n }\n\n async getDomainDns(name: string): Promise<DomainDnsResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/dns`, { method: 'GET' }, 'Get domain DNS');\n }\n\n async getDomainRecords(name: string): Promise<DomainRecordsResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/records`, { method: 'GET' }, 'Get domain records');\n }\n\n async getDomainShare(name: string): Promise<{ domain: string; hash: string }> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/share`, { method: 'GET' }, 'Get domain share');\n }\n\n async validateDomain(name: string): Promise<DomainValidateResponse> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/validate`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain: name }) },\n 'Validate domain'\n );\n }\n\n // ===========================================================================\n // PUBLIC API - TOKENS\n // ===========================================================================\n\n async createToken(ttl?: number, tags?: string[]): Promise<TokenCreateResponse> {\n const body: { ttl?: number; tags?: string[] } = {};\n if (ttl !== undefined) body.ttl = ttl;\n if (tags !== undefined) body.tags = tags;\n\n return this.request(\n `${this.apiUrl}${ENDPOINTS.TOKENS}`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'Create token'\n );\n }\n\n async listTokens(): Promise<TokenListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.TOKENS}`, { method: 'GET' }, 'List tokens');\n }\n\n async removeToken(token: string): Promise<void> {\n await this.request<void>(`${this.apiUrl}${ENDPOINTS.TOKENS}/${encodeURIComponent(token)}`, { method: 'DELETE' }, 'Remove token');\n }\n\n // ===========================================================================\n // PUBLIC API - ACCOUNT & CONFIG\n // ===========================================================================\n\n async getAccount(): Promise<Account> {\n return this.request(`${this.apiUrl}${ENDPOINTS.ACCOUNT}`, { method: 'GET' }, 'Get account');\n }\n\n async getConfig(): Promise<ConfigResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.CONFIG}`, { method: 'GET' }, 'Get config');\n }\n\n async ping(): Promise<boolean> {\n const data = await this.request<PingResponse>(`${this.apiUrl}${ENDPOINTS.PING}`, { method: 'GET' }, 'Ping');\n return data?.success || false;\n }\n\n async getPingResponse(): Promise<PingResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.PING}`, { method: 'GET' }, 'Ping');\n }\n\n // ===========================================================================\n // PUBLIC API - SPA CHECK\n // ===========================================================================\n\n async checkSPA(files: StaticFile[]): Promise<boolean> {\n const indexFile = files.find(f => f.path === 'index.html' || f.path === '/index.html');\n if (!indexFile || indexFile.size > 100 * 1024) {\n return false;\n }\n\n let indexContent: string;\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(indexFile.content)) {\n indexContent = indexFile.content.toString('utf-8');\n } else if (typeof Blob !== 'undefined' && indexFile.content instanceof Blob) {\n indexContent = await indexFile.content.text();\n } else if (typeof File !== 'undefined' && indexFile.content instanceof File) {\n indexContent = await indexFile.content.text();\n } else {\n return false;\n }\n\n const body: SPACheckRequest = { files: files.map(f => f.path), index: indexContent };\n const response = await this.request<SPACheckResponse>(\n `${this.apiUrl}${ENDPOINTS.SPA_CHECK}`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'SPA check'\n );\n\n return response.isSPA;\n }\n}\n","/**\n * Event system for Ship SDK\n * Lightweight, reliable event handling with proper error boundaries\n */\n\nimport type { ShipEvents } from './types.js';\n\n/**\n * Lightweight event system\n * - Add handler: on() \n * - Remove handler: off()\n * - Emit events: emit() [internal]\n * - Transfer events: transfer() [internal]\n * - Reliable error handling and cleanup\n */\nexport class SimpleEvents {\n private handlers = new Map<string, Set<Function>>();\n\n /**\n * Add event handler\n */\n on<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n if (!this.handlers.has(event as string)) {\n this.handlers.set(event as string, new Set());\n }\n this.handlers.get(event as string)!.add(handler);\n }\n\n /**\n * Remove event handler \n */\n off<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n const eventHandlers = this.handlers.get(event as string);\n if (eventHandlers) {\n eventHandlers.delete(handler);\n if (eventHandlers.size === 0) {\n this.handlers.delete(event as string);\n }\n }\n }\n\n /**\n * Emit event (internal use only)\n * @internal\n */\n emit<K extends keyof ShipEvents>(event: K, ...args: ShipEvents[K]): void {\n const eventHandlers = this.handlers.get(event as string);\n if (!eventHandlers) return;\n\n // Create array to prevent modification during iteration\n const handlerArray = Array.from(eventHandlers);\n \n for (const handler of handlerArray) {\n try {\n handler(...args);\n } catch (error) {\n // Remove failing handlers to prevent repeated failures\n eventHandlers.delete(handler);\n \n // Re-emit as error event (only if not already error to prevent loops)\n if (event !== 'error') {\n // Use setTimeout to break out of current call stack and prevent infinite recursion\n setTimeout(() => {\n if (error instanceof Error) {\n this.emit('error', error, String(event));\n } else {\n this.emit('error', new Error(String(error)), String(event));\n }\n }, 0);\n }\n }\n }\n }\n\n /**\n * Transfer all handlers to another events instance\n * @internal\n */\n transfer(target: SimpleEvents): void {\n this.handlers.forEach((handlers, event) => {\n handlers.forEach(handler => {\n // any[] required: handler type info is erased when stored in Map<string, Set<Function>>\n target.on(event as keyof ShipEvents, handler as (...args: any[]) => void);\n });\n });\n }\n\n /**\n * Clear all handlers (for cleanup)\n * @internal \n */\n clear(): void {\n this.handlers.clear();\n }\n}","/**\n * @file Base Ship SDK class - provides shared functionality across environments.\n */\n\nimport { ApiHttp } from './api/http.js';\nimport { ShipError } from '@shipstatic/types';\nimport type { ShipClientOptions, ShipEvents } from './types.js';\nimport type { Deployment, ConfigResponse } from '@shipstatic/types';\nimport { getCurrentConfig } from './core/platform-config.js';\nimport type { ResolvedConfig } from './core/config.js';\n\n// Resource imports\nimport {\n createDeploymentResource,\n createDomainResource,\n createAccountResource,\n createTokenResource,\n type DeployInput\n} from './resources.js';\nimport type {\n DeploymentResource,\n DomainResource,\n AccountResource,\n TokenResource\n} from '@shipstatic/types';\n\nimport type { StaticFile } from '@shipstatic/types';\nimport type { DeploymentOptions, DeployBodyCreator } from './types.js';\n\n/**\n * Authentication state for the Ship instance\n * Discriminated union ensures only one auth method is active at a time\n */\ntype AuthState =\n | { type: 'token'; value: string }\n | { type: 'apiKey'; value: string }\n | null;\n\n/**\n * Abstract base class for Ship SDK implementations.\n *\n * Provides shared functionality while allowing environment-specific\n * implementations to handle configuration loading and deployment processing.\n */\nexport abstract class Ship {\n protected http: ApiHttp;\n protected readonly clientOptions: ShipClientOptions;\n protected initPromise: Promise<void> | null = null;\n protected _config: ConfigResponse | null = null;\n\n // Authentication state management\n private auth: AuthState = null;\n\n // Store the auth headers callback to reuse when replacing HTTP client\n protected readonly authHeadersCallback: () => Record<string, string>;\n\n // Resource instances (initialized during creation)\n protected _deployments: DeploymentResource;\n protected _domains: DomainResource;\n protected _account: AccountResource;\n protected _tokens: TokenResource;\n\n constructor(options: ShipClientOptions = {}) {\n this.clientOptions = options;\n\n // Initialize auth state from constructor options\n // Prioritize deployToken over apiKey if both are provided\n if (options.deployToken) {\n this.auth = { type: 'token', value: options.deployToken };\n } else if (options.apiKey) {\n this.auth = { type: 'apiKey', value: options.apiKey };\n }\n\n // Create the auth headers callback once and reuse it\n this.authHeadersCallback = () => this.getAuthHeaders();\n\n // Initialize HTTP client with constructor options for immediate use\n const config = this.resolveInitialConfig(options);\n this.http = new ApiHttp({\n ...options,\n ...config,\n getAuthHeaders: this.authHeadersCallback,\n createDeployBody: this.getDeployBodyCreator()\n });\n\n const ctx = {\n getApi: () => this.http,\n ensureInit: () => this.ensureInitialized()\n };\n\n this._deployments = createDeploymentResource({\n ...ctx,\n processInput: (input, options) => this.processInput(input, options),\n clientDefaults: this.clientOptions,\n hasAuth: () => this.hasAuth()\n });\n this._domains = createDomainResource(ctx);\n this._account = createAccountResource(ctx);\n this._tokens = createTokenResource(ctx);\n }\n\n // Abstract methods that environments must implement\n protected abstract resolveInitialConfig(options: ShipClientOptions): ResolvedConfig;\n protected abstract loadFullConfig(): Promise<void>;\n protected abstract processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;\n protected abstract getDeployBodyCreator(): DeployBodyCreator;\n\n /**\n * Ensure full initialization is complete - called lazily by resources\n */\n protected async ensureInitialized(): Promise<void> {\n if (!this.initPromise) {\n this.initPromise = this.loadFullConfig();\n }\n return this.initPromise;\n }\n\n /**\n * Ping the API server to check connectivity\n */\n async ping(): Promise<boolean> {\n await this.ensureInitialized();\n return this.http.ping();\n }\n\n /**\n * Deploy project (convenience shortcut to ship.deployments.create())\n */\n async deploy(input: DeployInput, options?: DeploymentOptions): Promise<Deployment> {\n return this.deployments.create(input, options);\n }\n\n /**\n * Get current account information (convenience shortcut to ship.account.get())\n */\n async whoami() {\n return this.account.get();\n }\n\n /**\n * Get deployments resource (environment-specific)\n */\n get deployments(): DeploymentResource {\n return this._deployments;\n }\n\n /**\n * Get domains resource\n */\n get domains(): DomainResource {\n return this._domains;\n }\n\n /**\n * Get account resource\n */\n get account(): AccountResource {\n return this._account;\n }\n\n /**\n * Get tokens resource\n */\n get tokens(): TokenResource {\n return this._tokens;\n }\n\n /**\n * Get API configuration (file upload limits, etc.)\n * Reuses platform config fetched during initialization, then caches the result\n */\n async getConfig(): Promise<ConfigResponse> {\n if (this._config) {\n return this._config;\n }\n\n await this.ensureInitialized();\n // After initialization, platform config is already fetched - reuse it instead of making another API call\n this._config = getCurrentConfig();\n return this._config;\n }\n\n /**\n * Add event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n on<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n this.http.on(event, handler);\n }\n\n /**\n * Remove event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n off<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n this.http.off(event, handler);\n }\n\n /**\n * Replace HTTP client while preserving event listeners\n * Used during initialization to maintain user event subscriptions\n * @protected\n */\n protected replaceHttpClient(newClient: ApiHttp): void {\n if (this.http?.transferEventsTo) {\n try {\n this.http.transferEventsTo(newClient);\n } catch (error) {\n // Event transfer failed - log but continue (better than crashing initialization)\n console.warn('Event transfer failed during client replacement:', error);\n }\n }\n this.http = newClient;\n }\n\n /**\n * Sets the deploy token for authentication.\n * This will override any previously set API key or deploy token.\n * @param token The deploy token (format: token-<64-char-hex>)\n */\n public setDeployToken(token: string): void {\n if (!token || typeof token !== 'string') {\n throw ShipError.business('Invalid deploy token provided. Deploy token must be a non-empty string.');\n }\n this.auth = { type: 'token', value: token };\n }\n\n /**\n * Sets the API key for authentication.\n * This will override any previously set API key or deploy token.\n * @param key The API key (format: ship-<64-char-hex>)\n */\n public setApiKey(key: string): void {\n if (!key || typeof key !== 'string') {\n throw ShipError.business('Invalid API key provided. API key must be a non-empty string.');\n }\n this.auth = { type: 'apiKey', value: key };\n }\n\n /**\n * Generate authorization headers based on current auth state\n * Called dynamically on each request to ensure latest credentials are used\n * @private\n */\n private getAuthHeaders(): Record<string, string> {\n if (!this.auth) {\n return {};\n }\n return { 'Authorization': `Bearer ${this.auth.value}` };\n }\n\n /**\n * Check if authentication credentials are configured\n * Used by resources to fail fast if auth is required\n * @private\n */\n private hasAuth(): boolean {\n // useCredentials means cookies are used for auth - no explicit token needed\n if (this.clientOptions.useCredentials) {\n return true;\n }\n return this.auth !== null;\n }\n\n}","/**\n * Ship SDK resource factory functions.\n */\nimport {\n ShipError,\n type StaticFile,\n type DeployInput,\n type DeploymentResource,\n type DomainResource,\n type AccountResource,\n type TokenResource\n} from '@shipstatic/types';\n\nexport type {\n StaticFile,\n DeployInput,\n DeploymentResource,\n DomainResource,\n AccountResource,\n TokenResource\n};\nimport type { ApiHttp } from './api/http.js';\nimport type { ShipClientOptions, DeploymentOptions } from './types.js';\nimport { mergeDeployOptions } from './core/config.js';\nimport { detectAndConfigureSPA } from './lib/spa.js';\n\n/**\n * Shared context for all resource factories.\n */\nexport interface ResourceContext {\n getApi: () => ApiHttp;\n ensureInit: () => Promise<void>;\n}\n\n/**\n * Extended context for deployment resource.\n */\nexport interface DeploymentResourceContext extends ResourceContext {\n processInput: (input: DeployInput, options: DeploymentOptions) => Promise<StaticFile[]>;\n clientDefaults?: ShipClientOptions;\n hasAuth?: () => boolean;\n}\n\n/**\n * Create deployment resource with all CRUD operations.\n */\nexport function createDeploymentResource(ctx: DeploymentResourceContext): DeploymentResource {\n const { getApi, ensureInit, processInput, clientDefaults, hasAuth } = ctx;\n\n return {\n create: async (input: DeployInput, options: DeploymentOptions = {}) => {\n await ensureInit();\n\n const mergedOptions = clientDefaults\n ? mergeDeployOptions(options, clientDefaults)\n : options;\n\n if (hasAuth && !hasAuth() && !mergedOptions.deployToken && !mergedOptions.apiKey) {\n throw ShipError.authentication(\n 'Authentication credentials are required for deployment. ' +\n 'Please call setDeployToken() or setApiKey() first, or pass credentials in the deployment options.'\n );\n }\n\n if (!processInput) {\n throw ShipError.config('processInput function is not provided.');\n }\n\n const apiClient = getApi();\n let staticFiles = await processInput(input, mergedOptions);\n staticFiles = await detectAndConfigureSPA(staticFiles, apiClient, mergedOptions);\n\n return apiClient.deploy(staticFiles, mergedOptions);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listDeployments();\n },\n\n get: async (id: string) => {\n await ensureInit();\n return getApi().getDeployment(id);\n },\n\n set: async (id: string, options: { tags: string[] }) => {\n await ensureInit();\n return getApi().updateDeploymentTags(id, options.tags);\n },\n\n remove: async (id: string) => {\n await ensureInit();\n await getApi().removeDeployment(id);\n }\n };\n}\n\n/**\n * Create domain resource with all CRUD operations.\n *\n * @remarks\n * The `name` parameter in all methods is an FQDN (Fully Qualified Domain Name).\n * The SDK does not validate or normalize domain names - the API handles all domain semantics.\n */\nexport function createDomainResource(ctx: ResourceContext): DomainResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n set: async (name: string, options: { deployment?: string; tags?: string[] } = {}) => {\n await ensureInit();\n const { deployment, tags } = options;\n\n // Smart routing: tags-only → PATCH; otherwise → PUT (create/link/reserve)\n if (deployment === undefined && tags && tags.length > 0) {\n return getApi().updateDomainTags(name, tags);\n }\n return getApi().setDomain(name, deployment, tags);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listDomains();\n },\n\n get: async (name: string) => {\n await ensureInit();\n return getApi().getDomain(name);\n },\n\n remove: async (name: string) => {\n await ensureInit();\n await getApi().removeDomain(name);\n },\n\n verify: async (name: string) => {\n await ensureInit();\n return getApi().verifyDomain(name);\n },\n\n validate: async (name: string) => {\n await ensureInit();\n return getApi().validateDomain(name);\n },\n\n dns: async (name: string) => {\n await ensureInit();\n return getApi().getDomainDns(name);\n },\n\n records: async (name: string) => {\n await ensureInit();\n return getApi().getDomainRecords(name);\n },\n\n share: async (name: string) => {\n await ensureInit();\n return getApi().getDomainShare(name);\n }\n };\n}\n\n/**\n * Create account resource (whoami functionality).\n */\nexport function createAccountResource(ctx: ResourceContext): AccountResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n get: async () => {\n await ensureInit();\n return getApi().getAccount();\n }\n };\n}\n\n/**\n * Create token resource for managing deploy tokens.\n */\nexport function createTokenResource(ctx: ResourceContext): TokenResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n create: async (options: { ttl?: number; tags?: string[] } = {}) => {\n await ensureInit();\n return getApi().createToken(options.ttl, options.tags);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listTokens();\n },\n\n remove: async (token: string) => {\n await ensureInit();\n await getApi().removeToken(token);\n }\n };\n}\n","/**\n * @file Shared configuration logic for both environments.\n *\n * CONFIGURATION PRECEDENCE (highest to lowest):\n * 1. Constructor options / CLI flags (passed directly to Ship())\n * 2. Environment variables (SHIP_API_KEY, SHIP_DEPLOY_TOKEN, SHIP_API_URL)\n * 3. Config file (.shiprc or package.json \"ship\" key)\n * 4. Default values (DEFAULT_API)\n *\n * This means CLI flags always win, followed by env vars, then config files.\n */\n\nimport { DEFAULT_API, type PlatformConfig, type ResolvedConfig } from '@shipstatic/types';\nimport type { ShipClientOptions, DeploymentOptions } from '../types.js';\nimport { getENV } from '../lib/env.js';\n\nexport type { ResolvedConfig } from '@shipstatic/types';\n\n/**\n * Cross-environment config loader that dispatches to appropriate implementation.\n */\nexport async function loadConfig(configFile?: string): Promise<PlatformConfig> {\n const env = getENV();\n\n if (env === 'browser') {\n // In browser, return empty config (no file system access)\n return {};\n } else if (env === 'node') {\n // In Node.js, load from environment and files\n const { loadConfig: nodeLoadConfig } = await import('../../node/core/config.js');\n return nodeLoadConfig(configFile);\n } else {\n // Fallback to empty config for unknown environments\n return {};\n }\n}\n\n/**\n * Universal configuration resolver for all environments.\n * This is the single source of truth for config resolution.\n */\nexport function resolveConfig(\n userOptions: ShipClientOptions = {},\n loadedConfig: Partial<ShipClientOptions> = {}\n): ResolvedConfig {\n const finalConfig = {\n apiUrl: userOptions.apiUrl || loadedConfig.apiUrl || DEFAULT_API,\n apiKey: userOptions.apiKey !== undefined ? userOptions.apiKey : loadedConfig.apiKey,\n deployToken: userOptions.deployToken !== undefined ? userOptions.deployToken : loadedConfig.deployToken,\n };\n\n const result: ResolvedConfig = {\n apiUrl: finalConfig.apiUrl\n };\n\n if (finalConfig.apiKey !== undefined) result.apiKey = finalConfig.apiKey;\n if (finalConfig.deployToken !== undefined) result.deployToken = finalConfig.deployToken;\n\n return result;\n}\n\n/**\n * Merge deployment options with client defaults.\n * This is shared logic used by both environments.\n */\nexport function mergeDeployOptions(\n options: DeploymentOptions,\n clientDefaults: ShipClientOptions\n): DeploymentOptions {\n const result: DeploymentOptions = { ...options };\n\n // Only add defined values from client defaults\n if (result.apiUrl === undefined && clientDefaults.apiUrl !== undefined) {\n result.apiUrl = clientDefaults.apiUrl;\n }\n if (result.apiKey === undefined && clientDefaults.apiKey !== undefined) {\n result.apiKey = clientDefaults.apiKey;\n }\n if (result.deployToken === undefined && clientDefaults.deployToken !== undefined) {\n result.deployToken = clientDefaults.deployToken;\n }\n if (result.timeout === undefined && clientDefaults.timeout !== undefined) {\n result.timeout = clientDefaults.timeout;\n }\n if (result.maxConcurrency === undefined && clientDefaults.maxConcurrency !== undefined) {\n result.maxConcurrency = clientDefaults.maxConcurrency;\n }\n if (result.onProgress === undefined && clientDefaults.onProgress !== undefined) {\n result.onProgress = clientDefaults.onProgress;\n }\n if (result.caller === undefined && clientDefaults.caller !== undefined) {\n result.caller = clientDefaults.caller;\n }\n\n return result;\n}\n","/**\n * @file SPA detection and auto-configuration utilities.\n *\n * Provides SPA detection and ship.json generation functionality\n * that can be used by both Node.js and browser environments.\n */\n\nimport { DEPLOYMENT_CONFIG_FILENAME } from '@shipstatic/types';\nimport { calculateMD5 } from './md5.js';\nimport type { StaticFile, DeploymentOptions } from '../types.js';\nimport type { ApiHttp } from '../api/http.js';\n\n/**\n * Creates ship.json configuration for SPA projects.\n * @returns Promise resolving to StaticFile with SPA configuration\n */\nexport async function createSPAConfig(): Promise<StaticFile> {\n const config = {\n \"rewrites\": [{\n \"source\": \"/(.*)\",\n \"destination\": \"/index.html\"\n }]\n };\n\n const configString = JSON.stringify(config, null, 2);\n\n // Create content that works in both browser and Node.js environments\n let content: Buffer | Blob;\n if (typeof Buffer !== 'undefined') {\n // Node.js environment\n content = Buffer.from(configString, 'utf-8');\n } else {\n // Browser environment\n content = new Blob([configString], { type: 'application/json' });\n }\n\n const { md5 } = await calculateMD5(content);\n\n return {\n path: DEPLOYMENT_CONFIG_FILENAME,\n content,\n size: configString.length,\n md5\n };\n}\n\n/**\n * Detects SPA projects and auto-generates configuration.\n * This function can be used by both Node.js and browser environments.\n *\n * @param files - Array of StaticFiles to analyze\n * @param apiClient - HTTP client for API communication\n * @param options - Deployment options containing SPA detection settings\n * @returns Promise resolving to files array with optional SPA config added\n */\nexport async function detectAndConfigureSPA(\n files: StaticFile[],\n apiClient: ApiHttp,\n options: DeploymentOptions\n): Promise<StaticFile[]> {\n // Skip if disabled or config already exists\n if (options.spaDetect === false || files.some(f => f.path === DEPLOYMENT_CONFIG_FILENAME)) {\n return files;\n }\n\n try {\n const isSPA = await apiClient.checkSPA(files);\n\n if (isSPA) {\n const spaConfig = await createSPAConfig();\n return [...files, spaConfig];\n }\n } catch (error) {\n // SPA detection failed, continue silently without auto-config\n }\n\n return files;\n}\n","/**\n * @file Ship SDK for Node.js environments with full file system support.\n */\n\nimport { Ship as BaseShip } from '../shared/base-ship.js';\nimport { ShipError } from '@shipstatic/types';\nimport { getENV } from '../shared/lib/env.js';\nimport { loadConfig } from './core/config.js';\nimport { resolveConfig, type ResolvedConfig } from '../shared/core/config.js';\nimport { setConfig } from '../shared/core/platform-config.js';\nimport { ApiHttp } from '../shared/api/http.js';\nimport type { ShipClientOptions, DeployInput, DeploymentOptions, StaticFile, DeployBodyCreator } from '../shared/types.js';\nimport { createDeployBody } from './core/deploy-body.js';\n\n// Export all shared functionality\nexport * from '../shared/index.js';\n\n/**\n * Ship SDK Client for Node.js environments.\n * \n * Provides full file system access, configuration file loading,\n * and environment variable support.\n * \n * @example\n * ```typescript\n * // Authenticated deployments with API key\n * const ship = new Ship({ apiKey: \"ship-xxxx\" });\n * \n * // Single-use deployments with deploy token\n * const ship = new Ship({ deployToken: \"token-xxxx\" });\n * \n * // Deploy a directory\n * await ship.deploy('./dist');\n * ```\n */\nexport class Ship extends BaseShip {\n constructor(options: ShipClientOptions = {}) {\n const environment = getENV();\n\n if (environment !== 'node') {\n throw ShipError.business('Node.js Ship class can only be used in Node.js environment.');\n }\n\n super(options);\n }\n\n protected resolveInitialConfig(options: ShipClientOptions): ResolvedConfig {\n return resolveConfig(options, {});\n }\n\n protected async loadFullConfig(): Promise<void> {\n try {\n // Load config from file/env\n const loadedConfig = await loadConfig(this.clientOptions.configFile);\n // Re-resolve and re-create the http client with the full config\n const finalConfig = resolveConfig(this.clientOptions, loadedConfig);\n\n // Update auth state with loaded credentials (if not already set by constructor)\n // This ensures hasAuth() returns true after loading from env/config files\n if (finalConfig.deployToken && !this.clientOptions.deployToken) {\n this.setDeployToken(finalConfig.deployToken);\n } else if (finalConfig.apiKey && !this.clientOptions.apiKey) {\n this.setApiKey(finalConfig.apiKey);\n }\n\n // Replace HTTP client while preserving event listeners (clean intentional API)\n // Use the same getAuthHeaders callback as the initial client\n const newClient = new ApiHttp({\n ...this.clientOptions,\n ...finalConfig,\n getAuthHeaders: this.authHeadersCallback,\n createDeployBody: this.getDeployBodyCreator()\n });\n this.replaceHttpClient(newClient);\n\n const platformConfig = await this.http.getConfig();\n setConfig(platformConfig);\n } catch (error) {\n // Reset initialization promise so it can be retried\n this.initPromise = null;\n throw error;\n }\n }\n\n protected async processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]> {\n // Normalize string to string[] and validate\n const paths = typeof input === 'string' ? [input] : input;\n\n if (!Array.isArray(paths) || !paths.every(p => typeof p === 'string')) {\n throw ShipError.business('Invalid input type for Node.js environment. Expected string or string[].');\n }\n\n if (paths.length === 0) {\n throw ShipError.business('No files to deploy.');\n }\n\n // Process files directly - no intermediate conversion layer\n const { processFilesForNode } = await import('./core/node-files.js');\n return processFilesForNode(paths, options);\n }\n\n protected getDeployBodyCreator(): DeployBodyCreator {\n return createDeployBody;\n }\n}\n\n// Default export (for import Ship from 'ship')\nexport default Ship;\n\n// Node.js specific exports\nexport { loadConfig } from './core/config.js';\nexport { setConfig as setPlatformConfig, getCurrentConfig } from '../shared/core/platform-config.js';\n\n// Node.js utilities\nexport { processFilesForNode } from './core/node-files.js';\nexport { __setTestEnvironment, getENV } from '../shared/lib/env.js';","/**\n * Node.js-specific deploy body creation.\n */\nimport { ShipError } from '@shipstatic/types';\nimport type { StaticFile, DeployBody } from '../../shared/types.js';\nimport { getMimeType } from '../../shared/utils/mimeType.js';\n\nexport async function createDeployBody(\n files: StaticFile[],\n tags?: string[],\n via?: string\n): Promise<DeployBody> {\n const { FormData, File } = await import('formdata-node');\n const { FormDataEncoder } = await import('form-data-encoder');\n\n const formData = new FormData();\n const checksums: string[] = [];\n\n for (const file of files) {\n const contentType = getMimeType(file.path);\n\n let fileInstance;\n if (Buffer.isBuffer(file.content)) {\n fileInstance = new File([file.content], file.path, { type: contentType });\n } else if (typeof Blob !== 'undefined' && file.content instanceof Blob) {\n fileInstance = new File([file.content], file.path, { type: contentType });\n } else {\n throw ShipError.file(`Unsupported file.content type for Node.js: ${file.path}`, file.path);\n }\n\n if (!file.md5) {\n throw ShipError.file(`File missing md5 checksum: ${file.path}`, file.path);\n }\n\n const preservedPath = file.path.startsWith('/') ? file.path : '/' + file.path;\n formData.append('files[]', fileInstance, preservedPath);\n checksums.push(file.md5);\n }\n\n formData.append('checksums', JSON.stringify(checksums));\n\n if (tags && tags.length > 0) {\n formData.append('tags', JSON.stringify(tags));\n }\n\n if (via) {\n formData.append('via', via);\n }\n\n const encoder = new FormDataEncoder(formData);\n const chunks = [];\n for await (const chunk of encoder.encode()) {\n chunks.push(Buffer.from(chunk));\n }\n const body = Buffer.concat(chunks);\n\n return {\n body: body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) as ArrayBuffer,\n headers: {\n 'Content-Type': encoder.contentType,\n 'Content-Length': Buffer.byteLength(body).toString()\n }\n };\n}\n","/**\n * Browser-compatible MIME type utilities\n * Uses mime-db directly without Node.js dependencies\n */\nimport mimeDb from 'mime-db';\n\n// Build extension to MIME type map from mime-db\nconst extensionToMimeMap: { [key: string]: string } = {};\nfor (const type in mimeDb) {\n const mimeInfo = mimeDb[type];\n if (mimeInfo && mimeInfo.extensions) {\n mimeInfo.extensions.forEach((ext: string) => {\n if (!extensionToMimeMap[ext]) {\n extensionToMimeMap[ext] = type;\n }\n });\n }\n}\n\n/**\n * Get MIME type from file path (browser-compatible, no Node.js dependencies)\n */\nexport function getMimeType(path: string): string {\n const extension = path.includes('.')\n ? path.substring(path.lastIndexOf('.') + 1).toLowerCase()\n : '';\n return extensionToMimeMap[extension] || 'application/octet-stream';\n}\n","/**\n * Simple CLI utilities following \"impossible simplicity\" mantra\n */\nimport columnify from 'columnify';\nimport { bold, dim, green, red, yellow, blue, inverse, hidden } from 'yoctocolors';\n\nconst INTERNAL_FIELDS = ['isCreate'];\n\nconst applyColor = (colorFn: (text: string) => string, text: string, noColor?: boolean): string => {\n return noColor ? text : colorFn(text);\n};\n\n/**\n * Message helper functions for consistent CLI output\n */\nexport const success = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ success: msg }, null, 2) + '\\n');\n } else {\n console.log(`${applyColor(green, msg.toLowerCase().replace(/\\.$/, ''), noColor)}\\n`);\n }\n};\n\nexport const error = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.error(JSON.stringify({ error: msg }, null, 2) + '\\n');\n } else {\n const errorPrefix = applyColor((text) => inverse(red(text)), `${applyColor(hidden, '[', noColor)}error${applyColor(hidden, ']', noColor)}`, noColor);\n const errorMsg = applyColor(red, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.error(`${errorPrefix} ${errorMsg}\\n`);\n }\n};\n\nexport const warn = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ warning: msg }, null, 2) + '\\n');\n } else {\n const warnPrefix = applyColor((text) => inverse(yellow(text)), `${applyColor(hidden, '[', noColor)}warning${applyColor(hidden, ']', noColor)}`, noColor);\n const warnMsg = applyColor(yellow, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.log(`${warnPrefix} ${warnMsg}\\n`);\n }\n};\n\nexport const info = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ info: msg }, null, 2) + '\\n');\n } else {\n const infoPrefix = applyColor((text) => inverse(blue(text)), `${applyColor(hidden, '[', noColor)}info${applyColor(hidden, ']', noColor)}`, noColor);\n const infoMsg = applyColor(blue, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.log(`${infoPrefix} ${infoMsg}\\n`);\n }\n};\n\n\n/**\n * Format unix timestamp to ISO 8601 string without milliseconds, or return '-' if not provided\n */\nexport const formatTimestamp = (timestamp?: number, context: 'table' | 'details' = 'details', noColor?: boolean): string => {\n if (timestamp === undefined || timestamp === null || timestamp === 0) {\n return '-';\n }\n \n const isoString = new Date(timestamp * 1000).toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n \n // Hide the T and Z characters only in table/list views for cleaner appearance\n if (context === 'table') {\n return isoString.replace(/T/, applyColor(hidden, 'T', noColor)).replace(/Z$/, applyColor(hidden, 'Z', noColor));\n }\n \n return isoString;\n};\n\n/**\n * Format value for display.\n * Handles timestamps, file sizes, and boolean configs with special formatting.\n */\nconst formatValue = (key: string, value: unknown, context: 'table' | 'details' = 'details', noColor?: boolean): string => {\n if (typeof value === 'number' && (key === 'created' || key === 'expires' || key === 'linked')) {\n return formatTimestamp(value, context, noColor);\n }\n if (key === 'size' && typeof value === 'number') {\n const mb = value / (1024 * 1024);\n return mb >= 1 ? `${mb.toFixed(1)}Mb` : `${(value / 1024).toFixed(1)}Kb`;\n }\n if (key === 'config') {\n // Handle both boolean and number (0/1) values\n if (typeof value === 'boolean') {\n return value ? 'yes' : 'no';\n }\n if (typeof value === 'number') {\n return value === 1 ? 'yes' : 'no';\n }\n }\n return String(value);\n};\n\n/**\n * Format data as table with specified columns for easy parsing.\n * @param data - Array of objects to display as table rows\n * @param columns - Optional column order (defaults to first item's keys)\n * @param noColor - Disable colors\n * @param headerMap - Optional mapping of property names to display headers (e.g., { url: 'deployment' })\n */\nexport const formatTable = (data: object[], columns?: string[], noColor?: boolean, headerMap?: Record<string, string>): string => {\n if (!data || data.length === 0) return '';\n\n // Get column order from first item (preserves API order) or use provided columns\n const firstItem = data[0] as Record<string, unknown>;\n const columnOrder = columns || Object.keys(firstItem).filter(key =>\n firstItem[key] !== undefined && !INTERNAL_FIELDS.includes(key)\n );\n\n // Transform data preserving column order\n const transformedData = data.map(item => {\n const record = item as Record<string, unknown>;\n const transformed: Record<string, string> = {};\n columnOrder.forEach(col => {\n if (col in record && record[col] !== undefined) {\n transformed[col] = formatValue(col, record[col], 'table', noColor);\n }\n });\n return transformed;\n });\n\n const output = columnify(transformedData, {\n columnSplitter: ' ',\n columns: columnOrder,\n config: columnOrder.reduce<Record<string, { headingTransform: (h: string) => string }>>((config, col) => {\n config[col] = {\n headingTransform: (heading: string) => applyColor(dim, headerMap?.[heading] || heading, noColor)\n };\n return config;\n }, {})\n });\n \n // Clean output: remove null bytes and ensure clean spacing\n return output\n .split('\\n')\n .map((line: string) => line\n .replace(/\\0/g, '') // Remove any null bytes\n .replace(/\\s+$/, '') // Remove trailing spaces\n )\n .join('\\n') + '\\n';\n};\n\n/**\n * Format object properties as key-value pairs with space separation for readability.\n * @param obj - Object to display as key-value pairs\n * @param noColor - Disable colors\n */\nexport const formatDetails = (obj: object, noColor?: boolean): string => {\n const entries = (Object.entries(obj) as [string, unknown][]).filter(([key, value]) => {\n if (INTERNAL_FIELDS.includes(key)) return false;\n return value !== undefined;\n });\n \n if (entries.length === 0) return '';\n \n // Transform to columnify format while preserving order\n const data = entries.map(([key, value]) => ({\n property: key + ':',\n value: formatValue(key, value, 'details', noColor)\n }));\n \n const output = columnify(data, {\n columnSplitter: ' ',\n showHeaders: false,\n config: {\n property: { \n dataTransform: (value: string) => applyColor(dim, value, noColor)\n }\n }\n });\n \n // Clean output: remove null bytes and ensure clean spacing\n return output\n .split('\\n')\n .map((line: string) => line.replace(/\\0/g, '')) // Remove any null bytes\n .join('\\n') + '\\n';\n};\n\n","/**\n * Pure formatting functions for CLI output.\n * All formatters are synchronous and have no side effects beyond console output.\n */\nimport type {\n Deployment,\n DeploymentListResponse,\n DomainListResponse,\n DomainValidateResponse,\n Account,\n TokenCreateResponse,\n TokenListResponse\n} from '@shipstatic/types';\nimport type { EnrichedDomain, MessageResult, CLIResult } from './types.js';\nimport { formatTable, formatDetails, success, error, info } from './utils.js';\n\nexport interface OutputContext {\n operation?: string;\n resourceType?: string;\n resourceId?: string;\n}\n\nexport interface FormatOptions {\n isJson?: boolean;\n noColor?: boolean;\n}\n\n/**\n * Format deployments list\n */\nexport function formatDeploymentsList(result: DeploymentListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.deployments || result.deployments.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ deployments: [] }, null, 2));\n } else {\n console.log('no deployments found');\n console.log();\n }\n return;\n }\n\n const columns = ['url', 'tags', 'created'];\n console.log(formatTable(result.deployments, columns, noColor, { url: 'deployment' }));\n}\n\n/**\n * Format domains list\n */\nexport function formatDomainsList(result: DomainListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.domains || result.domains.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ domains: [] }, null, 2));\n } else {\n console.log('no domains found');\n console.log();\n }\n return;\n }\n\n const columns = ['url', 'deployment', 'tags', 'linked', 'created'];\n console.log(formatTable(result.domains, columns, noColor, { url: 'domain' }));\n}\n\n/**\n * Format single domain result.\n * Expects _dnsRecords and _shareHash to be pre-populated for new external domains.\n */\nexport function formatDomain(result: EnrichedDomain, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n // Show success message for set/update operations\n if (result.domain && (context.operation === 'set' || context.operation === 'update')) {\n const verb = context.operation === 'update' ? 'updated'\n : result.isCreate ? 'created' : 'updated';\n success(`${result.domain} domain ${verb}`, isJson, noColor);\n }\n\n // Display pre-fetched DNS records (for new external domains)\n if (!isJson && result._dnsRecords && result._dnsRecords.length > 0) {\n console.log();\n info('DNS Records to configure:', isJson, noColor);\n result._dnsRecords.forEach((record) => {\n console.log(` ${record.type}: ${record.name} → ${record.value}`);\n });\n }\n\n // Display setup instructions link\n if (!isJson && result._shareHash) {\n console.log();\n info(`Setup instructions: https://setup.shipstatic.com/${result._shareHash}/${result.domain}`, isJson, noColor);\n }\n\n // Filter out internal fields before displaying details\n const { _dnsRecords, _shareHash, ...displayResult } = result;\n\n console.log();\n console.log(formatDetails(displayResult, noColor));\n}\n\n/**\n * Format single deployment result\n */\nexport function formatDeployment(result: Deployment, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n // Show success message for create operations\n if (result.status && context.operation === 'create') {\n success(`${result.deployment} deployment created`, isJson, noColor);\n }\n\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Format account/email result\n */\nexport function formatAccount(result: Account, context: OutputContext, options: FormatOptions): void {\n const { noColor } = options;\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Format message result (e.g., from DNS verification)\n */\nexport function formatMessage(result: MessageResult, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n if (result.message) {\n success(result.message, isJson, noColor);\n }\n}\n\n/**\n * Format domain validation result\n */\nexport function formatDomainValidate(result: DomainValidateResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (isJson) {\n console.log(JSON.stringify(result, null, 2));\n console.log();\n return;\n }\n\n if (result.valid) {\n success(`domain is valid`, isJson, noColor);\n console.log();\n if (result.normalized) {\n console.log(` normalized: ${result.normalized}`);\n }\n if (result.available !== undefined) {\n const availabilityText = result.available ? 'available ✓' : 'already taken';\n console.log(` availability: ${availabilityText}`);\n }\n console.log();\n } else {\n error(result.error || 'domain is invalid', isJson, noColor);\n }\n}\n\n/**\n * Format tokens list\n */\nexport function formatTokensList(result: TokenListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.tokens || result.tokens.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ tokens: [] }, null, 2));\n } else {\n console.log('no tokens found');\n console.log();\n }\n return;\n }\n\n const columns = ['token', 'tags', 'created', 'expires'];\n console.log(formatTable(result.tokens, columns, noColor));\n}\n\n/**\n * Format single token result\n */\nexport function formatToken(result: TokenCreateResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (context.operation === 'create' && result.token) {\n success(`token created`, isJson, noColor);\n }\n\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Main output function - routes to appropriate formatter based on result shape.\n * Handles JSON mode, removal operations, and ping results.\n */\nexport function formatOutput(\n result: CLIResult,\n context: OutputContext,\n options: FormatOptions\n): void {\n const { isJson, noColor } = options;\n\n // Handle void/undefined results (removal operations)\n if (result === undefined) {\n if (context.operation === 'remove' && context.resourceType && context.resourceId) {\n success(`${context.resourceId} ${context.resourceType.toLowerCase()} removed`, isJson, noColor);\n } else {\n success('removed successfully', isJson, noColor);\n }\n return;\n }\n\n // Handle ping result (boolean or PingResponse)\n if (result === true || (result !== null && typeof result === 'object' && 'success' in result)) {\n const isSuccess = result === true || (result as { success: boolean }).success;\n if (isSuccess) {\n success('api reachable', isJson, noColor);\n } else {\n error('api unreachable', isJson, noColor);\n }\n return;\n }\n\n // JSON mode: output raw JSON for all results\n if (isJson && result !== null && typeof result === 'object') {\n // Filter internal fields from JSON output\n const output = { ...result } as Record<string, unknown>;\n delete output._dnsRecords;\n delete output._shareHash;\n console.log(JSON.stringify(output, null, 2));\n console.log();\n return;\n }\n\n // Route to specific formatter based on result shape\n // Order matters: check list types before singular types\n if (result !== null && typeof result === 'object') {\n if ('deployments' in result) {\n formatDeploymentsList(result as DeploymentListResponse, context, options);\n } else if ('domains' in result) {\n formatDomainsList(result as DomainListResponse, context, options);\n } else if ('tokens' in result) {\n formatTokensList(result as TokenListResponse, context, options);\n } else if ('domain' in result) {\n formatDomain(result as EnrichedDomain, context, options);\n } else if ('deployment' in result) {\n formatDeployment(result as Deployment, context, options);\n } else if ('token' in result) {\n formatToken(result as TokenCreateResponse, context, options);\n } else if ('email' in result) {\n formatAccount(result as Account, context, options);\n } else if ('valid' in result) {\n formatDomainValidate(result as DomainValidateResponse, context, options);\n } else if ('message' in result) {\n formatMessage(result as MessageResult, context, options);\n } else {\n // Fallback\n success('success', isJson, noColor);\n }\n } else {\n // Fallback for non-object results\n success('success', isJson, noColor);\n }\n}\n","/**\n * Shell completion install/uninstall logic.\n * Handles bash, zsh, and fish shells.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { success, error, info, warn } from './utils.js';\n\nexport interface CompletionOptions {\n isJson?: boolean;\n noColor?: boolean;\n}\n\n/**\n * Detect current shell from environment\n */\nfunction detectShell(): 'bash' | 'zsh' | 'fish' | null {\n const shell = process.env.SHELL || '';\n if (shell.includes('bash')) return 'bash';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n return null;\n}\n\n/**\n * Get shell-specific paths\n */\nfunction getShellPaths(shell: 'bash' | 'zsh' | 'fish', homeDir: string) {\n switch (shell) {\n case 'bash':\n return {\n completionFile: path.join(homeDir, '.ship_completion.bash'),\n profileFile: path.join(homeDir, '.bash_profile'),\n scriptName: 'ship.bash'\n };\n case 'zsh':\n return {\n completionFile: path.join(homeDir, '.ship_completion.zsh'),\n profileFile: path.join(homeDir, '.zshrc'),\n scriptName: 'ship.zsh'\n };\n case 'fish':\n return {\n completionFile: path.join(homeDir, '.config/fish/completions/ship.fish'),\n profileFile: null, // fish doesn't need profile sourcing\n scriptName: 'ship.fish'\n };\n }\n}\n\n/**\n * Install shell completion script\n */\nexport function installCompletion(scriptDir: string, options: CompletionOptions = {}): void {\n const { isJson, noColor } = options;\n const shell = detectShell();\n const homeDir = os.homedir();\n\n if (!shell) {\n error(`unsupported shell: ${process.env.SHELL}. supported: bash, zsh, fish`, isJson, noColor);\n return;\n }\n\n const paths = getShellPaths(shell, homeDir);\n const sourceScript = path.join(scriptDir, paths.scriptName);\n\n try {\n // Fish has a different installation pattern\n if (shell === 'fish') {\n const fishDir = path.dirname(paths.completionFile);\n if (!fs.existsSync(fishDir)) {\n fs.mkdirSync(fishDir, { recursive: true });\n }\n fs.copyFileSync(sourceScript, paths.completionFile);\n success('fish completion installed successfully', isJson, noColor);\n info('please restart your shell to apply the changes', isJson, noColor);\n return;\n }\n\n // Bash and zsh: copy script and add sourcing to profile\n fs.copyFileSync(sourceScript, paths.completionFile);\n const sourceLine = `# ship\\nsource '${paths.completionFile}'\\n# ship end`;\n\n if (paths.profileFile) {\n if (fs.existsSync(paths.profileFile)) {\n const content = fs.readFileSync(paths.profileFile, 'utf-8');\n if (!content.includes('# ship') || !content.includes('# ship end')) {\n const prefix = content.length > 0 && !content.endsWith('\\n') ? '\\n' : '';\n fs.appendFileSync(paths.profileFile, prefix + sourceLine);\n }\n } else {\n fs.writeFileSync(paths.profileFile, sourceLine);\n }\n\n success(`completion script installed for ${shell}`, isJson, noColor);\n warn(`run \"source ${paths.profileFile}\" or restart your shell`, isJson, noColor);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n error(`could not install completion script: ${message}`, isJson, noColor);\n }\n}\n\n/**\n * Uninstall shell completion script\n */\nexport function uninstallCompletion(options: CompletionOptions = {}): void {\n const { isJson, noColor } = options;\n const shell = detectShell();\n const homeDir = os.homedir();\n\n if (!shell) {\n error(`unsupported shell: ${process.env.SHELL}. supported: bash, zsh, fish`, isJson, noColor);\n return;\n }\n\n const paths = getShellPaths(shell, homeDir);\n\n try {\n // Fish: just remove the file\n if (shell === 'fish') {\n if (fs.existsSync(paths.completionFile)) {\n fs.unlinkSync(paths.completionFile);\n success('fish completion uninstalled successfully', isJson, noColor);\n } else {\n warn('fish completion was not installed', isJson, noColor);\n }\n info('please restart your shell to apply the changes', isJson, noColor);\n return;\n }\n\n // Bash and zsh: remove file and clean profile\n if (fs.existsSync(paths.completionFile)) {\n fs.unlinkSync(paths.completionFile);\n }\n\n if (!paths.profileFile) return;\n\n if (!fs.existsSync(paths.profileFile)) {\n error('profile file not found', isJson, noColor);\n return;\n }\n\n const content = fs.readFileSync(paths.profileFile, 'utf-8');\n const lines = content.split('\\n');\n\n // Remove ship block (between \"# ship\" and \"# ship end\")\n const filtered: string[] = [];\n let i = 0;\n let removed = false;\n\n while (i < lines.length) {\n if (lines[i].trim() === '# ship') {\n removed = true;\n i++;\n while (i < lines.length && lines[i].trim() !== '# ship end') i++;\n if (i < lines.length) i++; // skip \"# ship end\"\n } else {\n filtered.push(lines[i]);\n i++;\n }\n }\n\n if (removed) {\n const endsWithNewline = content.endsWith('\\n');\n const newContent = filtered.length === 0\n ? ''\n : filtered.join('\\n') + (endsWithNewline ? '\\n' : '');\n fs.writeFileSync(paths.profileFile, newContent);\n success(`completion script uninstalled for ${shell}`, isJson, noColor);\n warn(`run \"source ${paths.profileFile}\" or restart your shell`, isJson, noColor);\n } else {\n error('completion was not found in profile', isJson, noColor);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n error(`could not uninstall completion script: ${message}`, isJson, noColor);\n }\n}\n","/**\n * @file Error handling utilities for the CLI.\n * Pure functions for error message formatting - fully unit testable.\n */\n\nimport { ShipError, isShipError } from '@shipstatic/types';\n\n/**\n * Convert any error to a ShipError.\n * Used by the CLI's global error handler to normalize unknown errors.\n */\nexport function toShipError(err: unknown): ShipError {\n if (isShipError(err)) {\n return err;\n }\n if (err instanceof Error) {\n return ShipError.business(err.message);\n }\n return ShipError.business(String(err ?? 'Unknown error'));\n}\n\n/**\n * Context for error message generation\n */\nexport interface ErrorContext {\n operation?: string;\n resourceType?: string;\n resourceId?: string;\n}\n\n/**\n * CLI options relevant to error message generation\n */\nexport interface ErrorOptions {\n apiKey?: string;\n deployToken?: string;\n}\n\n/**\n * Get actionable user-facing message from an error.\n * Transforms technical errors into helpful messages that tell users what to do.\n *\n * This is a pure function - given the same inputs, always returns the same output.\n * All error message logic is centralized here for easy testing and maintenance.\n */\nexport function getUserMessage(\n err: ShipError,\n context?: ErrorContext,\n options?: ErrorOptions\n): string {\n // Auth errors - tell user what credentials to provide\n if (err.isAuthError()) {\n if (options?.apiKey) {\n return 'authentication failed: invalid API key';\n } else if (options?.deployToken) {\n return 'authentication failed: invalid or expired deploy token';\n } else {\n return 'authentication required: use --api-key or --deploy-token, or set SHIP_API_KEY';\n }\n }\n\n // Network errors - include context about what failed\n if (err.isNetworkError()) {\n const url = err.details?.url;\n if (url) {\n return `network error: could not reach ${url}`;\n }\n return 'network error: could not reach the API. check your internet connection';\n }\n\n // File, validation, config errors - trust the original message (we wrote it)\n if (err.isFileError() || err.isValidationError() || err.isClientError()) {\n return err.message;\n }\n\n // API errors with 4xx status - these have user-facing messages from the API\n // Includes: 400 (validation), 404 (not found), 409 (conflict), etc.\n if (err.status && err.status >= 400 && err.status < 500) {\n return err.message;\n }\n\n // Server errors (5xx) - generic but actionable\n return 'server error: please try again or check https://status.shipstatic.com';\n}\n\n/**\n * Format error for JSON output.\n * Returns the JSON string to be output (without newline).\n */\nexport function formatErrorJson(message: string, details?: unknown): string {\n return JSON.stringify({\n error: message,\n ...(details ? { details } : {})\n }, null, 2);\n}\n"],"mappings":"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","names":["isShipError","error","validateApiKey","apiKey","API_KEY_PREFIX","ShipError","API_KEY_TOTAL_LENGTH","API_KEY_HEX_LENGTH","hexPart","validateDeployToken","deployToken","DEPLOY_TOKEN_PREFIX","DEPLOY_TOKEN_TOTAL_LENGTH","DEPLOY_TOKEN_HEX_LENGTH","validateApiUrl","apiUrl","url","ErrorType","ERROR_CATEGORIES","DEPLOYMENT_CONFIG_FILENAME","DEFAULT_API","init_dist","__esmMin","_ShipError","type","message","status","details","response","resource","id","cause","filePath","errorType","setConfig","config","_config","getCurrentConfig","ShipError","init_platform_config","__esmMin","init_dist","detectEnvironment","getENV","_testEnvironment","init_env","__esmMin","calculateMD5Browser","blob","SparkMD5","resolve","reject","chunks","currentChunk","spark","fileReader","loadNext","start","end","e","result","ShipError","calculateMD5Node","input","crypto","hash","fs","stream","err","chunk","calculateMD5","env","getENV","init_md5","__esmMin","init_env","init_dist","validateConfig","config","ConfigSchema","error","firstError","path","ShipError","loadConfigFromFile","configFile","getENV","cosmiconfigSync","os","explorer","MODULE_NAME","result","isShipError","loadConfig","envConfig","fileConfig","mergedConfig","import_zod","init_config","__esmMin","init_dist","init_env","filterJunk","filePaths","filePath","parts","basename","directorySegments","segment","JUNK_DIRECTORIES","junkDir","import_junk","init_junk","__esmMin","findCommonParent","dirPaths","normalizedPaths","p","pathSegments","commonSegments","minLength","i","segment","segments","normalizeWebPath","path","init_path","__esmMin","optimizeDeployPaths","filePaths","options","path","normalizeWebPath","extractFileName","commonPrefix","findCommonDirectory","filePath","deployPath","prefixToRemove","pathSegments","commonSegments","minLength","segments","i","segment","init_deploy_paths","__esmMin","init_path","node_files_exports","__export","processFilesForNode","findAllFilePaths","dirPath","visited","results","realPath","entries","entry","fullPath","stats","subFiles","paths","options","getENV","ShipError","absolutePaths","p","absPath","uniquePaths","validPaths","filterJunk","inputAbsolutePaths","inputBasePath","findCommonParent","relativePaths","filePath","rel","deployFiles","optimizeDeployPaths","totalSize","platformLimits","getCurrentConfig","i","deployPath","content","md5","calculateMD5","error","isShipError","errorMessage","fs","path","init_node_files","__esmMin","init_env","init_md5","init_junk","init_dist","init_platform_config","init_deploy_paths","init_path","import_commander","init_dist","SimpleEvents","event","handler","eventHandlers","args","handlerArray","error","target","handlers","ENDPOINTS","DEFAULT_REQUEST_TIMEOUT","ApiHttp","SimpleEvents","options","DEFAULT_API","target","url","operationName","headers","signal","cleanup","fetchOptions","response","error","err","data","customHeaders","existingSignal","controller","timeoutId","abort","errorData","json","obj","message","ShipError","isShipError","files","file","body","bodyHeaders","authHeaders","id","tags","name","deployment","status","ttl","token","indexFile","f","indexContent","init_dist","init_platform_config","init_dist","init_dist","resolveConfig","userOptions","loadedConfig","finalConfig","DEFAULT_API","result","mergeDeployOptions","options","clientDefaults","init_dist","init_md5","createSPAConfig","configString","content","md5","calculateMD5","DEPLOYMENT_CONFIG_FILENAME","detectAndConfigureSPA","files","apiClient","options","f","spaConfig","createDeploymentResource","ctx","getApi","ensureInit","processInput","clientDefaults","hasAuth","input","options","mergedOptions","mergeDeployOptions","ShipError","apiClient","staticFiles","detectAndConfigureSPA","id","createDomainResource","name","deployment","tags","createAccountResource","createTokenResource","token","Ship","options","config","ApiHttp","ctx","createDeploymentResource","input","createDomainResource","createAccountResource","createTokenResource","getCurrentConfig","event","handler","newClient","error","token","ShipError","key","init_dist","init_env","init_config","init_platform_config","init_dist","import_mime_db","extensionToMimeMap","type","mimeDb","mimeInfo","ext","getMimeType","path","extension","createDeployBody","files","tags","via","FormData","File","FormDataEncoder","formData","checksums","file","contentType","getMimeType","fileInstance","ShipError","preservedPath","encoder","chunks","chunk","body","Ship","options","getENV","ShipError","resolveConfig","loadedConfig","loadConfig","finalConfig","newClient","ApiHttp","platformConfig","setConfig","error","input","paths","p","processFilesForNode","createDeployBody","init_dist","import_fs","path","import_columnify","import_yoctocolors","INTERNAL_FIELDS","applyColor","colorFn","text","noColor","success","msg","isJson","error","errorPrefix","errorMsg","warn","warnPrefix","warnMsg","info","infoPrefix","infoMsg","formatTimestamp","timestamp","context","isoString","formatValue","key","value","mb","formatTable","data","columns","headerMap","firstItem","columnOrder","transformedData","item","record","transformed","col","columnify","config","heading","line","formatDetails","obj","entries","formatDeploymentsList","result","context","options","isJson","noColor","columns","formatTable","formatDomainsList","formatDomain","verb","success","info","record","_dnsRecords","_shareHash","displayResult","formatDetails","formatDeployment","formatAccount","formatMessage","formatDomainValidate","availabilityText","error","formatTokensList","formatToken","formatOutput","output","fs","path","os","detectShell","shell","getShellPaths","homeDir","installCompletion","scriptDir","options","isJson","noColor","error","paths","sourceScript","fishDir","success","info","sourceLine","content","prefix","warn","e","message","uninstallCompletion","lines","filtered","i","removed","endsWithNewline","newContent","init_dist","toShipError","err","isShipError","ShipError","getUserMessage","context","options","url","formatErrorJson","message","details","import_yoctocolors","loadPackageJson","paths","p","packageJson","program","err","globalOptions","message","error","displayHelp","str","noColor","applyBold","text","applyDim","output","collect","value","previous","mergeTagOption","cmdOptions","programOpts","tags","handleUnknownSubcommand","validSubcommands","args","processOptions","commandObj","unknownArg","arg","command","options","handleError","context","opts","shipError","toShipError","getUserMessage","formatErrorJson","withErrorHandling","handler","client","createClient","result","outputContext","errorContext","config","apiUrl","apiKey","deployToken","Ship","performDeploy","deployPath","commandContext","ShipError","stats","deployOptions","abortController","spinner","yoctoSpinner","sigintHandler","formatOutput","thisCommand","actionCommand","validateApiKey","validateDeployToken","validateApiUrl","validationError","isShipError","deploymentsCmd","deployment","id","domainsCmd","name","records","share","tokensCmd","token","accountCmd","completionCmd","scriptDir","installCompletion","uninstallCompletion","handleCompletion","isBash","isZsh","isFish","code","exitCode"]}
1
+ {"version":3,"sources":["../node_modules/.pnpm/@shipstatic+types@0.4.22/node_modules/@shipstatic/types/dist/index.js","../src/shared/core/platform-config.ts","../src/shared/lib/env.ts","../src/shared/lib/md5.ts","../src/node/core/config.ts","../src/shared/lib/junk.ts","../src/shared/lib/path.ts","../src/shared/lib/deploy-paths.ts","../src/node/core/node-files.ts","../src/node/cli/index.ts","../src/shared/api/http.ts","../src/shared/events.ts","../src/shared/base-ship.ts","../src/shared/resources.ts","../src/shared/core/config.ts","../src/shared/lib/spa.ts","../src/node/index.ts","../src/node/core/deploy-body.ts","../src/shared/utils/mimeType.ts","../src/node/cli/utils.ts","../src/node/cli/formatters.ts","../src/node/cli/completion.ts","../src/node/cli/error-handling.ts"],"sourcesContent":["/**\n * @file Shared TypeScript types, constants, and utilities for the Shipstatic platform.\n * This package is the single source of truth for all shared data structures.\n */\n// =============================================================================\n// I. CORE ENTITIES\n// =============================================================================\n/**\n * Deployment status constants\n */\nexport const DeploymentStatus = {\n PENDING: 'pending',\n SUCCESS: 'success',\n FAILED: 'failed',\n DELETING: 'deleting'\n};\n// =============================================================================\n// DOMAIN TYPES\n// =============================================================================\n/**\n * Domain status constants\n *\n * - PENDING: DNS not configured\n * - PARTIAL: DNS partially configured\n * - SUCCESS: DNS fully verified\n * - PAUSED: Domain paused due to plan enforcement (billing)\n */\nexport const DomainStatus = {\n PENDING: 'pending',\n PARTIAL: 'partial',\n SUCCESS: 'success',\n PAUSED: 'paused'\n};\n// =============================================================================\n// ACCOUNT TYPES\n// =============================================================================\n/**\n * Account plan constants\n */\nexport const AccountPlan = {\n FREE: 'free',\n STANDARD: 'standard',\n SPONSORED: 'sponsored',\n ENTERPRISE: 'enterprise',\n SUSPENDED: 'suspended',\n TERMINATING: 'terminating',\n TERMINATED: 'terminated'\n};\n// =============================================================================\n// ERROR SYSTEM\n// =============================================================================\n/**\n * All possible error types in the Shipstatic platform\n * Names are developer-friendly while wire format stays consistent\n */\nexport var ErrorType;\n(function (ErrorType) {\n /** Validation failed (400) */\n ErrorType[\"Validation\"] = \"validation_failed\";\n /** Resource not found (404) */\n ErrorType[\"NotFound\"] = \"not_found\";\n /** Rate limit exceeded (429) */\n ErrorType[\"RateLimit\"] = \"rate_limit_exceeded\";\n /** Authentication required (401) */\n ErrorType[\"Authentication\"] = \"authentication_failed\";\n /** Business logic error (400) */\n ErrorType[\"Business\"] = \"business_logic_error\";\n /** API server error (500) - renamed from Internal for clarity */\n ErrorType[\"Api\"] = \"internal_server_error\";\n /** Network/connection error */\n ErrorType[\"Network\"] = \"network_error\";\n /** Operation was cancelled */\n ErrorType[\"Cancelled\"] = \"operation_cancelled\";\n /** File operation error */\n ErrorType[\"File\"] = \"file_error\";\n /** Configuration error */\n ErrorType[\"Config\"] = \"config_error\";\n})(ErrorType || (ErrorType = {}));\n/**\n * Categorizes error types for better type checking\n */\nconst ERROR_CATEGORIES = {\n client: new Set([ErrorType.Business, ErrorType.Config, ErrorType.File, ErrorType.Validation]),\n network: new Set([ErrorType.Network]),\n auth: new Set([ErrorType.Authentication]),\n};\n/**\n * Simple unified error class for both API and SDK\n */\nexport class ShipError extends Error {\n type;\n status;\n details;\n constructor(type, message, status, details) {\n super(message);\n this.type = type;\n this.status = status;\n this.details = details;\n this.name = 'ShipError';\n }\n /** Convert to wire format */\n toResponse() {\n // For security, exclude internal details from authentication errors in API responses\n const details = this.type === ErrorType.Authentication && this.details?.internal\n ? undefined\n : this.details;\n return {\n error: this.type,\n message: this.message,\n status: this.status,\n details\n };\n }\n /** Create from wire format */\n static fromResponse(response) {\n return new ShipError(response.error, response.message, response.status, response.details);\n }\n // Factory methods for common errors\n static validation(message, details) {\n return new ShipError(ErrorType.Validation, message, 400, details);\n }\n static notFound(resource, id) {\n const message = id ? `${resource} ${id} not found` : `${resource} not found`;\n return new ShipError(ErrorType.NotFound, message, 404);\n }\n static rateLimit(message = \"Too many requests\") {\n return new ShipError(ErrorType.RateLimit, message, 429);\n }\n static authentication(message = \"Authentication required\", details) {\n return new ShipError(ErrorType.Authentication, message, 401, details);\n }\n static business(message, status = 400) {\n return new ShipError(ErrorType.Business, message, status);\n }\n static network(message, cause) {\n return new ShipError(ErrorType.Network, message, undefined, { cause });\n }\n static cancelled(message) {\n return new ShipError(ErrorType.Cancelled, message);\n }\n static file(message, filePath) {\n return new ShipError(ErrorType.File, message, undefined, { filePath });\n }\n static config(message, details) {\n return new ShipError(ErrorType.Config, message, undefined, details);\n }\n static api(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n static database(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n static storage(message, status = 500) {\n return new ShipError(ErrorType.Api, message, status);\n }\n // Helper getter for accessing file path from details\n get filePath() {\n return this.details?.filePath;\n }\n // Helper methods for error type checking using categorization\n isClientError() {\n return ERROR_CATEGORIES.client.has(this.type);\n }\n isNetworkError() {\n return ERROR_CATEGORIES.network.has(this.type);\n }\n isAuthError() {\n return ERROR_CATEGORIES.auth.has(this.type);\n }\n isValidationError() {\n return this.type === ErrorType.Validation;\n }\n isFileError() {\n return this.type === ErrorType.File;\n }\n isConfigError() {\n return this.type === ErrorType.Config;\n }\n // Generic type checker\n isType(errorType) {\n return this.type === errorType;\n }\n}\n/**\n * Type guard to check if an unknown value is a ShipError.\n *\n * Uses structural checking instead of instanceof to handle module duplication\n * in bundled applications where multiple copies of the ShipError class may exist.\n *\n * @example\n * if (isShipError(error)) {\n * console.log(error.status, error.message);\n * }\n */\nexport function isShipError(error) {\n return (error !== null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === 'ShipError' &&\n 'status' in error);\n}\n/**\n * Allowed MIME types for static web hosting.\n *\n * This is a static platform constant, not per-user configuration.\n * Safe to share across frontend/backend due to atomic deploys.\n *\n * Validation rules:\n * - Exact match: 'application/json' allows only 'application/json'\n * - Prefix match: 'image/' allows all image types (png, jpeg, webp, etc.)\n *\n * Coverage: 100% of browser-renderable web content\n * - Core web (HTML, CSS, JS, WASM)\n * - Media (images, audio, video, fonts)\n * - Documents (PDF, Markdown, data formats)\n * - Modern web (PWA, 3D, structured data)\n *\n * ============================================================================\n * INTENTIONALLY EXCLUDED (Security & Platform Integrity)\n * ============================================================================\n *\n * We are a WEB HOSTING platform, not a file distribution service.\n * GitHub Pages-style parity for renderable content, more restrictive for downloads.\n *\n * 1. EXECUTABLES (Malware Distribution)\n * → .exe, .msi, .dmg, .deb, .rpm, .app, .apk, .jar\n * → Reason: Direct malware delivery vector\n * → Alternative: Use GitHub Releases or dedicated software distribution CDN\n *\n * 2. ARCHIVES (Piracy & Abuse)\n * → .zip, .rar, .tar, .gz, .7z, .bz2\n * → Reason: File sharing abuse, can contain executables, no web rendering\n * → Alternative: Use file hosting service (Dropbox, Google Drive) or GitHub Releases\n *\n * 3. SERVER-SIDE SCRIPTS (Credential Leakage)\n * → .php, .asp, .jsp, .cgi\n * → Reason: Source code exposure (database passwords, API keys, secrets)\n * → Alternative: Static hosting only - use serverless functions for backends\n *\n * 4. SHELL SCRIPTS (OS Execution)\n * → .sh, .bash, .bat, .cmd, .ps1, .vbs\n * → Reason: Execute on user's OS outside browser sandbox, social engineering risk\n * → Alternative: Embed code examples in HTML <pre><code> or link to GitHub repo\n *\n * 5. PROGRAMMING LANGUAGE SOURCE (Platform Scope)\n * → .py, .rb, .pl, .java, .c, .cpp, .cs, .go, .rs\n * → Reason: Not web-renderable, better served by GitHub/GitLab/Bitbucket\n * → Alternative: Use GitHub for code hosting, link to repository\n *\n * 6. OFFICE DOCUMENTS (Macro Malware)\n * → .doc, .docx, .xls, .xlsx, .ppt, .pptx\n * → Reason: Can contain VBA macros, active exploits in the wild\n * → Alternative: Use PDF for documents (fully supported)\n *\n * 7. GENERIC BINARIES (Unvalidatable)\n * → application/octet-stream\n * → Reason: Too broad - allows any binary format, cannot moderate effectively\n * → Alternative: Use specific MIME types for known formats\n *\n * ============================================================================\n * Security Model:\n * - Browser sandbox (JS/WASM execute safely in controlled environment)\n * - AI content moderation (scans text/image content for abuse)\n * - No server-side execution (static files only)\n * - Explicit allowlist (only approved formats, reject unknown)\n * ============================================================================\n */\nexport const ALLOWED_MIME_TYPES = [\n // =========================================================================\n // TEXT CONTENT (explicit list - no prefix matching for security)\n // =========================================================================\n // Core web documents\n 'text/html', // HTML pages\n 'text/css', // Stylesheets\n 'text/plain', // Plain text (robots.txt, .well-known/*, LICENSE, README.txt)\n 'text/markdown', // Markdown files (.md)\n 'text/xml', // XML files\n // Data formats\n 'text/csv', // CSV data files\n 'text/yaml', // YAML config files\n // Web-specific formats\n 'text/vtt', // WebVTT video subtitles/captions (accessibility)\n 'text/calendar', // iCalendar (.ics) event files\n // JavaScript (legacy MIME type, still widely used by ~50% of servers)\n 'text/javascript',\n // Modern web development formats (uncompiled source)\n 'text/typescript', // TypeScript source (.ts)\n 'text/tsx', // TypeScript JSX (.tsx)\n 'text/jsx', // React JSX (.jsx)\n 'text/x-scss', // SCSS preprocessor\n 'text/x-sass', // Sass preprocessor\n 'text/x-less', // Less preprocessor\n 'text/stylus', // Stylus preprocessor\n 'text/x-vue', // Vue single-file components (.vue)\n 'text/x-svelte', // Svelte components (.svelte)\n // =========================================================================\n // MEDIA (prefix matching - covers all common subtypes)\n // =========================================================================\n // Images: PNG, JPEG, GIF, SVG, WebP, AVIF, HEIC, BMP, TIFF, ICO, etc.\n 'image/',\n // Audio: MP3, OGG, WAV, WebM, AAC, FLAC, Opus, etc.\n 'audio/',\n // Video: MP4, WebM, OGG, QuickTime, etc.\n 'video/',\n // Modern fonts: WOFF2, WOFF, TTF, OTF\n 'font/',\n // =========================================================================\n // CORE WEB APPLICATION TYPES\n // =========================================================================\n // JavaScript (multiple MIME types for compatibility)\n 'application/javascript', // Modern standard (RFC 9239)\n 'application/ecmascript', // ECMAScript (legacy but still used)\n 'application/x-javascript', // Legacy variant (old CDNs, Apache configs)\n // WebAssembly (modern web apps, games, compute-heavy workloads)\n 'application/wasm',\n // JSON and structured data\n 'application/json',\n 'application/ld+json', // JSON-LD for structured data / SEO (Schema.org, Open Graph)\n 'application/manifest+json', // PWA web app manifests\n // Development tools\n 'application/source-map', // Source maps (.js.map, .css.map) for debugging\n // XML and feeds\n 'application/xml',\n 'application/xhtml+xml', // XHTML - XML-compliant HTML (legacy sites)\n 'application/rss+xml', // RSS feeds (blogs, podcasts)\n 'application/atom+xml', // Atom feeds\n // Configuration formats\n 'application/yaml', // YAML configs (static site generators)\n 'application/toml', // TOML configs (Cargo, Netlify, Rust projects)\n // Documents\n 'application/pdf', // PDF documents\n // =========================================================================\n // 3D FORMATS (industry standard only)\n // =========================================================================\n // glTF - Khronos standard for 3D web content\n 'model/gltf+json', // glTF JSON format\n 'model/gltf-binary', // GLB binary format\n // =========================================================================\n // LEGACY COMPATIBILITY\n // =========================================================================\n // Video (some tools detect MP4 as application/mp4)\n 'application/mp4',\n // Legacy font MIME types (Bootstrap, Font Awesome, IE compatibility)\n 'application/font-woff',\n 'application/font-woff2',\n 'application/x-font-woff',\n 'application/x-woff',\n 'application/vnd.ms-fontobject', // EOT files (Internet Explorer)\n 'application/x-font-ttf',\n 'application/x-font-truetype',\n 'application/x-font-otf',\n 'application/x-font-opentype',\n];\n/**\n * Check if a MIME type is allowed for upload.\n *\n * Supports both exact matches and prefix matches:\n * - 'application/json' matches 'application/json' exactly\n * - 'text/' matches 'text/plain', 'text/html', etc.\n *\n * @example\n * isAllowedMimeType('text/plain') // true (prefix match)\n * isAllowedMimeType('application/json') // true (exact match)\n * isAllowedMimeType('application/wasm') // false (not allowed)\n */\nexport function isAllowedMimeType(mimeType) {\n return ALLOWED_MIME_TYPES.some(allowed => mimeType === allowed || mimeType.startsWith(allowed));\n}\n// API Key Configuration\nexport const API_KEY_PREFIX = 'ship-';\nexport const API_KEY_HEX_LENGTH = 64;\nexport const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69\n// Deploy Token Configuration\nexport const DEPLOY_TOKEN_PREFIX = 'token-';\nexport const DEPLOY_TOKEN_HEX_LENGTH = 64;\nexport const DEPLOY_TOKEN_TOTAL_LENGTH = DEPLOY_TOKEN_PREFIX.length + DEPLOY_TOKEN_HEX_LENGTH; // 70\n// Authentication Method Constants\nexport const AuthMethod = {\n JWT: 'jwt',\n API_KEY: 'apiKey',\n TOKEN: 'token',\n WEBHOOK: 'webhook',\n SYSTEM: 'system'\n};\n// Deployment Configuration\nexport const DEPLOYMENT_CONFIG_FILENAME = 'ship.json';\n// =============================================================================\n// VALIDATION UTILITIES\n// =============================================================================\n/**\n * Validate API key format\n */\nexport function validateApiKey(apiKey) {\n if (!apiKey.startsWith(API_KEY_PREFIX)) {\n throw ShipError.validation(`API key must start with \"${API_KEY_PREFIX}\"`);\n }\n if (apiKey.length !== API_KEY_TOTAL_LENGTH) {\n throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);\n }\n const hexPart = apiKey.slice(API_KEY_PREFIX.length);\n if (!/^[a-f0-9]{64}$/i.test(hexPart)) {\n throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after \"${API_KEY_PREFIX}\" prefix`);\n }\n}\n/**\n * Validate deploy token format\n */\nexport function validateDeployToken(deployToken) {\n if (!deployToken.startsWith(DEPLOY_TOKEN_PREFIX)) {\n throw ShipError.validation(`Deploy token must start with \"${DEPLOY_TOKEN_PREFIX}\"`);\n }\n if (deployToken.length !== DEPLOY_TOKEN_TOTAL_LENGTH) {\n throw ShipError.validation(`Deploy token must be ${DEPLOY_TOKEN_TOTAL_LENGTH} characters total (${DEPLOY_TOKEN_PREFIX} + ${DEPLOY_TOKEN_HEX_LENGTH} hex chars)`);\n }\n const hexPart = deployToken.slice(DEPLOY_TOKEN_PREFIX.length);\n if (!/^[a-f0-9]{64}$/i.test(hexPart)) {\n throw ShipError.validation(`Deploy token must contain ${DEPLOY_TOKEN_HEX_LENGTH} hexadecimal characters after \"${DEPLOY_TOKEN_PREFIX}\" prefix`);\n }\n}\n/**\n * Validate API URL format\n */\nexport function validateApiUrl(apiUrl) {\n try {\n const url = new URL(apiUrl);\n if (!['http:', 'https:'].includes(url.protocol)) {\n throw ShipError.validation('API URL must use http:// or https:// protocol');\n }\n if (url.pathname !== '/' && url.pathname !== '') {\n throw ShipError.validation('API URL must not contain a path');\n }\n if (url.search || url.hash) {\n throw ShipError.validation('API URL must not contain query parameters or fragments');\n }\n }\n catch (error) {\n if (isShipError(error)) {\n throw error;\n }\n throw ShipError.validation('API URL must be a valid URL');\n }\n}\n/**\n * Check if a string matches the deployment ID pattern (word-word-alphanumeric7)\n * Example: \"happy-cat-abc1234\"\n */\nexport function isDeployment(input) {\n return /^[a-z]+-[a-z]+-[a-z0-9]{7}$/i.test(input);\n}\n// =============================================================================\n// PLATFORM CONSTANTS\n// =============================================================================\n/** Default API URL if not otherwise configured. */\nexport const DEFAULT_API = 'https://api.shipstatic.com';\n// =============================================================================\n// FILE UPLOAD TYPES\n// =============================================================================\n/**\n * File status constants for validation state tracking\n */\nexport const FileValidationStatus = {\n PENDING: 'pending',\n PROCESSING_ERROR: 'processing_error',\n EMPTY_FILE: 'empty_file',\n VALIDATION_FAILED: 'validation_failed',\n READY: 'ready',\n};\n// =============================================================================\n// DOMAIN UTILITIES\n// =============================================================================\n/**\n * Check if a domain is a platform domain (subdomain of our platform).\n * Platform domains are free and don't require DNS verification.\n *\n * @example isPlatformDomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → true\n * @example isPlatformDomain(\"example.com\", \"shipstatic.dev\") → false\n */\nexport function isPlatformDomain(domain, platformDomain) {\n return domain.endsWith(`.${platformDomain}`);\n}\n/**\n * Check if a domain is a custom domain (not a platform subdomain).\n * Custom domains are billable and require DNS verification.\n *\n * @example isCustomDomain(\"example.com\", \"shipstatic.dev\") → true\n * @example isCustomDomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → false\n */\nexport function isCustomDomain(domain, platformDomain) {\n return !isPlatformDomain(domain, platformDomain);\n}\n/**\n * Extract subdomain from a platform domain.\n * Returns null if not a platform domain.\n *\n * @example extractSubdomain(\"www.shipstatic.dev\", \"shipstatic.dev\") → \"www\"\n * @example extractSubdomain(\"example.com\", \"shipstatic.dev\") → null\n */\nexport function extractSubdomain(domain, platformDomain) {\n if (!isPlatformDomain(domain, platformDomain)) {\n return null;\n }\n return domain.slice(0, -(platformDomain.length + 1)); // +1 for the dot\n}\n/**\n * Generate deployment URL from deployment ID and platform domain\n */\nexport function generateDeploymentUrl(deployment, platformDomain) {\n const domain = platformDomain || 'shipstatic.com';\n return `https://${deployment}.${domain}`;\n}\n/**\n * Generate URL for a domain.\n * Domains are stored as FQDNs, so this just prepends https://\n */\nexport function generateDomainUrl(domain) {\n return `https://${domain}`;\n}\n// =============================================================================\n// TAG UTILITIES\n// =============================================================================\n/**\n * Tag validation constraints shared across UI and API.\n * These rules define the single source of truth for tag validation.\n */\nexport const TAG_CONSTRAINTS = {\n /** Minimum tag length in characters */\n MIN_LENGTH: 3,\n /** Maximum tag length in characters (concise tags, matches Stack Overflow's original limit) */\n MAX_LENGTH: 25,\n /** Maximum number of tags allowed per resource */\n MAX_COUNT: 10,\n /** Allowed separator characters between tag segments */\n SEPARATORS: '._-',\n};\n/**\n * Tag validation pattern.\n * Must start and end with alphanumeric (a-z, 0-9).\n * Can contain separators (. _ -) between segments, but not consecutive.\n *\n * Valid examples: 'production', 'v1.2.3', 'api_v2', 'us-east-1'\n * Invalid examples: 'ab' (too short), '-prod' (starts with separator), 'foo--bar' (consecutive separators)\n */\nexport const TAG_PATTERN = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;\n/**\n * Serialize tags array to JSON string for database storage.\n * Returns null for empty or undefined arrays.\n *\n * @example serializeTags(['web', 'production']) → '[\"web\",\"production\"]'\n * @example serializeTags([]) → null\n * @example serializeTags(undefined) → null\n */\nexport function serializeTags(tags) {\n if (!tags || tags.length === 0)\n return null;\n return JSON.stringify(tags);\n}\n/**\n * Deserialize tags from JSON string to array.\n * Returns undefined for null/empty strings.\n *\n * @example deserializeTags('[\"web\",\"production\"]') → ['web', 'production']\n * @example deserializeTags(null) → undefined\n * @example deserializeTags('') → undefined\n */\nexport function deserializeTags(tagsJson) {\n if (!tagsJson)\n return undefined;\n try {\n const parsed = JSON.parse(tagsJson);\n return Array.isArray(parsed) && parsed.length > 0 ? parsed : undefined;\n }\n catch {\n return undefined;\n }\n}\n","/**\n * @file Platform configuration management for the Ship SDK.\n * Implements fail-fast dynamic configuration with mandatory API fetch.\n */\n\nimport type { ConfigResponse } from '@shipstatic/types';\nimport { ShipError } from '@shipstatic/types';\n\n// Dynamic config - must be fetched from API before operations\nlet _config: ConfigResponse | null = null;\n\n/**\n * Set the current config (called after fetching from API)\n */\nexport function setConfig(config: ConfigResponse): void {\n _config = config;\n}\n\n/**\n * Get current config - throws if not initialized (fail-fast approach)\n * @throws {ShipError.config} If configuration hasn't been fetched from API\n */\nexport function getCurrentConfig(): ConfigResponse {\n if (_config === null) {\n throw ShipError.config(\n 'Platform configuration not initialized. The SDK must fetch configuration from the API before performing operations.'\n );\n }\n return _config;\n}\n\n/**\n * Check if config has been initialized from API\n */\nexport function isConfigInitialized(): boolean {\n return _config !== null;\n}\n\n/**\n * Reset config state (primarily for testing)\n * @internal\n */\nexport function resetConfig(): void {\n _config = null;\n}","/**\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.js';\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 Manages loading and validation of client configuration.\n * This module uses `cosmiconfig` to find and load configuration from various\n * file sources (e.g., `.shiprc`, `package.json`) and environment variables.\n * Configuration values are validated using Zod schemas.\n */\n\nimport { z } from 'zod';\nimport type { ShipClientOptions, DeploymentOptions } from '../../shared/types.js';\nimport { ShipError, isShipError } from '@shipstatic/types';\nimport { getENV } from '../../shared/lib/env.js';\nimport { DEFAULT_API } from '../../shared/core/constants.js';\n\n\n\n/** @internal Name of the module, used by cosmiconfig for config file searching. */\nconst MODULE_NAME = 'ship';\n\n/**\n * Zod schema for validating ship configuration.\n * @internal\n */\nconst ConfigSchema = z.object({\n apiUrl: z.string().url().optional(),\n apiKey: z.string().optional(),\n deployToken: z.string().optional()\n}).strict();\n\n/**\n * Validates configuration using Zod schema.\n * @param config - Configuration object to validate\n * @returns Validated configuration or throws error\n * @internal\n */\nfunction validateConfig(config: unknown): Partial<ShipClientOptions> {\n try {\n return ConfigSchema.parse(config);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const firstError = error.issues[0];\n const path = firstError.path.length > 0 ? ` at ${firstError.path.join('.')}` : '';\n throw ShipError.config(`Configuration validation failed${path}: ${firstError.message}`);\n }\n throw ShipError.config('Configuration validation failed');\n }\n}\n\n/**\n * Loads client configuration from files.\n * Searches for .shiprc and package.json with ship key.\n * First searches from the current directory, then from the home directory.\n * @param configFile - Optional specific config file path to load\n * @returns Configuration object or empty if not found/invalid\n * @internal\n */\nasync function loadConfigFromFile(configFile?: string): Promise<Partial<ShipClientOptions>> {\n try {\n // Only use cosmiconfig in Node.js environments\n if (getENV() !== 'node') {\n return {};\n }\n \n // Dynamically import cosmiconfig and os only in Node.js environments\n const { cosmiconfigSync } = await import('cosmiconfig');\n const os = await import('os');\n \n const explorer = cosmiconfigSync(MODULE_NAME, {\n searchPlaces: [\n `.${MODULE_NAME}rc`,\n 'package.json',\n `${os.homedir()}/.${MODULE_NAME}rc`, // Always include home directory as fallback\n ],\n stopDir: os.homedir(), // Stop searching at home directory\n });\n \n let result;\n \n // If a specific config file is provided, load it directly\n if (configFile) {\n result = explorer.load(configFile);\n } else {\n // cosmiconfig automatically searches up the directory tree\n // from current directory to stopDir (home directory)\n result = explorer.search();\n }\n \n if (result && result.config) {\n return validateConfig(result.config);\n }\n } catch (error) {\n if (isShipError(error)) throw error; // Re-throw all ShipError instances\n // Silently fail for file loading issues - this is optional config\n }\n return {};\n}\n\n/**\n * Simplified configuration loading prioritizing environment variables.\n * Only loads file config if environment variables are not set.\n * Only available in Node.js environments.\n *\n * @param configFile - Optional specific config file path to load\n * @returns Configuration object with loaded values\n * @throws {ShipInvalidConfigError} If the configuration is invalid.\n */\nexport async function loadConfig(configFile?: string): Promise<Partial<ShipClientOptions>> {\n if (getENV() !== 'node') return {};\n\n // Start with environment variables (highest priority)\n const envConfig = {\n apiUrl: process.env.SHIP_API_URL,\n apiKey: process.env.SHIP_API_KEY,\n deployToken: process.env.SHIP_DEPLOY_TOKEN,\n };\n\n // Always try to load file config for fallback values\n const fileConfig = await loadConfigFromFile(configFile);\n\n // Merge with environment variables taking precedence\n const mergedConfig = {\n apiUrl: envConfig.apiUrl ?? fileConfig.apiUrl,\n apiKey: envConfig.apiKey ?? fileConfig.apiKey,\n deployToken: envConfig.deployToken ?? fileConfig.deployToken,\n };\n\n // Validate final config\n return validateConfig(mergedConfig);\n}\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 *\n * @example\n * ```typescript\n * import { filterJunk } from '@shipstatic/ship';\n *\n * // Filter an array of file paths\n * const paths = ['index.html', '.DS_Store', '__MACOSX/file.txt', 'app.js'];\n * const clean = filterJunk(paths);\n * // Result: ['index.html', 'app.js']\n * ```\n *\n * @example\n * ```typescript\n * // Use with browser File objects\n * import { filterJunk } from '@shipstatic/ship';\n *\n * const files: File[] = [...]; // From input or drag-drop\n *\n * // Extract paths from File objects\n * const filePaths = files.map(f => f.webkitRelativePath || f.name);\n *\n * // Filter out junk paths\n * const validPaths = new Set(filterJunk(filePaths));\n *\n * // Filter the original File array\n * const validFiles = files.filter(f =>\n * validPaths.has(f.webkitRelativePath || f.name)\n * );\n * ```\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","/**\n * @file Path helper utilities that work in both browser and Node.js environments.\n * Provides environment-agnostic path manipulation functions.\n */\n\n/**\n * Finds the common parent directory from an array of directory paths.\n * Simple, unified implementation for flattenDirs functionality.\n * \n * @param dirPaths - Array of directory paths (not file paths - directories containing the files)\n * @returns The common parent directory path, or empty string if none found\n */\nexport function findCommonParent(dirPaths: string[]): string {\n if (!dirPaths || dirPaths.length === 0) return '';\n \n const normalizedPaths = dirPaths\n .filter(p => p && typeof p === 'string')\n .map(p => p.replace(/\\\\/g, '/'));\n \n if (normalizedPaths.length === 0) return '';\n if (normalizedPaths.length === 1) return normalizedPaths[0];\n\n const pathSegments = normalizedPaths.map(p => p.split('/').filter(Boolean));\n const commonSegments = [];\n const minLength = Math.min(...pathSegments.map(p => p.length));\n \n for (let i = 0; i < minLength; i++) {\n const segment = pathSegments[0][i];\n if (pathSegments.every(segments => segments[i] === segment)) {\n commonSegments.push(segment);\n } else {\n break;\n }\n }\n \n return commonSegments.join('/');\n}\n\n\n\n/**\n * Converts backslashes to forward slashes for cross-platform compatibility.\n * Does not remove leading slashes (preserves absolute paths).\n * @param path - The path to normalize\n * @returns Path with forward slashes\n */\nexport function normalizeSlashes(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\n/**\n * Normalizes a path for web usage by converting backslashes to forward slashes\n * and removing leading slashes.\n * @param path - The path to normalize\n * @returns Normalized path suitable for web deployment\n */\nexport function normalizeWebPath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\/+/, '');\n}\n\n","/**\n * @file Deploy path optimization - the core logic that makes Ship deployments clean and intuitive.\n * Automatically strips common parent directories to create clean deployment URLs.\n */\n\nimport { normalizeWebPath } from './path.js';\n\n/**\n * Represents a file ready for deployment with its optimized path\n */\nexport interface DeployFile {\n /** The clean deployment path (e.g., \"assets/style.css\") */\n path: string;\n /** Original filename */\n name: string;\n}\n\n/**\n * Core path optimization logic.\n * Transforms messy local paths into clean deployment paths.\n * \n * @example\n * Input: [\"dist/index.html\", \"dist/assets/app.js\"]\n * Output: [\"index.html\", \"assets/app.js\"]\n * \n * @param filePaths - Raw file paths from the local filesystem\n * @param options - Path processing options\n */\nexport function optimizeDeployPaths(\n filePaths: string[], \n options: { flatten?: boolean } = {}\n): DeployFile[] {\n // When flattening is disabled, keep original structure\n if (options.flatten === false) {\n return filePaths.map(path => ({\n path: normalizeWebPath(path),\n name: extractFileName(path)\n }));\n }\n\n // Find the common directory prefix to strip\n const commonPrefix = findCommonDirectory(filePaths);\n \n return filePaths.map(filePath => {\n let deployPath = normalizeWebPath(filePath);\n \n // Strip the common prefix to create clean deployment paths\n if (commonPrefix) {\n const prefixToRemove = commonPrefix.endsWith('/') ? commonPrefix : `${commonPrefix}/`;\n if (deployPath.startsWith(prefixToRemove)) {\n deployPath = deployPath.substring(prefixToRemove.length);\n }\n }\n \n // Fallback to filename if path becomes empty\n if (!deployPath) {\n deployPath = extractFileName(filePath);\n }\n \n return {\n path: deployPath,\n name: extractFileName(filePath)\n };\n });\n}\n\n/**\n * Finds the common directory shared by all file paths.\n * This is what gets stripped to create clean deployment URLs.\n * \n * @example\n * [\"dist/index.html\", \"dist/assets/app.js\"] → \"dist\"\n * [\"src/components/A.tsx\", \"src/utils/B.ts\"] → \"src\"\n * [\"file1.txt\", \"file2.txt\", \"subdir/file3.txt\"] → \"\" (no common directory)\n */\nfunction findCommonDirectory(filePaths: string[]): string {\n if (!filePaths.length) return '';\n \n // Normalize all paths first\n const normalizedPaths = filePaths.map(path => normalizeWebPath(path));\n \n // Find the common prefix among all file paths (not just directories)\n const pathSegments = normalizedPaths.map(path => path.split('/'));\n const commonSegments: string[] = [];\n const minLength = Math.min(...pathSegments.map(segments => segments.length));\n \n // Check each segment level to find the longest common prefix\n for (let i = 0; i < minLength - 1; i++) { // -1 because we don't want to include the filename\n const segment = pathSegments[0][i];\n if (pathSegments.every(segments => segments[i] === segment)) {\n commonSegments.push(segment);\n } else {\n break;\n }\n }\n \n return commonSegments.join('/');\n}\n\n/**\n * Extracts just the filename from a file path\n */\nfunction extractFileName(path: string): string {\n return path.split(/[/\\\\]/).pop() || path;\n}","/**\n * @file Node.js-specific file utilities for the Ship SDK.\n * Provides helpers for recursively discovering, filtering, and preparing files for deploy in Node.js.\n */\nimport { getENV } from '../../shared/lib/env.js';\nimport type { StaticFile, DeploymentOptions } from '../../shared/types.js';\nimport { calculateMD5 } from '../../shared/lib/md5.js';\nimport { filterJunk } from '../../shared/lib/junk.js';\nimport { ShipError, isShipError } from '@shipstatic/types';\nimport { getCurrentConfig } from '../../shared/core/platform-config.js';\nimport { optimizeDeployPaths } from '../../shared/lib/deploy-paths.js';\nimport { findCommonParent } from '../../shared/lib/path.js';\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n\n/**\n * Recursive function to walk directory and return all file paths.\n * Includes symlink loop protection to prevent infinite recursion.\n * @param dirPath - Directory path to traverse\n * @param visited - Set of already visited real paths (for cycle detection)\n * @returns Array of absolute file paths in the directory\n */\nfunction findAllFilePaths(dirPath: string, visited: Set<string> = new Set()): string[] {\n const results: string[] = [];\n\n // Resolve the real path to detect symlink cycles\n const realPath = fs.realpathSync(dirPath);\n if (visited.has(realPath)) {\n // Already visited this directory (symlink cycle) - skip to prevent infinite loop\n return results;\n }\n visited.add(realPath);\n\n const entries = fs.readdirSync(dirPath);\n\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry);\n const stats = fs.statSync(fullPath);\n\n if (stats.isDirectory()) {\n const subFiles = findAllFilePaths(fullPath, visited);\n results.push(...subFiles);\n } else if (stats.isFile()) {\n results.push(fullPath);\n }\n }\n\n return results;\n}\n\n/**\n * Processes Node.js file and directory paths into an array of StaticFile objects ready for deploy.\n * Uses corrected logic to properly handle common parent directory stripping.\n * \n * @param paths - File or directory paths to scan and process.\n * @param options - Processing options (pathDetect, etc.).\n * @returns Promise resolving to an array of StaticFile objects.\n * @throws {ShipClientError} If called outside Node.js or if fs/path modules fail.\n */\nexport async function processFilesForNode(\n paths: string[],\n options: DeploymentOptions = {}\n): Promise<StaticFile[]> {\n if (getENV() !== 'node') {\n throw ShipError.business('processFilesForNode can only be called in Node.js environment.');\n }\n\n // 1. Discover all unique, absolute file paths from the input list\n const absolutePaths = paths.flatMap(p => {\n const absPath = path.resolve(p);\n try {\n const stats = fs.statSync(absPath);\n return stats.isDirectory() ? findAllFilePaths(absPath) : [absPath];\n } catch (error) {\n throw ShipError.file(`Path does not exist: ${p}`, p);\n }\n });\n const uniquePaths = [...new Set(absolutePaths)];\n \n // 2. Filter out junk files from the final list\n const validPaths = filterJunk(uniquePaths);\n if (validPaths.length === 0) {\n return [];\n }\n\n // 3. Determine the base path for calculating relative paths\n // Find the common parent of the INPUT paths (not the discovered file paths)\n const inputAbsolutePaths = paths.map(p => path.resolve(p));\n const inputBasePath = findCommonParent(inputAbsolutePaths.map(p => {\n try {\n const stats = fs.statSync(p);\n return stats.isDirectory() ? p : path.dirname(p);\n } catch {\n return path.dirname(p);\n }\n }));\n\n // 4. Create raw relative paths for optimization\n const relativePaths = validPaths.map(filePath => {\n // If we have a meaningful common base path from inputs, use it\n if (inputBasePath && inputBasePath.length > 0) {\n const rel = path.relative(inputBasePath, filePath);\n if (rel && typeof rel === 'string' && !rel.startsWith('..')) {\n return rel.replace(/\\\\/g, '/');\n }\n }\n \n // Fallback: if no good common parent or relative path goes up, just use basename\n return path.basename(filePath);\n });\n\n // 5. Optimize paths for deployment (flattening)\n const deployFiles = optimizeDeployPaths(relativePaths, {\n flatten: options.pathDetect !== false\n });\n\n // 6. Process files into StaticFile objects\n const results: StaticFile[] = [];\n let totalSize = 0;\n const platformLimits = getCurrentConfig();\n\n for (let i = 0; i < validPaths.length; i++) {\n const filePath = validPaths[i];\n const deployPath = deployFiles[i].path;\n \n try {\n const stats = fs.statSync(filePath);\n if (stats.size === 0) {\n continue;\n }\n\n // Validate file sizes\n if (stats.size > platformLimits.maxFileSize) {\n throw ShipError.business(`File ${filePath} is too large. Maximum allowed size is ${platformLimits.maxFileSize / (1024 * 1024)}MB.`);\n }\n totalSize += stats.size;\n if (totalSize > platformLimits.maxTotalSize) {\n throw ShipError.business(`Total deploy size is too large. Maximum allowed is ${platformLimits.maxTotalSize / (1024 * 1024)}MB.`);\n }\n\n const content = fs.readFileSync(filePath);\n const { md5 } = await calculateMD5(content);\n \n // Security validation: Ensure no dangerous characters in paths\n if (deployPath.includes('\\0') || deployPath.includes('/../') || deployPath.startsWith('../') || deployPath.endsWith('/..')) {\n throw ShipError.business(`Security error: Unsafe file path \"${deployPath}\" for file: ${filePath}`);\n }\n \n results.push({\n path: deployPath,\n content,\n size: content.length,\n md5,\n });\n } catch (error) {\n // Re-throw ShipError instances directly\n if (isShipError(error)) {\n throw error;\n }\n // Convert file system errors to ShipError with clear message\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw ShipError.file(`Failed to read file \"${filePath}\": ${errorMessage}`, filePath);\n }\n }\n\n // Final validation\n if (results.length > platformLimits.maxFilesCount) {\n throw ShipError.business(`Too many files to deploy. Maximum allowed is ${platformLimits.maxFilesCount} files.`);\n }\n \n return results;\n}","/**\n * @file Main entry point for the Ship CLI.\n */\nimport { Command } from 'commander';\nimport { Ship } from '../index.js';\nimport { ShipError, validateApiKey, validateDeployToken, validateApiUrl, isShipError, type Deployment } from '@shipstatic/types';\nimport { readFileSync, existsSync, statSync } from 'fs';\nimport * as path from 'path';\nimport { success, error } from './utils.js';\nimport { formatOutput } from './formatters.js';\nimport { installCompletion, uninstallCompletion } from './completion.js';\nimport { getUserMessage, toShipError, formatErrorJson, type ErrorContext } from './error-handling.js';\nimport { bold, dim } from 'yoctocolors';\nimport type { GlobalOptions, DeployCommandOptions, TagOptions, TokenCreateCommandOptions, ProcessedOptions, CLIResult } from './types.js';\n\n// Load package.json for version\nfunction loadPackageJson(): { version: string } {\n const paths = [\n path.resolve(__dirname, '../package.json'),\n path.resolve(__dirname, '../../package.json')\n ];\n for (const p of paths) {\n try {\n return JSON.parse(readFileSync(p, 'utf-8'));\n } catch {}\n }\n return { version: '0.0.0' };\n}\n\nconst packageJson = loadPackageJson();\n\n\n\nconst program = new Command();\n\n// Override Commander.js error handling while preserving help/version behavior\nprogram\n .exitOverride((err) => {\n // Only override actual errors, not help/version exits\n if (err.code === 'commander.help' || err.code === 'commander.version' || err.exitCode === 0) {\n process.exit(err.exitCode || 0);\n }\n \n const globalOptions = program.opts();\n\n let message = err.message || 'unknown command error';\n message = message\n .replace(/^error: /, '')\n .replace(/\\n.*/, '')\n .replace(/\\.$/, '')\n .toLowerCase();\n\n error(message, globalOptions.json, globalOptions.noColor);\n\n if (!globalOptions.json) {\n displayHelp(globalOptions.noColor);\n }\n \n process.exit(err.exitCode || 1);\n })\n .configureOutput({\n writeErr: (str) => {\n if (!str.startsWith('error:')) {\n process.stderr.write(str);\n }\n },\n writeOut: (str) => process.stdout.write(str)\n });\n\n\n/**\n * Display comprehensive help information for all commands\n */\nfunction displayHelp(noColor?: boolean) {\n const applyBold = (text: string) => noColor ? text : bold(text);\n const applyDim = (text: string) => noColor ? text : dim(text);\n \n const output = `${applyBold('USAGE')}\n ship <path> 🚀 Deploy static sites with simplicity\n\n${applyBold('COMMANDS')}\n 📦 ${applyBold('Deployments')}\n ship deployments list List all deployments\n ship deployments create <path> Create deployment from directory\n ship deployments get <id> Show deployment information\n ship deployments set <id> Set deployment tags\n ship deployments remove <id> Delete deployment permanently\n\n 🌎 ${applyBold('Domains')}\n ship domains list List all domains\n ship domains set <name> [deployment] Point domain to deployment, or update tags\n ship domains get <name> Show domain information\n ship domains validate <name> Check if domain name is valid and available\n ship domains verify <name> Trigger DNS verification for external domain\n ship domains remove <name> Delete domain permanently\n\n 🔑 ${applyBold('Tokens')}\n ship tokens list List all deploy tokens\n ship tokens create Create a new deploy token\n ship tokens remove <token> Delete token permanently\n\n 🦸 ${applyBold('Account')}\n ship whoami Get current account information\n\n 🛠️ ${applyBold('Completion')}\n ship completion install Install shell completion script\n ship completion uninstall Uninstall shell completion script\n\n${applyBold('FLAGS')}\n --api-key <key> API key for authenticated deployments\n --deploy-token <token> Deploy token for single-use deployments\n --config <file> Custom config file path\n --no-path-detect Disable automatic path optimization and flattening\n --no-spa-detect Disable automatic SPA detection and configuration\n --no-color Disable colored output\n --json Output results in JSON format\n --version Show version information\n\n${applyDim('Please report any issues to https://github.com/shipstatic/ship/issues')}\n`;\n\n console.log(output);\n}\n\n/**\n * Collector function for Commander.js to accumulate repeated option values.\n * Used for --tag flag that can be specified multiple times.\n */\nfunction collect(value: string, previous: string[] = []): string[] {\n return previous.concat([value]);\n}\n\n/**\n * Merge tag options from command and program levels.\n * Commander.js sometimes routes --tag to program level instead of command level.\n */\nfunction mergeTagOption(cmdOptions: TagOptions | undefined, programOpts: TagOptions | undefined): string[] | undefined {\n const tags = cmdOptions?.tag?.length ? cmdOptions.tag : programOpts?.tag;\n return tags?.length ? tags : undefined;\n}\n\n/**\n * Handle unknown subcommand for parent commands.\n * Shows error for unknown subcommand, then displays help.\n */\nfunction handleUnknownSubcommand(validSubcommands: string[]): (...args: unknown[]) => void {\n return (...args: unknown[]) => {\n const globalOptions = processOptions(program);\n\n // Get the command object (last argument) - Commander passes it as the final arg\n const commandObj = args[args.length - 1] as { args?: string[] } | undefined;\n\n // Check if an unknown subcommand was provided\n if (commandObj?.args?.length) {\n const unknownArg = commandObj.args.find((arg) => !validSubcommands.includes(arg));\n if (unknownArg) {\n error(`unknown command '${unknownArg}'`, globalOptions.json, globalOptions.noColor);\n }\n }\n\n displayHelp(globalOptions.noColor);\n process.exit(1);\n };\n}\n\n/**\n * Process CLI options using Commander's built-in option merging.\n * Applies CLI-specific transformations (validation is done in preAction hook).\n */\nfunction processOptions(command: Command): ProcessedOptions {\n // Use Commander's built-in option merging\n // optsWithGlobals() gets both command-level and global options\n const options = command.optsWithGlobals ? command.optsWithGlobals() : command.opts();\n\n // Convert Commander.js --no-color flag (color: false) to our convention (noColor: true)\n if (options.color === false) {\n options.noColor = true;\n }\n\n // Note: Validation is handled by the preAction hook to avoid duplication\n return options as ProcessedOptions;\n}\n\n/**\n * Error handler - outputs errors consistently in text or JSON format.\n * Message formatting is delegated to the error-handling module.\n */\nfunction handleError(\n err: unknown,\n context?: ErrorContext\n) {\n const opts = program.opts() as GlobalOptions;\n const shipError = toShipError(err);\n\n // Get user-facing message using the extracted pure function\n const message = getUserMessage(shipError, context, {\n apiKey: opts.apiKey,\n deployToken: opts.deployToken\n });\n\n // Output in appropriate format\n if (opts.json) {\n console.error(formatErrorJson(message, shipError.details) + '\\n');\n } else {\n error(message, opts.json, opts.noColor);\n // Show help only for unknown command errors (user CLI mistake)\n if (shipError.isValidationError() && message.includes('unknown command')) {\n displayHelp(opts.noColor);\n }\n }\n\n process.exit(1);\n}\n\n/**\n * Wrapper for CLI actions that handles errors and client creation consistently.\n * Reduces boilerplate while preserving context for error handling.\n */\nfunction withErrorHandling<T extends unknown[], R extends CLIResult>(\n handler: (client: Ship, ...args: T) => Promise<R>,\n context?: { operation?: string; resourceType?: string; getResourceId?: (...args: T) => string }\n) {\n return async function(this: Command, ...args: T) {\n // Process options once at the start (used by both success and error paths)\n const globalOptions = processOptions(this);\n\n try {\n const client = createClient();\n const result = await handler(client, ...args);\n\n // Build context for output if provided\n const outputContext = context ? {\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.getResourceId ? context.getResourceId(...args) : undefined\n } : {};\n\n output(result, outputContext, globalOptions);\n } catch (err) {\n const errorContext = context ? {\n operation: context.operation,\n resourceType: context.resourceType,\n resourceId: context.getResourceId ? context.getResourceId(...args) : undefined\n } : undefined;\n\n handleError(err, errorContext);\n }\n };\n}\n\n/**\n * Create Ship client from CLI options\n */\nfunction createClient(): Ship {\n const { config, apiUrl, apiKey, deployToken } = program.opts();\n return new Ship({ configFile: config, apiUrl, apiKey, deployToken });\n}\n\n/** Spinner instance type from yocto-spinner */\ninterface Spinner {\n start(): Spinner;\n stop(): void;\n}\n\n/**\n * Common deploy logic used by both shortcut and explicit commands.\n */\nasync function performDeploy(\n client: Ship,\n deployPath: string,\n cmdOptions: DeployCommandOptions | undefined,\n commandContext?: Command\n): Promise<Deployment> {\n if (!existsSync(deployPath)) {\n throw ShipError.file(`${deployPath} path does not exist`, deployPath);\n }\n\n const stats = statSync(deployPath);\n if (!stats.isDirectory() && !stats.isFile()) {\n throw ShipError.file(`${deployPath} path must be a file or directory`, deployPath);\n }\n\n const deployOptions: {\n via: string;\n tags?: string[];\n pathDetect?: boolean;\n spaDetect?: boolean;\n signal?: AbortSignal;\n } = { via: 'cli' };\n\n // Handle tags\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n if (tags) deployOptions.tags = tags;\n\n // Handle detection flags\n if (cmdOptions?.noPathDetect !== undefined) {\n deployOptions.pathDetect = !cmdOptions.noPathDetect;\n }\n if (cmdOptions?.noSpaDetect !== undefined) {\n deployOptions.spaDetect = !cmdOptions.noSpaDetect;\n }\n\n // Cancellation support\n const abortController = new AbortController();\n deployOptions.signal = abortController.signal;\n\n // Spinner (TTY only, not JSON, not --no-color)\n let spinner: Spinner | null = null;\n const globalOptions = commandContext ? processOptions(commandContext) : {} as ProcessedOptions;\n if (process.stdout.isTTY && !globalOptions.json && !globalOptions.noColor) {\n const { default: yoctoSpinner } = await import('yocto-spinner');\n spinner = yoctoSpinner({ text: 'uploading…' }).start();\n }\n\n const sigintHandler = () => {\n abortController.abort();\n if (spinner) spinner.stop();\n process.exit(130);\n };\n process.on('SIGINT', sigintHandler);\n\n try {\n const result = await client.deployments.create(deployPath, deployOptions);\n process.removeListener('SIGINT', sigintHandler);\n if (spinner) spinner.stop();\n return result;\n } catch (err) {\n process.removeListener('SIGINT', sigintHandler);\n if (spinner) spinner.stop();\n throw err;\n }\n}\n\n/**\n * Output result using formatters module.\n */\nfunction output(result: CLIResult, context: { operation?: string; resourceType?: string; resourceId?: string }, options?: ProcessedOptions) {\n const opts = options || (program.opts() as ProcessedOptions);\n formatOutput(result, context, { isJson: opts.json, noColor: opts.noColor });\n}\n\n\n\nprogram\n .name('ship')\n .description('🚀 Deploy static sites with simplicity')\n .version(packageJson.version, '--version', 'Show version information')\n .option('--api-key <key>', 'API key for authenticated deployments')\n .option('--deploy-token <token>', 'Deploy token for single-use deployments')\n .option('--config <file>', 'Custom config file path')\n .option('--api-url <url>', 'API URL (for development)')\n .option('--json', 'Output results in JSON format')\n .option('--no-color', 'Disable colored output')\n .option('--help', 'Display help for command')\n .helpOption(false); // Disable default help\n\n// Handle --help flag manually to show custom help\nprogram.hook('preAction', (thisCommand, actionCommand) => {\n const options = thisCommand.opts();\n if (options.help) {\n const noColor = options.color === false || options.noColor;\n displayHelp(noColor);\n process.exit(0);\n }\n});\n\n// Validate options early - before any action is executed\nprogram.hook('preAction', (thisCommand, actionCommand) => {\n const options = thisCommand.opts();\n \n try {\n if (options.apiKey && typeof options.apiKey === 'string') {\n validateApiKey(options.apiKey);\n }\n \n if (options.deployToken && typeof options.deployToken === 'string') {\n validateDeployToken(options.deployToken);\n }\n \n if (options.apiUrl && typeof options.apiUrl === 'string') {\n validateApiUrl(options.apiUrl);\n }\n } catch (validationError) {\n if (isShipError(validationError)) {\n const noColor = options.color === false || options.noColor;\n error(validationError.message, options.json, noColor);\n process.exit(1);\n }\n throw validationError;\n }\n});\n\n// Ping command\nprogram\n .command('ping')\n .description('Check API connectivity')\n .action(withErrorHandling((client: Ship) => client.ping()));\n\n// Whoami shortcut - alias for account get\nprogram\n .command('whoami')\n .description('Get current account information')\n .action(withErrorHandling(\n (client: Ship) => client.whoami(),\n { operation: 'get', resourceType: 'Account' }\n ));\n\n// Deployments commands\nconst deploymentsCmd = program\n .command('deployments')\n .description('Manage deployments')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'create', 'get', 'set', 'remove']));\n\ndeploymentsCmd\n .command('list')\n .description('List all deployments')\n .action(withErrorHandling((client: Ship) => client.deployments.list()));\n\ndeploymentsCmd\n .command('create <path>')\n .description('Create deployment from file or directory')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to add (can be repeated)', collect, [])\n .option('--no-path-detect', 'Disable automatic path optimization and flattening')\n .option('--no-spa-detect', 'Disable automatic SPA detection and configuration')\n .action(withErrorHandling(\n function(this: Command, client: Ship, deployPath: string, cmdOptions: DeployCommandOptions) {\n return performDeploy(client, deployPath, cmdOptions, this);\n },\n { operation: 'create' }\n ));\n\ndeploymentsCmd\n .command('get <deployment>')\n .description('Show deployment information')\n .action(withErrorHandling(\n (client: Ship, deployment: string) => client.deployments.get(deployment),\n { operation: 'get', resourceType: 'Deployment', getResourceId: (id: string) => id }\n ));\n\ndeploymentsCmd\n .command('set <deployment>')\n .description('Set deployment tags')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n async (client: Ship, deployment: string, cmdOptions: TagOptions) => {\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions) || [];\n return client.deployments.set(deployment, { tags });\n },\n { operation: 'set', resourceType: 'Deployment', getResourceId: (deployment: string) => deployment }\n ));\n\ndeploymentsCmd\n .command('remove <deployment>')\n .description('Delete deployment permanently')\n .action(withErrorHandling(\n (client: Ship, deployment: string) => client.deployments.remove(deployment),\n { operation: 'remove', resourceType: 'Deployment', getResourceId: (deployment: string) => deployment }\n ));\n\n// Domains commands\nconst domainsCmd = program\n .command('domains')\n .description('Manage domains')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'get', 'set', 'validate', 'verify', 'remove']));\n\ndomainsCmd\n .command('list')\n .description('List all domains')\n .action(withErrorHandling((client: Ship) => client.domains.list()));\n\ndomainsCmd\n .command('get <name>')\n .description('Show domain information')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.get(name),\n { operation: 'get', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('validate <name>')\n .description('Check if domain name is valid and available')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.validate(name),\n { operation: 'validate', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('verify <name>')\n .description('Trigger DNS verification for external domain')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.verify(name),\n { operation: 'verify', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('set <name> [deployment]')\n .description('Point domain to deployment, or update tags')\n .passThroughOptions()\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n async (client: Ship, name: string, deployment: string | undefined, cmdOptions: TagOptions) => {\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n\n // Validate: must provide either deployment or tags\n if (!deployment && (!tags || tags.length === 0)) {\n throw ShipError.validation('Must provide deployment or --tag');\n }\n\n const options: { deployment?: string; tags?: string[] } = {};\n if (deployment) options.deployment = deployment;\n if (tags && tags.length > 0) options.tags = tags;\n\n const result = await client.domains.set(name, options);\n\n // Enrich with DNS info for new external domains (pure formatter will display it)\n if (result.isCreate && name.includes('.')) {\n try {\n const [records, share] = await Promise.all([\n client.domains.records(name),\n client.domains.share(name)\n ]);\n return {\n ...result,\n _dnsRecords: records.records,\n _shareHash: share.hash\n };\n } catch {\n // Graceful degradation - return without DNS info\n }\n }\n return result;\n },\n { operation: 'set', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\ndomainsCmd\n .command('remove <name>')\n .description('Delete domain permanently')\n .action(withErrorHandling(\n (client: Ship, name: string) => client.domains.remove(name),\n { operation: 'remove', resourceType: 'Domain', getResourceId: (name: string) => name }\n ));\n\n// Tokens commands\nconst tokensCmd = program\n .command('tokens')\n .description('Manage deploy tokens')\n .enablePositionalOptions()\n .action(handleUnknownSubcommand(['list', 'create', 'remove']));\n\ntokensCmd\n .command('list')\n .description('List all tokens')\n .action(withErrorHandling((client: Ship) => client.tokens.list()));\n\ntokensCmd\n .command('create')\n .description('Create a new deploy token')\n .option('--ttl <seconds>', 'Time to live in seconds (default: never expires)', parseInt)\n .option('--tag <tag>', 'Tag to set (can be repeated)', collect, [])\n .action(withErrorHandling(\n (client: Ship, cmdOptions: TokenCreateCommandOptions) => {\n const options: { ttl?: number; tags?: string[] } = {};\n if (cmdOptions?.ttl !== undefined) options.ttl = cmdOptions.ttl;\n const tags = mergeTagOption(cmdOptions, program.opts() as TagOptions);\n if (tags && tags.length > 0) options.tags = tags;\n return client.tokens.create(options);\n },\n { operation: 'create', resourceType: 'Token' }\n ));\n\ntokensCmd\n .command('remove <token>')\n .description('Delete token permanently')\n .action(withErrorHandling(\n (client: Ship, token: string) => client.tokens.remove(token),\n { operation: 'remove', resourceType: 'Token', getResourceId: (token: string) => token }\n ));\n\n// Account commands\nconst accountCmd = program\n .command('account')\n .description('Manage account')\n .action(handleUnknownSubcommand(['get']));\n\naccountCmd\n .command('get')\n .description('Show account information')\n .action(withErrorHandling(\n (client: Ship) => client.whoami(),\n { operation: 'get', resourceType: 'Account' }\n ));\n\n// Completion commands\nconst completionCmd = program\n .command('completion')\n .description('Setup shell completion')\n .action(handleUnknownSubcommand(['install', 'uninstall']));\n\ncompletionCmd\n .command('install')\n .description('Install shell completion script')\n .action(() => {\n const options = program.opts();\n const scriptDir = path.resolve(__dirname, 'completions');\n installCompletion(scriptDir, { isJson: options.json, noColor: options.noColor });\n });\n\ncompletionCmd\n .command('uninstall')\n .description('Uninstall shell completion script')\n .action(() => {\n const options = program.opts();\n uninstallCompletion({ isJson: options.json, noColor: options.noColor });\n });\n\n\n// Deploy shortcut as default action\nprogram\n .argument('[path]', 'Path to deploy')\n .option('--tag <tag>', 'Tag to add (can be repeated)', collect, [])\n .option('--no-path-detect', 'Disable automatic path optimization and flattening')\n .option('--no-spa-detect', 'Disable automatic SPA detection and configuration')\n .action(withErrorHandling(\n async function(this: Command, client: Ship, deployPath?: string, cmdOptions?: DeployCommandOptions) {\n if (!deployPath) {\n const globalOptions = program.opts() as GlobalOptions;\n // Convert Commander.js --no-color flag (color: false) to our convention (noColor: true)\n const noColor = globalOptions.color === false || globalOptions.noColor;\n displayHelp(noColor);\n process.exit(0);\n }\n\n // Check if the argument is a valid path by checking filesystem\n // This correctly handles paths like \"dist\", \"build\", \"public\" without slashes\n if (!existsSync(deployPath)) {\n // Path doesn't exist - could be unknown command or typo\n // Check if it looks like a command (no path separators, no extension)\n const looksLikeCommand = !deployPath.includes('/') && !deployPath.includes('\\\\') &&\n !deployPath.includes('.') && !deployPath.startsWith('~');\n if (looksLikeCommand) {\n throw ShipError.validation(`unknown command '${deployPath}'`);\n }\n // Otherwise let performDeploy handle the \"path does not exist\" error\n }\n\n return performDeploy(client, deployPath, cmdOptions, this);\n },\n { operation: 'create' }\n ));\n\n\n\n/**\n * Simple completion handler - no self-invocation, just static completions\n */\nfunction handleCompletion() {\n const args = process.argv;\n const isBash = args.includes('--compbash');\n const isZsh = args.includes('--compzsh');\n const isFish = args.includes('--compfish');\n\n if (!isBash && !isZsh && !isFish) return;\n\n const completions = ['ping', 'whoami', 'deployments', 'domains', 'account', 'completion'];\n console.log(completions.join(isFish ? '\\n' : ' '));\n process.exit(0);\n}\n\n// Handle completion requests (before any other processing)\nif (process.env.NODE_ENV !== 'test' && (process.argv.includes('--compbash') || process.argv.includes('--compzsh') || process.argv.includes('--compfish'))) {\n handleCompletion();\n}\n\n// Handle main CLI parsing\nif (process.env.NODE_ENV !== 'test') {\n try {\n program.parse(process.argv);\n } catch (err) {\n // Commander.js errors are already handled by exitOverride above\n // This catch is for safety - check if it's a Commander error\n if (err instanceof Error && 'code' in err) {\n const code = (err as Error & { code?: string }).code;\n const exitCode = (err as Error & { exitCode?: number }).exitCode;\n if (code?.startsWith('commander.')) {\n process.exit(exitCode || 1);\n }\n }\n throw err;\n }\n}","/**\n * @file HTTP client for Ship API.\n */\nimport type {\n Deployment,\n DeploymentListResponse,\n PingResponse,\n ConfigResponse,\n DeploymentRemoveResponse,\n Domain,\n DomainListResponse,\n DomainDnsResponse,\n DomainRecordsResponse,\n DomainValidateResponse,\n Account,\n SPACheckRequest,\n SPACheckResponse,\n StaticFile,\n TokenCreateResponse,\n TokenListResponse\n} from '@shipstatic/types';\nimport type { ApiDeployOptions, ShipClientOptions, ShipEvents, DeployBodyCreator } from '../types.js';\nimport { ShipError, isShipError, DEFAULT_API } from '@shipstatic/types';\nimport { SimpleEvents } from '../events.js';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst ENDPOINTS = {\n DEPLOYMENTS: '/deployments',\n DOMAINS: '/domains',\n TOKENS: '/tokens',\n ACCOUNT: '/account',\n CONFIG: '/config',\n PING: '/ping',\n SPA_CHECK: '/spa-check'\n} as const;\n\nconst DEFAULT_REQUEST_TIMEOUT = 30000;\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface ApiHttpOptions extends ShipClientOptions {\n getAuthHeaders: () => Record<string, string>;\n createDeployBody: DeployBodyCreator;\n}\n\ninterface RequestResult<T> {\n data: T;\n status: number;\n}\n\n/** Shape of error response from API */\ninterface ApiErrorData {\n message?: string;\n error?: string;\n}\n\n// =============================================================================\n// HTTP CLIENT\n// =============================================================================\n\nexport class ApiHttp extends SimpleEvents {\n private readonly apiUrl: string;\n private readonly getAuthHeadersCallback: () => Record<string, string>;\n private readonly timeout: number;\n private readonly createDeployBody: DeployBodyCreator;\n\n constructor(options: ApiHttpOptions) {\n super();\n this.apiUrl = options.apiUrl || DEFAULT_API;\n this.getAuthHeadersCallback = options.getAuthHeaders;\n this.timeout = options.timeout ?? DEFAULT_REQUEST_TIMEOUT;\n this.createDeployBody = options.createDeployBody;\n }\n\n /**\n * Transfer events to another client\n */\n transferEventsTo(target: ApiHttp): void {\n this.transfer(target);\n }\n\n // ===========================================================================\n // CORE REQUEST INFRASTRUCTURE\n // ===========================================================================\n\n /**\n * Execute HTTP request with timeout, events, and error handling\n */\n private async executeRequest<T>(\n url: string,\n options: RequestInit,\n operationName: string\n ): Promise<RequestResult<T>> {\n const headers = this.mergeHeaders(options.headers as Record<string, string>);\n const { signal, cleanup } = this.createTimeoutSignal(options.signal);\n\n const fetchOptions: RequestInit = {\n ...options,\n headers,\n credentials: !headers.Authorization ? 'include' : undefined,\n signal,\n };\n\n this.emit('request', url, fetchOptions);\n\n try {\n const response = await fetch(url, fetchOptions);\n cleanup();\n\n if (!response.ok) {\n await this.handleResponseError(response, operationName);\n }\n\n this.emit('response', this.safeClone(response), url);\n const data = await this.parseResponse<T>(this.safeClone(response));\n return { data, status: response.status };\n } catch (error) {\n cleanup();\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err, url);\n this.handleFetchError(error, operationName);\n }\n }\n\n /**\n * Simple request - returns data only\n */\n private async request<T>(url: string, options: RequestInit, operationName: string): Promise<T> {\n const { data } = await this.executeRequest<T>(url, options, operationName);\n return data;\n }\n\n /**\n * Request with status - returns data and HTTP status code\n */\n private async requestWithStatus<T>(url: string, options: RequestInit, operationName: string): Promise<RequestResult<T>> {\n return this.executeRequest<T>(url, options, operationName);\n }\n\n // ===========================================================================\n // REQUEST HELPERS\n // ===========================================================================\n\n private mergeHeaders(customHeaders: Record<string, string> = {}): Record<string, string> {\n return { ...customHeaders, ...this.getAuthHeadersCallback() };\n }\n\n private createTimeoutSignal(existingSignal?: AbortSignal | null): { signal: AbortSignal; cleanup: () => void } {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n if (existingSignal) {\n const abort = () => controller.abort();\n existingSignal.addEventListener('abort', abort);\n if (existingSignal.aborted) controller.abort();\n }\n\n return {\n signal: controller.signal,\n cleanup: () => clearTimeout(timeoutId)\n };\n }\n\n private safeClone(response: Response): Response {\n try {\n return response.clone();\n } catch {\n return response;\n }\n }\n\n private async parseResponse<T>(response: Response): Promise<T> {\n if (response.headers.get('Content-Length') === '0' || response.status === 204) {\n return undefined as T;\n }\n return response.json() as Promise<T>;\n }\n\n // ===========================================================================\n // ERROR HANDLING\n // ===========================================================================\n\n private async handleResponseError(response: Response, operationName: string): Promise<never> {\n let errorData: ApiErrorData = {};\n try {\n const contentType = response.headers.get('content-type');\n if (contentType?.includes('application/json')) {\n const json: unknown = await response.json();\n // Safely extract known fields from response\n if (json && typeof json === 'object') {\n const obj = json as Record<string, unknown>;\n if (typeof obj.message === 'string') errorData.message = obj.message;\n if (typeof obj.error === 'string') errorData.error = obj.error;\n }\n } else {\n errorData = { message: await response.text() };\n }\n } catch {\n errorData = { message: 'Failed to parse error response' };\n }\n\n const message = errorData.message || errorData.error || `${operationName} failed`;\n\n if (response.status === 401) {\n throw ShipError.authentication(message);\n }\n throw ShipError.api(message, response.status);\n }\n\n private handleFetchError(error: unknown, operationName: string): never {\n // Re-throw ShipErrors as-is\n if (isShipError(error)) {\n throw error;\n }\n // Handle abort errors\n if (error instanceof Error && error.name === 'AbortError') {\n throw ShipError.cancelled(`${operationName} was cancelled`);\n }\n // Handle network errors (fetch failures)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n throw ShipError.network(`${operationName} failed: ${error.message}`, error);\n }\n // Handle other Error instances\n if (error instanceof Error) {\n throw ShipError.business(`${operationName} failed: ${error.message}`);\n }\n // Handle non-Error throws\n throw ShipError.business(`${operationName} failed: Unknown error`);\n }\n\n // ===========================================================================\n // PUBLIC API - DEPLOYMENTS\n // ===========================================================================\n\n async deploy(files: StaticFile[], options: ApiDeployOptions = {}): Promise<Deployment> {\n if (!files.length) {\n throw ShipError.business('No files to deploy');\n }\n for (const file of files) {\n if (!file.md5) {\n throw ShipError.file(`MD5 checksum missing for file: ${file.path}`, file.path);\n }\n }\n\n const { body, headers: bodyHeaders } = await this.createDeployBody(files, options.tags, options.via);\n\n const authHeaders: Record<string, string> = {};\n if (options.deployToken) {\n authHeaders['Authorization'] = `Bearer ${options.deployToken}`;\n } else if (options.apiKey) {\n authHeaders['Authorization'] = `Bearer ${options.apiKey}`;\n }\n if (options.caller) {\n authHeaders['X-Caller'] = options.caller;\n }\n\n return this.request<Deployment>(\n `${options.apiUrl || this.apiUrl}${ENDPOINTS.DEPLOYMENTS}`,\n { method: 'POST', body, headers: { ...bodyHeaders, ...authHeaders }, signal: options.signal || null },\n 'Deploy'\n );\n }\n\n async listDeployments(): Promise<DeploymentListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}`, { method: 'GET' }, 'List deployments');\n }\n\n async getDeployment(id: string): Promise<Deployment> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`, { method: 'GET' }, 'Get deployment');\n }\n\n async updateDeploymentTags(id: string, tags: string[]): Promise<Deployment> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`,\n { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tags }) },\n 'Update deployment tags'\n );\n }\n\n async removeDeployment(id: string): Promise<void> {\n await this.request<DeploymentRemoveResponse>(\n `${this.apiUrl}${ENDPOINTS.DEPLOYMENTS}/${encodeURIComponent(id)}`,\n { method: 'DELETE' },\n 'Remove deployment'\n );\n }\n\n // ===========================================================================\n // PUBLIC API - DOMAINS\n // ===========================================================================\n // All domain methods accept FQDN (Fully Qualified Domain Name) as the `name` parameter.\n // The SDK does not validate or normalize - the API handles all domain semantics.\n\n async setDomain(name: string, deployment?: string, tags?: string[]): Promise<Domain> {\n const body: { deployment?: string; tags?: string[] } = {};\n if (deployment) body.deployment = deployment;\n if (tags !== undefined) body.tags = tags;\n\n const { data, status } = await this.requestWithStatus<Domain>(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`,\n { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'Set domain'\n );\n\n return { ...data, isCreate: status === 201 };\n }\n\n async listDomains(): Promise<DomainListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}`, { method: 'GET' }, 'List domains');\n }\n\n async getDomain(name: string): Promise<Domain> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`, { method: 'GET' }, 'Get domain');\n }\n\n async updateDomainTags(name: string, tags: string[]): Promise<Domain> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`,\n { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tags }) },\n 'Update domain tags'\n );\n }\n\n async removeDomain(name: string): Promise<void> {\n await this.request<void>(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}`, { method: 'DELETE' }, 'Remove domain');\n }\n\n async verifyDomain(name: string): Promise<{ message: string }> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/verify`, { method: 'POST' }, 'Verify domain');\n }\n\n async getDomainDns(name: string): Promise<DomainDnsResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/dns`, { method: 'GET' }, 'Get domain DNS');\n }\n\n async getDomainRecords(name: string): Promise<DomainRecordsResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/records`, { method: 'GET' }, 'Get domain records');\n }\n\n async getDomainShare(name: string): Promise<{ domain: string; hash: string }> {\n return this.request(`${this.apiUrl}${ENDPOINTS.DOMAINS}/${encodeURIComponent(name)}/share`, { method: 'GET' }, 'Get domain share');\n }\n\n async validateDomain(name: string): Promise<DomainValidateResponse> {\n return this.request(\n `${this.apiUrl}${ENDPOINTS.DOMAINS}/validate`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ domain: name }) },\n 'Validate domain'\n );\n }\n\n // ===========================================================================\n // PUBLIC API - TOKENS\n // ===========================================================================\n\n async createToken(ttl?: number, tags?: string[]): Promise<TokenCreateResponse> {\n const body: { ttl?: number; tags?: string[] } = {};\n if (ttl !== undefined) body.ttl = ttl;\n if (tags !== undefined) body.tags = tags;\n\n return this.request(\n `${this.apiUrl}${ENDPOINTS.TOKENS}`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'Create token'\n );\n }\n\n async listTokens(): Promise<TokenListResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.TOKENS}`, { method: 'GET' }, 'List tokens');\n }\n\n async removeToken(token: string): Promise<void> {\n await this.request<void>(`${this.apiUrl}${ENDPOINTS.TOKENS}/${encodeURIComponent(token)}`, { method: 'DELETE' }, 'Remove token');\n }\n\n // ===========================================================================\n // PUBLIC API - ACCOUNT & CONFIG\n // ===========================================================================\n\n async getAccount(): Promise<Account> {\n return this.request(`${this.apiUrl}${ENDPOINTS.ACCOUNT}`, { method: 'GET' }, 'Get account');\n }\n\n async getConfig(): Promise<ConfigResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.CONFIG}`, { method: 'GET' }, 'Get config');\n }\n\n async ping(): Promise<boolean> {\n const data = await this.request<PingResponse>(`${this.apiUrl}${ENDPOINTS.PING}`, { method: 'GET' }, 'Ping');\n return data?.success || false;\n }\n\n async getPingResponse(): Promise<PingResponse> {\n return this.request(`${this.apiUrl}${ENDPOINTS.PING}`, { method: 'GET' }, 'Ping');\n }\n\n // ===========================================================================\n // PUBLIC API - SPA CHECK\n // ===========================================================================\n\n async checkSPA(files: StaticFile[]): Promise<boolean> {\n const indexFile = files.find(f => f.path === 'index.html' || f.path === '/index.html');\n if (!indexFile || indexFile.size > 100 * 1024) {\n return false;\n }\n\n let indexContent: string;\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(indexFile.content)) {\n indexContent = indexFile.content.toString('utf-8');\n } else if (typeof Blob !== 'undefined' && indexFile.content instanceof Blob) {\n indexContent = await indexFile.content.text();\n } else if (typeof File !== 'undefined' && indexFile.content instanceof File) {\n indexContent = await indexFile.content.text();\n } else {\n return false;\n }\n\n const body: SPACheckRequest = { files: files.map(f => f.path), index: indexContent };\n const response = await this.request<SPACheckResponse>(\n `${this.apiUrl}${ENDPOINTS.SPA_CHECK}`,\n { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },\n 'SPA check'\n );\n\n return response.isSPA;\n }\n}\n","/**\n * Event system for Ship SDK\n * Lightweight, reliable event handling with proper error boundaries\n */\n\nimport type { ShipEvents } from './types.js';\n\n/**\n * Lightweight event system\n * - Add handler: on() \n * - Remove handler: off()\n * - Emit events: emit() [internal]\n * - Transfer events: transfer() [internal]\n * - Reliable error handling and cleanup\n */\nexport class SimpleEvents {\n private handlers = new Map<string, Set<Function>>();\n\n /**\n * Add event handler\n */\n on<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n if (!this.handlers.has(event as string)) {\n this.handlers.set(event as string, new Set());\n }\n this.handlers.get(event as string)!.add(handler);\n }\n\n /**\n * Remove event handler \n */\n off<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n const eventHandlers = this.handlers.get(event as string);\n if (eventHandlers) {\n eventHandlers.delete(handler);\n if (eventHandlers.size === 0) {\n this.handlers.delete(event as string);\n }\n }\n }\n\n /**\n * Emit event (internal use only)\n * @internal\n */\n emit<K extends keyof ShipEvents>(event: K, ...args: ShipEvents[K]): void {\n const eventHandlers = this.handlers.get(event as string);\n if (!eventHandlers) return;\n\n // Create array to prevent modification during iteration\n const handlerArray = Array.from(eventHandlers);\n \n for (const handler of handlerArray) {\n try {\n handler(...args);\n } catch (error) {\n // Remove failing handlers to prevent repeated failures\n eventHandlers.delete(handler);\n \n // Re-emit as error event (only if not already error to prevent loops)\n if (event !== 'error') {\n // Use setTimeout to break out of current call stack and prevent infinite recursion\n setTimeout(() => {\n if (error instanceof Error) {\n this.emit('error', error, String(event));\n } else {\n this.emit('error', new Error(String(error)), String(event));\n }\n }, 0);\n }\n }\n }\n }\n\n /**\n * Transfer all handlers to another events instance\n * @internal\n */\n transfer(target: SimpleEvents): void {\n this.handlers.forEach((handlers, event) => {\n handlers.forEach(handler => {\n // any[] required: handler type info is erased when stored in Map<string, Set<Function>>\n target.on(event as keyof ShipEvents, handler as (...args: any[]) => void);\n });\n });\n }\n\n /**\n * Clear all handlers (for cleanup)\n * @internal \n */\n clear(): void {\n this.handlers.clear();\n }\n}","/**\n * @file Base Ship SDK class - provides shared functionality across environments.\n */\n\nimport { ApiHttp } from './api/http.js';\nimport { ShipError } from '@shipstatic/types';\nimport type { ShipClientOptions, ShipEvents } from './types.js';\nimport type { Deployment, ConfigResponse } from '@shipstatic/types';\nimport { getCurrentConfig } from './core/platform-config.js';\nimport type { ResolvedConfig } from './core/config.js';\n\n// Resource imports\nimport {\n createDeploymentResource,\n createDomainResource,\n createAccountResource,\n createTokenResource,\n type DeployInput\n} from './resources.js';\nimport type {\n DeploymentResource,\n DomainResource,\n AccountResource,\n TokenResource\n} from '@shipstatic/types';\n\nimport type { StaticFile } from '@shipstatic/types';\nimport type { DeploymentOptions, DeployBodyCreator } from './types.js';\n\n/**\n * Authentication state for the Ship instance\n * Discriminated union ensures only one auth method is active at a time\n */\ntype AuthState =\n | { type: 'token'; value: string }\n | { type: 'apiKey'; value: string }\n | null;\n\n/**\n * Abstract base class for Ship SDK implementations.\n *\n * Provides shared functionality while allowing environment-specific\n * implementations to handle configuration loading and deployment processing.\n */\nexport abstract class Ship {\n protected http: ApiHttp;\n protected readonly clientOptions: ShipClientOptions;\n protected initPromise: Promise<void> | null = null;\n protected _config: ConfigResponse | null = null;\n\n // Authentication state management\n private auth: AuthState = null;\n\n // Store the auth headers callback to reuse when replacing HTTP client\n protected readonly authHeadersCallback: () => Record<string, string>;\n\n // Resource instances (initialized during creation)\n protected _deployments: DeploymentResource;\n protected _domains: DomainResource;\n protected _account: AccountResource;\n protected _tokens: TokenResource;\n\n constructor(options: ShipClientOptions = {}) {\n this.clientOptions = options;\n\n // Initialize auth state from constructor options\n // Prioritize deployToken over apiKey if both are provided\n if (options.deployToken) {\n this.auth = { type: 'token', value: options.deployToken };\n } else if (options.apiKey) {\n this.auth = { type: 'apiKey', value: options.apiKey };\n }\n\n // Create the auth headers callback once and reuse it\n this.authHeadersCallback = () => this.getAuthHeaders();\n\n // Initialize HTTP client with constructor options for immediate use\n const config = this.resolveInitialConfig(options);\n this.http = new ApiHttp({\n ...options,\n ...config,\n getAuthHeaders: this.authHeadersCallback,\n createDeployBody: this.getDeployBodyCreator()\n });\n\n const ctx = {\n getApi: () => this.http,\n ensureInit: () => this.ensureInitialized()\n };\n\n this._deployments = createDeploymentResource({\n ...ctx,\n processInput: (input, options) => this.processInput(input, options),\n clientDefaults: this.clientOptions,\n hasAuth: () => this.hasAuth()\n });\n this._domains = createDomainResource(ctx);\n this._account = createAccountResource(ctx);\n this._tokens = createTokenResource(ctx);\n }\n\n // Abstract methods that environments must implement\n protected abstract resolveInitialConfig(options: ShipClientOptions): ResolvedConfig;\n protected abstract loadFullConfig(): Promise<void>;\n protected abstract processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]>;\n protected abstract getDeployBodyCreator(): DeployBodyCreator;\n\n /**\n * Ensure full initialization is complete - called lazily by resources\n */\n protected async ensureInitialized(): Promise<void> {\n if (!this.initPromise) {\n this.initPromise = this.loadFullConfig();\n }\n return this.initPromise;\n }\n\n /**\n * Ping the API server to check connectivity\n */\n async ping(): Promise<boolean> {\n await this.ensureInitialized();\n return this.http.ping();\n }\n\n /**\n * Deploy project (convenience shortcut to ship.deployments.create())\n */\n async deploy(input: DeployInput, options?: DeploymentOptions): Promise<Deployment> {\n return this.deployments.create(input, options);\n }\n\n /**\n * Get current account information (convenience shortcut to ship.account.get())\n */\n async whoami() {\n return this.account.get();\n }\n\n /**\n * Get deployments resource (environment-specific)\n */\n get deployments(): DeploymentResource {\n return this._deployments;\n }\n\n /**\n * Get domains resource\n */\n get domains(): DomainResource {\n return this._domains;\n }\n\n /**\n * Get account resource\n */\n get account(): AccountResource {\n return this._account;\n }\n\n /**\n * Get tokens resource\n */\n get tokens(): TokenResource {\n return this._tokens;\n }\n\n /**\n * Get API configuration (file upload limits, etc.)\n * Reuses platform config fetched during initialization, then caches the result\n */\n async getConfig(): Promise<ConfigResponse> {\n if (this._config) {\n return this._config;\n }\n\n await this.ensureInitialized();\n // After initialization, platform config is already fetched - reuse it instead of making another API call\n this._config = getCurrentConfig();\n return this._config;\n }\n\n /**\n * Add event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n on<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n this.http.on(event, handler);\n }\n\n /**\n * Remove event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n off<K extends keyof ShipEvents>(event: K, handler: (...args: ShipEvents[K]) => void): void {\n this.http.off(event, handler);\n }\n\n /**\n * Replace HTTP client while preserving event listeners\n * Used during initialization to maintain user event subscriptions\n * @protected\n */\n protected replaceHttpClient(newClient: ApiHttp): void {\n if (this.http?.transferEventsTo) {\n try {\n this.http.transferEventsTo(newClient);\n } catch (error) {\n // Event transfer failed - log but continue (better than crashing initialization)\n console.warn('Event transfer failed during client replacement:', error);\n }\n }\n this.http = newClient;\n }\n\n /**\n * Sets the deploy token for authentication.\n * This will override any previously set API key or deploy token.\n * @param token The deploy token (format: token-<64-char-hex>)\n */\n public setDeployToken(token: string): void {\n if (!token || typeof token !== 'string') {\n throw ShipError.business('Invalid deploy token provided. Deploy token must be a non-empty string.');\n }\n this.auth = { type: 'token', value: token };\n }\n\n /**\n * Sets the API key for authentication.\n * This will override any previously set API key or deploy token.\n * @param key The API key (format: ship-<64-char-hex>)\n */\n public setApiKey(key: string): void {\n if (!key || typeof key !== 'string') {\n throw ShipError.business('Invalid API key provided. API key must be a non-empty string.');\n }\n this.auth = { type: 'apiKey', value: key };\n }\n\n /**\n * Generate authorization headers based on current auth state\n * Called dynamically on each request to ensure latest credentials are used\n * @private\n */\n private getAuthHeaders(): Record<string, string> {\n if (!this.auth) {\n return {};\n }\n return { 'Authorization': `Bearer ${this.auth.value}` };\n }\n\n /**\n * Check if authentication credentials are configured\n * Used by resources to fail fast if auth is required\n * @private\n */\n private hasAuth(): boolean {\n // useCredentials means cookies are used for auth - no explicit token needed\n if (this.clientOptions.useCredentials) {\n return true;\n }\n return this.auth !== null;\n }\n\n}","/**\n * Ship SDK resource factory functions.\n */\nimport {\n ShipError,\n type StaticFile,\n type DeployInput,\n type DeploymentResource,\n type DomainResource,\n type AccountResource,\n type TokenResource\n} from '@shipstatic/types';\n\nexport type {\n StaticFile,\n DeployInput,\n DeploymentResource,\n DomainResource,\n AccountResource,\n TokenResource\n};\nimport type { ApiHttp } from './api/http.js';\nimport type { ShipClientOptions, DeploymentOptions } from './types.js';\nimport { mergeDeployOptions } from './core/config.js';\nimport { detectAndConfigureSPA } from './lib/spa.js';\n\n/**\n * Shared context for all resource factories.\n */\nexport interface ResourceContext {\n getApi: () => ApiHttp;\n ensureInit: () => Promise<void>;\n}\n\n/**\n * Extended context for deployment resource.\n */\nexport interface DeploymentResourceContext extends ResourceContext {\n processInput: (input: DeployInput, options: DeploymentOptions) => Promise<StaticFile[]>;\n clientDefaults?: ShipClientOptions;\n hasAuth?: () => boolean;\n}\n\n/**\n * Create deployment resource with all CRUD operations.\n */\nexport function createDeploymentResource(ctx: DeploymentResourceContext): DeploymentResource {\n const { getApi, ensureInit, processInput, clientDefaults, hasAuth } = ctx;\n\n return {\n create: async (input: DeployInput, options: DeploymentOptions = {}) => {\n await ensureInit();\n\n const mergedOptions = clientDefaults\n ? mergeDeployOptions(options, clientDefaults)\n : options;\n\n if (hasAuth && !hasAuth() && !mergedOptions.deployToken && !mergedOptions.apiKey) {\n throw ShipError.authentication(\n 'Authentication credentials are required for deployment. ' +\n 'Please call setDeployToken() or setApiKey() first, or pass credentials in the deployment options.'\n );\n }\n\n if (!processInput) {\n throw ShipError.config('processInput function is not provided.');\n }\n\n const apiClient = getApi();\n let staticFiles = await processInput(input, mergedOptions);\n staticFiles = await detectAndConfigureSPA(staticFiles, apiClient, mergedOptions);\n\n return apiClient.deploy(staticFiles, mergedOptions);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listDeployments();\n },\n\n get: async (id: string) => {\n await ensureInit();\n return getApi().getDeployment(id);\n },\n\n set: async (id: string, options: { tags: string[] }) => {\n await ensureInit();\n return getApi().updateDeploymentTags(id, options.tags);\n },\n\n remove: async (id: string) => {\n await ensureInit();\n await getApi().removeDeployment(id);\n }\n };\n}\n\n/**\n * Create domain resource with all CRUD operations.\n *\n * @remarks\n * The `name` parameter in all methods is an FQDN (Fully Qualified Domain Name).\n * The SDK does not validate or normalize domain names - the API handles all domain semantics.\n */\nexport function createDomainResource(ctx: ResourceContext): DomainResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n set: async (name: string, options: { deployment?: string; tags?: string[] } = {}) => {\n await ensureInit();\n const { deployment, tags } = options;\n\n // Smart routing: tags-only → PATCH; otherwise → PUT (create/link/reserve)\n if (deployment === undefined && tags && tags.length > 0) {\n return getApi().updateDomainTags(name, tags);\n }\n return getApi().setDomain(name, deployment, tags);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listDomains();\n },\n\n get: async (name: string) => {\n await ensureInit();\n return getApi().getDomain(name);\n },\n\n remove: async (name: string) => {\n await ensureInit();\n await getApi().removeDomain(name);\n },\n\n verify: async (name: string) => {\n await ensureInit();\n return getApi().verifyDomain(name);\n },\n\n validate: async (name: string) => {\n await ensureInit();\n return getApi().validateDomain(name);\n },\n\n dns: async (name: string) => {\n await ensureInit();\n return getApi().getDomainDns(name);\n },\n\n records: async (name: string) => {\n await ensureInit();\n return getApi().getDomainRecords(name);\n },\n\n share: async (name: string) => {\n await ensureInit();\n return getApi().getDomainShare(name);\n }\n };\n}\n\n/**\n * Create account resource (whoami functionality).\n */\nexport function createAccountResource(ctx: ResourceContext): AccountResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n get: async () => {\n await ensureInit();\n return getApi().getAccount();\n }\n };\n}\n\n/**\n * Create token resource for managing deploy tokens.\n */\nexport function createTokenResource(ctx: ResourceContext): TokenResource {\n const { getApi, ensureInit } = ctx;\n\n return {\n create: async (options: { ttl?: number; tags?: string[] } = {}) => {\n await ensureInit();\n return getApi().createToken(options.ttl, options.tags);\n },\n\n list: async () => {\n await ensureInit();\n return getApi().listTokens();\n },\n\n remove: async (token: string) => {\n await ensureInit();\n await getApi().removeToken(token);\n }\n };\n}\n","/**\n * @file Shared configuration logic for both environments.\n *\n * CONFIGURATION PRECEDENCE (highest to lowest):\n * 1. Constructor options / CLI flags (passed directly to Ship())\n * 2. Environment variables (SHIP_API_KEY, SHIP_DEPLOY_TOKEN, SHIP_API_URL)\n * 3. Config file (.shiprc or package.json \"ship\" key)\n * 4. Default values (DEFAULT_API)\n *\n * This means CLI flags always win, followed by env vars, then config files.\n */\n\nimport { DEFAULT_API, type PlatformConfig, type ResolvedConfig } from '@shipstatic/types';\nimport type { ShipClientOptions, DeploymentOptions } from '../types.js';\nimport { getENV } from '../lib/env.js';\n\nexport type { ResolvedConfig } from '@shipstatic/types';\n\n/**\n * Cross-environment config loader that dispatches to appropriate implementation.\n */\nexport async function loadConfig(configFile?: string): Promise<PlatformConfig> {\n const env = getENV();\n\n if (env === 'browser') {\n // In browser, return empty config (no file system access)\n return {};\n } else if (env === 'node') {\n // In Node.js, load from environment and files\n const { loadConfig: nodeLoadConfig } = await import('../../node/core/config.js');\n return nodeLoadConfig(configFile);\n } else {\n // Fallback to empty config for unknown environments\n return {};\n }\n}\n\n/**\n * Universal configuration resolver for all environments.\n * This is the single source of truth for config resolution.\n */\nexport function resolveConfig(\n userOptions: ShipClientOptions = {},\n loadedConfig: Partial<ShipClientOptions> = {}\n): ResolvedConfig {\n const finalConfig = {\n apiUrl: userOptions.apiUrl || loadedConfig.apiUrl || DEFAULT_API,\n apiKey: userOptions.apiKey !== undefined ? userOptions.apiKey : loadedConfig.apiKey,\n deployToken: userOptions.deployToken !== undefined ? userOptions.deployToken : loadedConfig.deployToken,\n };\n\n const result: ResolvedConfig = {\n apiUrl: finalConfig.apiUrl\n };\n\n if (finalConfig.apiKey !== undefined) result.apiKey = finalConfig.apiKey;\n if (finalConfig.deployToken !== undefined) result.deployToken = finalConfig.deployToken;\n\n return result;\n}\n\n/**\n * Merge deployment options with client defaults.\n * This is shared logic used by both environments.\n */\nexport function mergeDeployOptions(\n options: DeploymentOptions,\n clientDefaults: ShipClientOptions\n): DeploymentOptions {\n const result: DeploymentOptions = { ...options };\n\n // Only add defined values from client defaults\n if (result.apiUrl === undefined && clientDefaults.apiUrl !== undefined) {\n result.apiUrl = clientDefaults.apiUrl;\n }\n if (result.apiKey === undefined && clientDefaults.apiKey !== undefined) {\n result.apiKey = clientDefaults.apiKey;\n }\n if (result.deployToken === undefined && clientDefaults.deployToken !== undefined) {\n result.deployToken = clientDefaults.deployToken;\n }\n if (result.timeout === undefined && clientDefaults.timeout !== undefined) {\n result.timeout = clientDefaults.timeout;\n }\n if (result.maxConcurrency === undefined && clientDefaults.maxConcurrency !== undefined) {\n result.maxConcurrency = clientDefaults.maxConcurrency;\n }\n if (result.onProgress === undefined && clientDefaults.onProgress !== undefined) {\n result.onProgress = clientDefaults.onProgress;\n }\n if (result.caller === undefined && clientDefaults.caller !== undefined) {\n result.caller = clientDefaults.caller;\n }\n\n return result;\n}\n","/**\n * @file SPA detection and auto-configuration utilities.\n *\n * Provides SPA detection and ship.json generation functionality\n * that can be used by both Node.js and browser environments.\n */\n\nimport { DEPLOYMENT_CONFIG_FILENAME } from '@shipstatic/types';\nimport { calculateMD5 } from './md5.js';\nimport type { StaticFile, DeploymentOptions } from '../types.js';\nimport type { ApiHttp } from '../api/http.js';\n\n/**\n * Creates ship.json configuration for SPA projects.\n * @returns Promise resolving to StaticFile with SPA configuration\n */\nexport async function createSPAConfig(): Promise<StaticFile> {\n const config = {\n \"rewrites\": [{\n \"source\": \"/(.*)\",\n \"destination\": \"/index.html\"\n }]\n };\n\n const configString = JSON.stringify(config, null, 2);\n\n // Create content that works in both browser and Node.js environments\n let content: Buffer | Blob;\n if (typeof Buffer !== 'undefined') {\n // Node.js environment\n content = Buffer.from(configString, 'utf-8');\n } else {\n // Browser environment\n content = new Blob([configString], { type: 'application/json' });\n }\n\n const { md5 } = await calculateMD5(content);\n\n return {\n path: DEPLOYMENT_CONFIG_FILENAME,\n content,\n size: configString.length,\n md5\n };\n}\n\n/**\n * Detects SPA projects and auto-generates configuration.\n * This function can be used by both Node.js and browser environments.\n *\n * @param files - Array of StaticFiles to analyze\n * @param apiClient - HTTP client for API communication\n * @param options - Deployment options containing SPA detection settings\n * @returns Promise resolving to files array with optional SPA config added\n */\nexport async function detectAndConfigureSPA(\n files: StaticFile[],\n apiClient: ApiHttp,\n options: DeploymentOptions\n): Promise<StaticFile[]> {\n // Skip if disabled or config already exists\n if (options.spaDetect === false || files.some(f => f.path === DEPLOYMENT_CONFIG_FILENAME)) {\n return files;\n }\n\n try {\n const isSPA = await apiClient.checkSPA(files);\n\n if (isSPA) {\n const spaConfig = await createSPAConfig();\n return [...files, spaConfig];\n }\n } catch (error) {\n // SPA detection failed, continue silently without auto-config\n }\n\n return files;\n}\n","/**\n * @file Ship SDK for Node.js environments with full file system support.\n */\n\nimport { Ship as BaseShip } from '../shared/base-ship.js';\nimport { ShipError } from '@shipstatic/types';\nimport { getENV } from '../shared/lib/env.js';\nimport { loadConfig } from './core/config.js';\nimport { resolveConfig, type ResolvedConfig } from '../shared/core/config.js';\nimport { setConfig } from '../shared/core/platform-config.js';\nimport { ApiHttp } from '../shared/api/http.js';\nimport type { ShipClientOptions, DeployInput, DeploymentOptions, StaticFile, DeployBodyCreator } from '../shared/types.js';\nimport { createDeployBody } from './core/deploy-body.js';\n\n// Export all shared functionality\nexport * from '../shared/index.js';\n\n/**\n * Ship SDK Client for Node.js environments.\n * \n * Provides full file system access, configuration file loading,\n * and environment variable support.\n * \n * @example\n * ```typescript\n * // Authenticated deployments with API key\n * const ship = new Ship({ apiKey: \"ship-xxxx\" });\n * \n * // Single-use deployments with deploy token\n * const ship = new Ship({ deployToken: \"token-xxxx\" });\n * \n * // Deploy a directory\n * await ship.deploy('./dist');\n * ```\n */\nexport class Ship extends BaseShip {\n constructor(options: ShipClientOptions = {}) {\n const environment = getENV();\n\n if (environment !== 'node') {\n throw ShipError.business('Node.js Ship class can only be used in Node.js environment.');\n }\n\n super(options);\n }\n\n protected resolveInitialConfig(options: ShipClientOptions): ResolvedConfig {\n return resolveConfig(options, {});\n }\n\n protected async loadFullConfig(): Promise<void> {\n try {\n // Load config from file/env\n const loadedConfig = await loadConfig(this.clientOptions.configFile);\n // Re-resolve and re-create the http client with the full config\n const finalConfig = resolveConfig(this.clientOptions, loadedConfig);\n\n // Update auth state with loaded credentials (if not already set by constructor)\n // This ensures hasAuth() returns true after loading from env/config files\n if (finalConfig.deployToken && !this.clientOptions.deployToken) {\n this.setDeployToken(finalConfig.deployToken);\n } else if (finalConfig.apiKey && !this.clientOptions.apiKey) {\n this.setApiKey(finalConfig.apiKey);\n }\n\n // Replace HTTP client while preserving event listeners (clean intentional API)\n // Use the same getAuthHeaders callback as the initial client\n const newClient = new ApiHttp({\n ...this.clientOptions,\n ...finalConfig,\n getAuthHeaders: this.authHeadersCallback,\n createDeployBody: this.getDeployBodyCreator()\n });\n this.replaceHttpClient(newClient);\n\n const platformConfig = await this.http.getConfig();\n setConfig(platformConfig);\n } catch (error) {\n // Reset initialization promise so it can be retried\n this.initPromise = null;\n throw error;\n }\n }\n\n protected async processInput(input: DeployInput, options: DeploymentOptions): Promise<StaticFile[]> {\n // Normalize string to string[] and validate\n const paths = typeof input === 'string' ? [input] : input;\n\n if (!Array.isArray(paths) || !paths.every(p => typeof p === 'string')) {\n throw ShipError.business('Invalid input type for Node.js environment. Expected string or string[].');\n }\n\n if (paths.length === 0) {\n throw ShipError.business('No files to deploy.');\n }\n\n // Process files directly - no intermediate conversion layer\n const { processFilesForNode } = await import('./core/node-files.js');\n return processFilesForNode(paths, options);\n }\n\n protected getDeployBodyCreator(): DeployBodyCreator {\n return createDeployBody;\n }\n}\n\n// Default export (for import Ship from 'ship')\nexport default Ship;\n\n// Node.js specific exports\nexport { loadConfig } from './core/config.js';\nexport { setConfig as setPlatformConfig, getCurrentConfig } from '../shared/core/platform-config.js';\n\n// Node.js utilities\nexport { processFilesForNode } from './core/node-files.js';\nexport { __setTestEnvironment, getENV } from '../shared/lib/env.js';","/**\n * Node.js-specific deploy body creation.\n */\nimport { ShipError } from '@shipstatic/types';\nimport type { StaticFile, DeployBody } from '../../shared/types.js';\nimport { getMimeType } from '../../shared/utils/mimeType.js';\n\nexport async function createDeployBody(\n files: StaticFile[],\n tags?: string[],\n via?: string\n): Promise<DeployBody> {\n const { FormData, File } = await import('formdata-node');\n const { FormDataEncoder } = await import('form-data-encoder');\n\n const formData = new FormData();\n const checksums: string[] = [];\n\n for (const file of files) {\n const contentType = getMimeType(file.path);\n\n let fileInstance;\n if (Buffer.isBuffer(file.content)) {\n fileInstance = new File([file.content], file.path, { type: contentType });\n } else if (typeof Blob !== 'undefined' && file.content instanceof Blob) {\n fileInstance = new File([file.content], file.path, { type: contentType });\n } else {\n throw ShipError.file(`Unsupported file.content type for Node.js: ${file.path}`, file.path);\n }\n\n if (!file.md5) {\n throw ShipError.file(`File missing md5 checksum: ${file.path}`, file.path);\n }\n\n const preservedPath = file.path.startsWith('/') ? file.path : '/' + file.path;\n formData.append('files[]', fileInstance, preservedPath);\n checksums.push(file.md5);\n }\n\n formData.append('checksums', JSON.stringify(checksums));\n\n if (tags && tags.length > 0) {\n formData.append('tags', JSON.stringify(tags));\n }\n\n if (via) {\n formData.append('via', via);\n }\n\n const encoder = new FormDataEncoder(formData);\n const chunks = [];\n for await (const chunk of encoder.encode()) {\n chunks.push(Buffer.from(chunk));\n }\n const body = Buffer.concat(chunks);\n\n return {\n body: body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength) as ArrayBuffer,\n headers: {\n 'Content-Type': encoder.contentType,\n 'Content-Length': Buffer.byteLength(body).toString()\n }\n };\n}\n","/**\n * Browser-compatible MIME type utilities\n * Uses mime-db directly without Node.js dependencies\n */\nimport mimeDb from 'mime-db';\n\n// Build extension to MIME type map from mime-db\nconst extensionToMimeMap: { [key: string]: string } = {};\nfor (const type in mimeDb) {\n const mimeInfo = mimeDb[type];\n if (mimeInfo && mimeInfo.extensions) {\n mimeInfo.extensions.forEach((ext: string) => {\n if (!extensionToMimeMap[ext]) {\n extensionToMimeMap[ext] = type;\n }\n });\n }\n}\n\n/**\n * Get MIME type from file path (browser-compatible, no Node.js dependencies)\n */\nexport function getMimeType(path: string): string {\n const extension = path.includes('.')\n ? path.substring(path.lastIndexOf('.') + 1).toLowerCase()\n : '';\n return extensionToMimeMap[extension] || 'application/octet-stream';\n}\n","/**\n * Simple CLI utilities following \"impossible simplicity\" mantra\n */\nimport columnify from 'columnify';\nimport { bold, dim, green, red, yellow, blue, inverse, hidden } from 'yoctocolors';\n\nconst INTERNAL_FIELDS = ['isCreate'];\n\nconst applyColor = (colorFn: (text: string) => string, text: string, noColor?: boolean): string => {\n return noColor ? text : colorFn(text);\n};\n\n/**\n * Message helper functions for consistent CLI output\n */\nexport const success = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ success: msg }, null, 2) + '\\n');\n } else {\n console.log(`${applyColor(green, msg.toLowerCase().replace(/\\.$/, ''), noColor)}\\n`);\n }\n};\n\nexport const error = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.error(JSON.stringify({ error: msg }, null, 2) + '\\n');\n } else {\n const errorPrefix = applyColor((text) => inverse(red(text)), `${applyColor(hidden, '[', noColor)}error${applyColor(hidden, ']', noColor)}`, noColor);\n const errorMsg = applyColor(red, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.error(`${errorPrefix} ${errorMsg}\\n`);\n }\n};\n\nexport const warn = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ warning: msg }, null, 2) + '\\n');\n } else {\n const warnPrefix = applyColor((text) => inverse(yellow(text)), `${applyColor(hidden, '[', noColor)}warning${applyColor(hidden, ']', noColor)}`, noColor);\n const warnMsg = applyColor(yellow, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.log(`${warnPrefix} ${warnMsg}\\n`);\n }\n};\n\nexport const info = (msg: string, isJson?: boolean, noColor?: boolean) => {\n if (isJson) {\n console.log(JSON.stringify({ info: msg }, null, 2) + '\\n');\n } else {\n const infoPrefix = applyColor((text) => inverse(blue(text)), `${applyColor(hidden, '[', noColor)}info${applyColor(hidden, ']', noColor)}`, noColor);\n const infoMsg = applyColor(blue, msg.toLowerCase().replace(/\\.$/, ''), noColor);\n console.log(`${infoPrefix} ${infoMsg}\\n`);\n }\n};\n\n\n/**\n * Format unix timestamp to ISO 8601 string without milliseconds, or return '-' if not provided\n */\nexport const formatTimestamp = (timestamp?: number, context: 'table' | 'details' = 'details', noColor?: boolean): string => {\n if (timestamp === undefined || timestamp === null || timestamp === 0) {\n return '-';\n }\n \n const isoString = new Date(timestamp * 1000).toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n \n // Hide the T and Z characters only in table/list views for cleaner appearance\n if (context === 'table') {\n return isoString.replace(/T/, applyColor(hidden, 'T', noColor)).replace(/Z$/, applyColor(hidden, 'Z', noColor));\n }\n \n return isoString;\n};\n\n/**\n * Format value for display.\n * Handles timestamps, file sizes, and boolean configs with special formatting.\n */\nconst formatValue = (key: string, value: unknown, context: 'table' | 'details' = 'details', noColor?: boolean): string => {\n if (typeof value === 'number' && (key === 'created' || key === 'expires' || key === 'linked')) {\n return formatTimestamp(value, context, noColor);\n }\n if (key === 'size' && typeof value === 'number') {\n const mb = value / (1024 * 1024);\n return mb >= 1 ? `${mb.toFixed(1)}Mb` : `${(value / 1024).toFixed(1)}Kb`;\n }\n if (key === 'config') {\n // Handle both boolean and number (0/1) values\n if (typeof value === 'boolean') {\n return value ? 'yes' : 'no';\n }\n if (typeof value === 'number') {\n return value === 1 ? 'yes' : 'no';\n }\n }\n return String(value);\n};\n\n/**\n * Format data as table with specified columns for easy parsing.\n * @param data - Array of objects to display as table rows\n * @param columns - Optional column order (defaults to first item's keys)\n * @param noColor - Disable colors\n * @param headerMap - Optional mapping of property names to display headers (e.g., { url: 'deployment' })\n */\nexport const formatTable = (data: object[], columns?: string[], noColor?: boolean, headerMap?: Record<string, string>): string => {\n if (!data || data.length === 0) return '';\n\n // Get column order from first item (preserves API order) or use provided columns\n const firstItem = data[0] as Record<string, unknown>;\n const columnOrder = columns || Object.keys(firstItem).filter(key =>\n firstItem[key] !== undefined && !INTERNAL_FIELDS.includes(key)\n );\n\n // Transform data preserving column order\n const transformedData = data.map(item => {\n const record = item as Record<string, unknown>;\n const transformed: Record<string, string> = {};\n columnOrder.forEach(col => {\n if (col in record && record[col] !== undefined) {\n transformed[col] = formatValue(col, record[col], 'table', noColor);\n }\n });\n return transformed;\n });\n\n const output = columnify(transformedData, {\n columnSplitter: ' ',\n columns: columnOrder,\n config: columnOrder.reduce<Record<string, { headingTransform: (h: string) => string }>>((config, col) => {\n config[col] = {\n headingTransform: (heading: string) => applyColor(dim, headerMap?.[heading] || heading, noColor)\n };\n return config;\n }, {})\n });\n \n // Clean output: remove null bytes and ensure clean spacing\n return output\n .split('\\n')\n .map((line: string) => line\n .replace(/\\0/g, '') // Remove any null bytes\n .replace(/\\s+$/, '') // Remove trailing spaces\n )\n .join('\\n') + '\\n';\n};\n\n/**\n * Format object properties as key-value pairs with space separation for readability.\n * @param obj - Object to display as key-value pairs\n * @param noColor - Disable colors\n */\nexport const formatDetails = (obj: object, noColor?: boolean): string => {\n const entries = (Object.entries(obj) as [string, unknown][]).filter(([key, value]) => {\n if (INTERNAL_FIELDS.includes(key)) return false;\n return value !== undefined;\n });\n \n if (entries.length === 0) return '';\n \n // Transform to columnify format while preserving order\n const data = entries.map(([key, value]) => ({\n property: key + ':',\n value: formatValue(key, value, 'details', noColor)\n }));\n \n const output = columnify(data, {\n columnSplitter: ' ',\n showHeaders: false,\n config: {\n property: { \n dataTransform: (value: string) => applyColor(dim, value, noColor)\n }\n }\n });\n \n // Clean output: remove null bytes and ensure clean spacing\n return output\n .split('\\n')\n .map((line: string) => line.replace(/\\0/g, '')) // Remove any null bytes\n .join('\\n') + '\\n';\n};\n\n","/**\n * Pure formatting functions for CLI output.\n * All formatters are synchronous and have no side effects beyond console output.\n */\nimport type {\n Deployment,\n DeploymentListResponse,\n DomainListResponse,\n DomainValidateResponse,\n Account,\n TokenCreateResponse,\n TokenListResponse\n} from '@shipstatic/types';\nimport type { EnrichedDomain, MessageResult, CLIResult } from './types.js';\nimport { formatTable, formatDetails, success, error, info } from './utils.js';\n\nexport interface OutputContext {\n operation?: string;\n resourceType?: string;\n resourceId?: string;\n}\n\nexport interface FormatOptions {\n isJson?: boolean;\n noColor?: boolean;\n}\n\n/**\n * Format deployments list\n */\nexport function formatDeploymentsList(result: DeploymentListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.deployments || result.deployments.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ deployments: [] }, null, 2));\n } else {\n console.log('no deployments found');\n console.log();\n }\n return;\n }\n\n const columns = ['url', 'tags', 'created'];\n console.log(formatTable(result.deployments, columns, noColor, { url: 'deployment' }));\n}\n\n/**\n * Format domains list\n */\nexport function formatDomainsList(result: DomainListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.domains || result.domains.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ domains: [] }, null, 2));\n } else {\n console.log('no domains found');\n console.log();\n }\n return;\n }\n\n const columns = ['url', 'deployment', 'tags', 'linked', 'created'];\n console.log(formatTable(result.domains, columns, noColor, { url: 'domain' }));\n}\n\n/**\n * Format single domain result.\n * Expects _dnsRecords and _shareHash to be pre-populated for new external domains.\n */\nexport function formatDomain(result: EnrichedDomain, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n // Show success message for set/update operations\n if (result.domain && (context.operation === 'set' || context.operation === 'update')) {\n const verb = context.operation === 'update' ? 'updated'\n : result.isCreate ? 'created' : 'updated';\n success(`${result.domain} domain ${verb}`, isJson, noColor);\n }\n\n // Display pre-fetched DNS records (for new external domains)\n if (!isJson && result._dnsRecords && result._dnsRecords.length > 0) {\n console.log();\n info('DNS Records to configure:', isJson, noColor);\n result._dnsRecords.forEach((record) => {\n console.log(` ${record.type}: ${record.name} → ${record.value}`);\n });\n }\n\n // Display setup instructions link\n if (!isJson && result._shareHash) {\n console.log();\n info(`Setup instructions: https://setup.shipstatic.com/${result._shareHash}/${result.domain}`, isJson, noColor);\n }\n\n // Filter out internal fields before displaying details\n const { _dnsRecords, _shareHash, ...displayResult } = result;\n\n console.log();\n console.log(formatDetails(displayResult, noColor));\n}\n\n/**\n * Format single deployment result\n */\nexport function formatDeployment(result: Deployment, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n // Show success message for create operations\n if (result.status && context.operation === 'create') {\n success(`${result.deployment} deployment created`, isJson, noColor);\n }\n\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Format account/email result\n */\nexport function formatAccount(result: Account, context: OutputContext, options: FormatOptions): void {\n const { noColor } = options;\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Format message result (e.g., from DNS verification)\n */\nexport function formatMessage(result: MessageResult, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n if (result.message) {\n success(result.message, isJson, noColor);\n }\n}\n\n/**\n * Format domain validation result\n */\nexport function formatDomainValidate(result: DomainValidateResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (isJson) {\n console.log(JSON.stringify(result, null, 2));\n console.log();\n return;\n }\n\n if (result.valid) {\n success(`domain is valid`, isJson, noColor);\n console.log();\n if (result.normalized) {\n console.log(` normalized: ${result.normalized}`);\n }\n if (result.available !== undefined) {\n const availabilityText = result.available ? 'available ✓' : 'already taken';\n console.log(` availability: ${availabilityText}`);\n }\n console.log();\n } else {\n error(result.error || 'domain is invalid', isJson, noColor);\n }\n}\n\n/**\n * Format tokens list\n */\nexport function formatTokensList(result: TokenListResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (!result.tokens || result.tokens.length === 0) {\n if (isJson) {\n console.log(JSON.stringify({ tokens: [] }, null, 2));\n } else {\n console.log('no tokens found');\n console.log();\n }\n return;\n }\n\n const columns = ['token', 'tags', 'created', 'expires'];\n console.log(formatTable(result.tokens, columns, noColor));\n}\n\n/**\n * Format single token result\n */\nexport function formatToken(result: TokenCreateResponse, context: OutputContext, options: FormatOptions): void {\n const { isJson, noColor } = options;\n\n if (context.operation === 'create' && result.token) {\n success(`token created`, isJson, noColor);\n }\n\n console.log(formatDetails(result, noColor));\n}\n\n/**\n * Main output function - routes to appropriate formatter based on result shape.\n * Handles JSON mode, removal operations, and ping results.\n */\nexport function formatOutput(\n result: CLIResult,\n context: OutputContext,\n options: FormatOptions\n): void {\n const { isJson, noColor } = options;\n\n // Handle void/undefined results (removal operations)\n if (result === undefined) {\n if (context.operation === 'remove' && context.resourceType && context.resourceId) {\n success(`${context.resourceId} ${context.resourceType.toLowerCase()} removed`, isJson, noColor);\n } else {\n success('removed successfully', isJson, noColor);\n }\n return;\n }\n\n // Handle ping result (boolean or PingResponse)\n if (result === true || (result !== null && typeof result === 'object' && 'success' in result)) {\n const isSuccess = result === true || (result as { success: boolean }).success;\n if (isSuccess) {\n success('api reachable', isJson, noColor);\n } else {\n error('api unreachable', isJson, noColor);\n }\n return;\n }\n\n // JSON mode: output raw JSON for all results\n if (isJson && result !== null && typeof result === 'object') {\n // Filter internal fields from JSON output\n const output = { ...result } as Record<string, unknown>;\n delete output._dnsRecords;\n delete output._shareHash;\n console.log(JSON.stringify(output, null, 2));\n console.log();\n return;\n }\n\n // Route to specific formatter based on result shape\n // Order matters: check list types before singular types\n if (result !== null && typeof result === 'object') {\n if ('deployments' in result) {\n formatDeploymentsList(result as DeploymentListResponse, context, options);\n } else if ('domains' in result) {\n formatDomainsList(result as DomainListResponse, context, options);\n } else if ('tokens' in result) {\n formatTokensList(result as TokenListResponse, context, options);\n } else if ('domain' in result) {\n formatDomain(result as EnrichedDomain, context, options);\n } else if ('deployment' in result) {\n formatDeployment(result as Deployment, context, options);\n } else if ('token' in result) {\n formatToken(result as TokenCreateResponse, context, options);\n } else if ('email' in result) {\n formatAccount(result as Account, context, options);\n } else if ('valid' in result) {\n formatDomainValidate(result as DomainValidateResponse, context, options);\n } else if ('message' in result) {\n formatMessage(result as MessageResult, context, options);\n } else {\n // Fallback\n success('success', isJson, noColor);\n }\n } else {\n // Fallback for non-object results\n success('success', isJson, noColor);\n }\n}\n","/**\n * Shell completion install/uninstall logic.\n * Handles bash, zsh, and fish shells.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { success, error, info, warn } from './utils.js';\n\nexport interface CompletionOptions {\n isJson?: boolean;\n noColor?: boolean;\n}\n\n/**\n * Detect current shell from environment\n */\nfunction detectShell(): 'bash' | 'zsh' | 'fish' | null {\n const shell = process.env.SHELL || '';\n if (shell.includes('bash')) return 'bash';\n if (shell.includes('zsh')) return 'zsh';\n if (shell.includes('fish')) return 'fish';\n return null;\n}\n\n/**\n * Get shell-specific paths\n */\nfunction getShellPaths(shell: 'bash' | 'zsh' | 'fish', homeDir: string) {\n switch (shell) {\n case 'bash':\n return {\n completionFile: path.join(homeDir, '.ship_completion.bash'),\n profileFile: path.join(homeDir, '.bash_profile'),\n scriptName: 'ship.bash'\n };\n case 'zsh':\n return {\n completionFile: path.join(homeDir, '.ship_completion.zsh'),\n profileFile: path.join(homeDir, '.zshrc'),\n scriptName: 'ship.zsh'\n };\n case 'fish':\n return {\n completionFile: path.join(homeDir, '.config/fish/completions/ship.fish'),\n profileFile: null, // fish doesn't need profile sourcing\n scriptName: 'ship.fish'\n };\n }\n}\n\n/**\n * Install shell completion script\n */\nexport function installCompletion(scriptDir: string, options: CompletionOptions = {}): void {\n const { isJson, noColor } = options;\n const shell = detectShell();\n const homeDir = os.homedir();\n\n if (!shell) {\n error(`unsupported shell: ${process.env.SHELL}. supported: bash, zsh, fish`, isJson, noColor);\n return;\n }\n\n const paths = getShellPaths(shell, homeDir);\n const sourceScript = path.join(scriptDir, paths.scriptName);\n\n try {\n // Fish has a different installation pattern\n if (shell === 'fish') {\n const fishDir = path.dirname(paths.completionFile);\n if (!fs.existsSync(fishDir)) {\n fs.mkdirSync(fishDir, { recursive: true });\n }\n fs.copyFileSync(sourceScript, paths.completionFile);\n success('fish completion installed successfully', isJson, noColor);\n info('please restart your shell to apply the changes', isJson, noColor);\n return;\n }\n\n // Bash and zsh: copy script and add sourcing to profile\n fs.copyFileSync(sourceScript, paths.completionFile);\n const sourceLine = `# ship\\nsource '${paths.completionFile}'\\n# ship end`;\n\n if (paths.profileFile) {\n if (fs.existsSync(paths.profileFile)) {\n const content = fs.readFileSync(paths.profileFile, 'utf-8');\n if (!content.includes('# ship') || !content.includes('# ship end')) {\n const prefix = content.length > 0 && !content.endsWith('\\n') ? '\\n' : '';\n fs.appendFileSync(paths.profileFile, prefix + sourceLine);\n }\n } else {\n fs.writeFileSync(paths.profileFile, sourceLine);\n }\n\n success(`completion script installed for ${shell}`, isJson, noColor);\n warn(`run \"source ${paths.profileFile}\" or restart your shell`, isJson, noColor);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n error(`could not install completion script: ${message}`, isJson, noColor);\n }\n}\n\n/**\n * Uninstall shell completion script\n */\nexport function uninstallCompletion(options: CompletionOptions = {}): void {\n const { isJson, noColor } = options;\n const shell = detectShell();\n const homeDir = os.homedir();\n\n if (!shell) {\n error(`unsupported shell: ${process.env.SHELL}. supported: bash, zsh, fish`, isJson, noColor);\n return;\n }\n\n const paths = getShellPaths(shell, homeDir);\n\n try {\n // Fish: just remove the file\n if (shell === 'fish') {\n if (fs.existsSync(paths.completionFile)) {\n fs.unlinkSync(paths.completionFile);\n success('fish completion uninstalled successfully', isJson, noColor);\n } else {\n warn('fish completion was not installed', isJson, noColor);\n }\n info('please restart your shell to apply the changes', isJson, noColor);\n return;\n }\n\n // Bash and zsh: remove file and clean profile\n if (fs.existsSync(paths.completionFile)) {\n fs.unlinkSync(paths.completionFile);\n }\n\n if (!paths.profileFile) return;\n\n if (!fs.existsSync(paths.profileFile)) {\n error('profile file not found', isJson, noColor);\n return;\n }\n\n const content = fs.readFileSync(paths.profileFile, 'utf-8');\n const lines = content.split('\\n');\n\n // Remove ship block (between \"# ship\" and \"# ship end\")\n const filtered: string[] = [];\n let i = 0;\n let removed = false;\n\n while (i < lines.length) {\n if (lines[i].trim() === '# ship') {\n removed = true;\n i++;\n while (i < lines.length && lines[i].trim() !== '# ship end') i++;\n if (i < lines.length) i++; // skip \"# ship end\"\n } else {\n filtered.push(lines[i]);\n i++;\n }\n }\n\n if (removed) {\n const endsWithNewline = content.endsWith('\\n');\n const newContent = filtered.length === 0\n ? ''\n : filtered.join('\\n') + (endsWithNewline ? '\\n' : '');\n fs.writeFileSync(paths.profileFile, newContent);\n success(`completion script uninstalled for ${shell}`, isJson, noColor);\n warn(`run \"source ${paths.profileFile}\" or restart your shell`, isJson, noColor);\n } else {\n error('completion was not found in profile', isJson, noColor);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n error(`could not uninstall completion script: ${message}`, isJson, noColor);\n }\n}\n","/**\n * @file Error handling utilities for the CLI.\n * Pure functions for error message formatting - fully unit testable.\n */\n\nimport { ShipError, isShipError } from '@shipstatic/types';\n\n/**\n * Convert any error to a ShipError.\n * Used by the CLI's global error handler to normalize unknown errors.\n */\nexport function toShipError(err: unknown): ShipError {\n if (isShipError(err)) {\n return err;\n }\n if (err instanceof Error) {\n return ShipError.business(err.message);\n }\n return ShipError.business(String(err ?? 'Unknown error'));\n}\n\n/**\n * Context for error message generation\n */\nexport interface ErrorContext {\n operation?: string;\n resourceType?: string;\n resourceId?: string;\n}\n\n/**\n * CLI options relevant to error message generation\n */\nexport interface ErrorOptions {\n apiKey?: string;\n deployToken?: string;\n}\n\n/**\n * Get actionable user-facing message from an error.\n * Transforms technical errors into helpful messages that tell users what to do.\n *\n * This is a pure function - given the same inputs, always returns the same output.\n * All error message logic is centralized here for easy testing and maintenance.\n */\nexport function getUserMessage(\n err: ShipError,\n context?: ErrorContext,\n options?: ErrorOptions\n): string {\n // Auth errors - tell user what credentials to provide\n if (err.isAuthError()) {\n if (options?.apiKey) {\n return 'authentication failed: invalid API key';\n } else if (options?.deployToken) {\n return 'authentication failed: invalid or expired deploy token';\n } else {\n return 'authentication required: use --api-key or --deploy-token, or set SHIP_API_KEY';\n }\n }\n\n // Network errors - include context about what failed\n if (err.isNetworkError()) {\n const url = err.details?.url;\n if (url) {\n return `network error: could not reach ${url}`;\n }\n return 'network error: could not reach the API. check your internet connection';\n }\n\n // File, validation, config errors - trust the original message (we wrote it)\n if (err.isFileError() || err.isValidationError() || err.isClientError()) {\n return err.message;\n }\n\n // API errors with 4xx status - these have user-facing messages from the API\n // Includes: 400 (validation), 404 (not found), 409 (conflict), etc.\n if (err.status && err.status >= 400 && err.status < 500) {\n return err.message;\n }\n\n // Server errors (5xx) - generic but actionable\n return 'server error: please try again or check https://status.shipstatic.com';\n}\n\n/**\n * Format error for JSON output.\n * Returns the JSON string to be output (without newline).\n */\nexport function formatErrorJson(message: string, details?: unknown): string {\n return JSON.stringify({\n error: message,\n ...(details ? { details } : {})\n }, null, 2);\n}\n"],"mappings":"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","names":["isShipError","error","validateApiKey","apiKey","API_KEY_PREFIX","ShipError","API_KEY_TOTAL_LENGTH","API_KEY_HEX_LENGTH","hexPart","validateDeployToken","deployToken","DEPLOY_TOKEN_PREFIX","DEPLOY_TOKEN_TOTAL_LENGTH","DEPLOY_TOKEN_HEX_LENGTH","validateApiUrl","apiUrl","url","ErrorType","ERROR_CATEGORIES","DEPLOYMENT_CONFIG_FILENAME","DEFAULT_API","init_dist","__esmMin","_ShipError","type","message","status","details","response","resource","id","cause","filePath","errorType","setConfig","config","_config","getCurrentConfig","ShipError","init_platform_config","__esmMin","init_dist","detectEnvironment","getENV","_testEnvironment","init_env","__esmMin","calculateMD5Browser","blob","SparkMD5","resolve","reject","chunks","currentChunk","spark","fileReader","loadNext","start","end","e","result","ShipError","calculateMD5Node","input","crypto","hash","fs","stream","err","chunk","calculateMD5","env","getENV","init_md5","__esmMin","init_env","init_dist","validateConfig","config","ConfigSchema","error","firstError","path","ShipError","loadConfigFromFile","configFile","getENV","cosmiconfigSync","os","explorer","MODULE_NAME","result","isShipError","loadConfig","envConfig","fileConfig","mergedConfig","import_zod","init_config","__esmMin","init_dist","init_env","filterJunk","filePaths","filePath","parts","basename","directorySegments","segment","JUNK_DIRECTORIES","junkDir","import_junk","init_junk","__esmMin","findCommonParent","dirPaths","normalizedPaths","p","pathSegments","commonSegments","minLength","i","segment","segments","normalizeWebPath","path","init_path","__esmMin","optimizeDeployPaths","filePaths","options","path","normalizeWebPath","extractFileName","commonPrefix","findCommonDirectory","filePath","deployPath","prefixToRemove","pathSegments","commonSegments","minLength","segments","i","segment","init_deploy_paths","__esmMin","init_path","node_files_exports","__export","processFilesForNode","findAllFilePaths","dirPath","visited","results","realPath","entries","entry","fullPath","stats","subFiles","paths","options","getENV","ShipError","absolutePaths","p","absPath","uniquePaths","validPaths","filterJunk","inputAbsolutePaths","inputBasePath","findCommonParent","relativePaths","filePath","rel","deployFiles","optimizeDeployPaths","totalSize","platformLimits","getCurrentConfig","i","deployPath","content","md5","calculateMD5","error","isShipError","errorMessage","fs","path","init_node_files","__esmMin","init_env","init_md5","init_junk","init_dist","init_platform_config","init_deploy_paths","init_path","import_commander","init_dist","SimpleEvents","event","handler","eventHandlers","args","handlerArray","error","target","handlers","ENDPOINTS","DEFAULT_REQUEST_TIMEOUT","ApiHttp","SimpleEvents","options","DEFAULT_API","target","url","operationName","headers","signal","cleanup","fetchOptions","response","error","err","data","customHeaders","existingSignal","controller","timeoutId","abort","errorData","json","obj","message","ShipError","isShipError","files","file","body","bodyHeaders","authHeaders","id","tags","name","deployment","status","ttl","token","indexFile","f","indexContent","init_dist","init_platform_config","init_dist","init_dist","resolveConfig","userOptions","loadedConfig","finalConfig","DEFAULT_API","result","mergeDeployOptions","options","clientDefaults","init_dist","init_md5","createSPAConfig","configString","content","md5","calculateMD5","DEPLOYMENT_CONFIG_FILENAME","detectAndConfigureSPA","files","apiClient","options","f","spaConfig","createDeploymentResource","ctx","getApi","ensureInit","processInput","clientDefaults","hasAuth","input","options","mergedOptions","mergeDeployOptions","ShipError","apiClient","staticFiles","detectAndConfigureSPA","id","createDomainResource","name","deployment","tags","createAccountResource","createTokenResource","token","Ship","options","config","ApiHttp","ctx","createDeploymentResource","input","createDomainResource","createAccountResource","createTokenResource","getCurrentConfig","event","handler","newClient","error","token","ShipError","key","init_dist","init_env","init_config","init_platform_config","init_dist","import_mime_db","extensionToMimeMap","type","mimeDb","mimeInfo","ext","getMimeType","path","extension","createDeployBody","files","tags","via","FormData","File","FormDataEncoder","formData","checksums","file","contentType","getMimeType","fileInstance","ShipError","preservedPath","encoder","chunks","chunk","body","Ship","options","getENV","ShipError","resolveConfig","loadedConfig","loadConfig","finalConfig","newClient","ApiHttp","platformConfig","setConfig","error","input","paths","p","processFilesForNode","createDeployBody","init_dist","import_fs","path","import_columnify","import_yoctocolors","INTERNAL_FIELDS","applyColor","colorFn","text","noColor","success","msg","isJson","error","errorPrefix","errorMsg","warn","warnPrefix","warnMsg","info","infoPrefix","infoMsg","formatTimestamp","timestamp","context","isoString","formatValue","key","value","mb","formatTable","data","columns","headerMap","firstItem","columnOrder","transformedData","item","record","transformed","col","columnify","config","heading","line","formatDetails","obj","entries","formatDeploymentsList","result","context","options","isJson","noColor","columns","formatTable","formatDomainsList","formatDomain","verb","success","info","record","_dnsRecords","_shareHash","displayResult","formatDetails","formatDeployment","formatAccount","formatMessage","formatDomainValidate","availabilityText","error","formatTokensList","formatToken","formatOutput","output","fs","path","os","detectShell","shell","getShellPaths","homeDir","installCompletion","scriptDir","options","isJson","noColor","error","paths","sourceScript","fishDir","success","info","sourceLine","content","prefix","warn","e","message","uninstallCompletion","lines","filtered","i","removed","endsWithNewline","newContent","init_dist","toShipError","err","isShipError","ShipError","getUserMessage","context","options","url","formatErrorJson","message","details","import_yoctocolors","loadPackageJson","paths","p","packageJson","program","err","globalOptions","message","error","displayHelp","str","noColor","applyBold","text","applyDim","output","collect","value","previous","mergeTagOption","cmdOptions","programOpts","tags","handleUnknownSubcommand","validSubcommands","args","processOptions","commandObj","unknownArg","arg","command","options","handleError","context","opts","shipError","toShipError","getUserMessage","formatErrorJson","withErrorHandling","handler","client","createClient","result","outputContext","errorContext","config","apiUrl","apiKey","deployToken","Ship","performDeploy","deployPath","commandContext","ShipError","stats","deployOptions","abortController","spinner","yoctoSpinner","sigintHandler","formatOutput","thisCommand","actionCommand","validateApiKey","validateDeployToken","validateApiUrl","validationError","isShipError","deploymentsCmd","deployment","id","domainsCmd","name","records","share","tokensCmd","token","accountCmd","completionCmd","scriptDir","installCompletion","uninstallCompletion","handleCompletion","isBash","isZsh","isFish","code","exitCode"]}