@layr-labs/ecloud-cli 0.4.3-dev → 0.4.3
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/VERSION +1 -1
- package/dist/commands/compute/app/deploy.js +1 -1
- package/dist/commands/compute/app/deploy.js.map +1 -1
- package/dist/commands/compute/app/info.js +1 -1
- package/dist/commands/compute/app/info.js.map +1 -1
- package/dist/commands/compute/app/list.js +1 -1
- package/dist/commands/compute/app/list.js.map +1 -1
- package/dist/commands/compute/app/logs.js +1 -1
- package/dist/commands/compute/app/logs.js.map +1 -1
- package/dist/commands/compute/app/profile/set.js +1 -1
- package/dist/commands/compute/app/profile/set.js.map +1 -1
- package/dist/commands/compute/app/releases.js +1 -1
- package/dist/commands/compute/app/releases.js.map +1 -1
- package/dist/commands/compute/app/start.js +1 -1
- package/dist/commands/compute/app/start.js.map +1 -1
- package/dist/commands/compute/app/stop.js +1 -1
- package/dist/commands/compute/app/stop.js.map +1 -1
- package/dist/commands/compute/app/terminate.js +1 -1
- package/dist/commands/compute/app/terminate.js.map +1 -1
- package/dist/commands/compute/app/upgrade.js +1 -1
- package/dist/commands/compute/app/upgrade.js.map +1 -1
- package/dist/commands/compute/build/info.js +1 -1
- package/dist/commands/compute/build/info.js.map +1 -1
- package/dist/commands/compute/build/list.js +1 -1
- package/dist/commands/compute/build/list.js.map +1 -1
- package/dist/commands/compute/build/logs.js +1 -1
- package/dist/commands/compute/build/logs.js.map +1 -1
- package/dist/commands/compute/build/status.js +1 -1
- package/dist/commands/compute/build/status.js.map +1 -1
- package/dist/commands/compute/build/submit.js +1 -1
- package/dist/commands/compute/build/submit.js.map +1 -1
- package/dist/commands/compute/build/verify.js +1 -1
- package/dist/commands/compute/build/verify.js.map +1 -1
- package/dist/commands/compute/undelegate.js +1 -1
- package/dist/commands/compute/undelegate.js.map +1 -1
- package/dist/hooks/init/__tests__/version-check.test.js +1 -1
- package/dist/hooks/init/__tests__/version-check.test.js.map +1 -1
- package/dist/hooks/init/version-check.js +1 -1
- package/dist/hooks/init/version-check.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/hooks/init/__tests__/version-check.test.ts","../../../../src/utils/version.ts","../../../../src/commands/upgrade.ts","../../../../src/telemetry.ts","../../../../src/utils/globalConfig.ts","../../../../src/hooks/init/version-check.ts"],"sourcesContent":["import { describe, it, expect, vi, beforeEach, type Mock } from \"vitest\";\n\nvi.mock(\"@inquirer/prompts\", () => ({\n confirm: vi.fn(),\n}));\n\nvi.mock(\"@layr-labs/ecloud-sdk\", () => ({\n getBuildType: vi.fn(() => \"prod\"),\n}));\n\nvi.mock(\"../../../utils/version\", () => ({\n getCliVersion: vi.fn(() => \"1.0.0\"),\n}));\n\nvi.mock(\"../../../commands/upgrade\", () => ({\n upgradePackage: vi.fn(),\n}));\n\nvi.mock(\"../../../utils/globalConfig\", () => ({\n loadGlobalConfig: vi.fn(() => ({})),\n saveGlobalConfig: vi.fn(),\n}));\n\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport { getCliVersion } from \"../../../utils/version\";\nimport { upgradePackage } from \"../../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../../utils/globalConfig\";\n\n// Import the hook - we need to call it manually\nimport hook from \"../version-check\";\n\nfunction createMockContext() {\n return {\n log: vi.fn(),\n exit: vi.fn(),\n };\n}\n\nfunction mockFetch(distTags: Record<string, string> | null, ok = true) {\n global.fetch = vi.fn().mockResolvedValue({\n ok,\n json: async () => (distTags ? { \"dist-tags\": distTags } : {}),\n });\n}\n\ndescribe(\"version-check init hook\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n (getCliVersion as Mock).mockReturnValue(\"1.0.0\");\n (getBuildType as Mock).mockReturnValue(\"prod\");\n (loadGlobalConfig as Mock).mockReturnValue({});\n (saveGlobalConfig as Mock).mockImplementation(() => {});\n });\n\n it(\"skips check for upgrade command\", async () => {\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"upgrade\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"skips check for version command\", async () => {\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"version\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"skips check for development builds\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"0.0.0\");\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does nothing when version is up to date\", async () => {\n mockFetch({ latest: \"1.0.0\" });\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does nothing when fetch fails\", async () => {\n global.fetch = vi.fn().mockRejectedValue(new Error(\"network error\"));\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"prompts user when new version is available\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(ctx.log).toHaveBeenCalled();\n expect(confirm).toHaveBeenCalled();\n expect(upgradePackage).not.toHaveBeenCalled();\n });\n\n it(\"upgrades when user confirms\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(true);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).toHaveBeenCalledWith(undefined, \"latest\");\n expect(ctx.exit).toHaveBeenCalledWith(0);\n });\n\n it(\"uses dev dist-tag for dev builds\", async () => {\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"2.0.0-dev.1\" });\n (confirm as Mock).mockResolvedValue(true);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).toHaveBeenCalledWith(undefined, \"dev\");\n });\n\n it(\"continues if upgrade fails\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(true);\n (upgradePackage as Mock).mockImplementation(() => {\n throw new Error(\"upgrade failed\");\n });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(ctx.exit).not.toHaveBeenCalled();\n expect(ctx.log).toHaveBeenCalledWith(expect.stringContaining(\"Upgrade failed\"));\n });\n\n it(\"detects newer major version\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects newer minor version\", async () => {\n mockFetch({ latest: \"1.1.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects newer patch version\", async () => {\n mockFetch({ latest: \"1.0.1\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"does not prompt when current is newer\", async () => {\n mockFetch({ latest: \"0.9.0\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"saves fetched version to global config\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(saveGlobalConfig).toHaveBeenCalledWith(\n expect.objectContaining({\n last_known_version: \"2.0.0\",\n last_version_check: expect.any(Number),\n }),\n );\n });\n\n it(\"uses cached version when check is fresh\", async () => {\n global.fetch = vi.fn();\n (loadGlobalConfig as Mock).mockReturnValue({\n last_version_check: Date.now() - 1000,\n last_known_version: \"2.0.0\",\n });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(global.fetch).not.toHaveBeenCalled();\n expect(confirm).toHaveBeenCalled();\n expect(ctx.log).toHaveBeenCalled();\n });\n\n it(\"detects newer dev prerelease version\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.2\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects release as newer than prerelease with same version\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"does not prompt when current dev prerelease is same as latest\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.1\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does not prompt when current dev prerelease is newer than latest\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.3\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.2\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does not re-prompt after user declines (snoozes for 24h)\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).not.toHaveBeenCalled();\n // Should save last_version_check to snooze the prompt\n expect(saveGlobalConfig).toHaveBeenLastCalledWith(\n expect.objectContaining({\n last_version_check: expect.any(Number),\n }),\n );\n // Verify the timestamp is recent (within last 5 seconds)\n const savedConfig = (saveGlobalConfig as Mock).mock.calls.at(-1)?.[0];\n expect(savedConfig.last_version_check).toBeGreaterThan(Date.now() - 5000);\n });\n\n it(\"re-fetches when cache is stale\", async () => {\n const twentyFiveHoursAgo = Date.now() - 25 * 60 * 60 * 1000;\n (loadGlobalConfig as Mock).mockReturnValue({\n last_version_check: twentyFiveHoursAgo,\n last_known_version: \"1.5.0\",\n });\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(global.fetch).toHaveBeenCalled();\n expect(saveGlobalConfig).toHaveBeenCalledWith(\n expect.objectContaining({\n last_known_version: \"2.0.0\",\n }),\n );\n });\n});\n","/**\n * CLI version utilities\n *\n * CLI_VERSION_BUILD_TIME is replaced at build time by tsup's define option\n */\n\n// @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time by tsup\ndeclare const CLI_VERSION_BUILD_TIME: string | undefined;\n\n/**\n * Get the CLI version\n */\nexport function getCliVersion(): string {\n // @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time\n return typeof CLI_VERSION_BUILD_TIME !== \"undefined\" ? CLI_VERSION_BUILD_TIME : \"0.0.0\";\n}\n\n/**\n * Get the x-client-id header value for API calls\n */\nexport function getClientId(): string {\n return `ecloud-cli/v${getCliVersion()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport chalk from \"chalk\";\nimport { withTelemetry } from \"../telemetry\";\n\n// Package being upgraded\nconst ecloudCLIPackage = \"@layr-labs/ecloud-cli\";\n\n// Possible PackManagers being covered\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"yarnBerry\" | \"bun\" | \"unknown\";\n\n// Detect package-manager from UA, check for bun as special case\nexport function detectPM(): PackageManager {\n const ua = process.env.npm_config_user_agent ?? \"\";\n\n if (ua.includes(\"pnpm/\")) return \"pnpm\";\n if (ua.includes(\"yarn/1\")) return \"yarn\";\n if (ua.match(/yarn\\/[23]/)) return \"yarnBerry\";\n if (ua.includes(\"npm/\")) return \"npm\";\n\n if (isBun()) return \"bun\";\n\n return \"unknown\";\n}\n\n// Detect bun using env falling back to checking for bun binary\nfunction isBun(): boolean {\n const execPath = process.execPath?.toLowerCase() ?? \"\";\n if (execPath.includes(\"bun\")) return true;\n\n if (process.env.BUN_INSTALL || process.env.BUN_RUNTIME) return true;\n\n try {\n const cmd = process.platform === \"win32\" ? \"where bun\" : \"which bun\";\n const p = execSync(cmd).toString().split(/\\r?\\n/)[0]?.trim();\n if (p && existsSync(p)) return true;\n } catch {\n // ignore\n }\n\n return false;\n}\n\n// Unified \"upgrade global to latest\" by manager\nexport function upgradePackage(packageManager?: string, buildTag = \"latest\"): void {\n const pm = packageManager ?? detectPM();\n\n const cmd = (() => {\n switch (pm) {\n case \"npm\":\n return `npm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"pnpm\":\n return `pnpm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"yarn\":\n return `yarn global add ${ecloudCLIPackage}@${buildTag}`;\n case \"yarnBerry\":\n // best effort, behaves more like a disposable global\n return `yarn dlx ${ecloudCLIPackage}@${buildTag}`;\n case \"bun\":\n return `bun add -g ${ecloudCLIPackage}@${buildTag}`;\n case \"unknown\":\n default:\n throw new Error();\n }\n })();\n\n execSync(cmd, { stdio: \"inherit\" });\n}\n\n// export Upgrade command to perform upgradePackage() call\nexport default class Upgrade extends Command {\n static description = \"Upgrade ecloud-cli package\";\n\n static flags = {\n \"package-manager\": Flags.string({\n required: false,\n description: \"Explicitly set package-manager to use for upgrade\",\n options: [\"npm\", \"pnpm\", \"yarn\", \"yarnBerry\", \"bun\"],\n env: \"PACKAGE_MANAGER\",\n }),\n };\n\n async run() {\n return withTelemetry(this, async () => {\n const { flags } = await this.parse(Upgrade);\n\n const buildType = getBuildType();\n const buildTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n try {\n upgradePackage(flags[\"package-manager\"], buildTag);\n this.log(`\\n${chalk.green(`Upgrade successful!`)}`);\n } catch (e) {\n this.log(`\\n${chalk.red(`Upgrade failed!`)}`);\n this.log(\n `\\n${chalk.red(`Cannot determine package manager to upgrade ${ecloudCLIPackage}.`)}`,\n );\n this.log(\n `\\n${chalk.red(`Use ${chalk.yellow(\"`package-manager`\")} flag to instruct upgrade (<supported managers: npm|pnpm|yarn|yarnBerry|bun>).`)}\\n`,\n );\n throw e;\n }\n });\n }\n}\n","/**\n * Telemetry utilities for CLI commands\n *\n * Provides helpers to wrap command execution with telemetry tracking\n */\n\nimport {\n createTelemetryClient,\n createAppEnvironment,\n createMetricsContext,\n addMetric,\n addMetricWithDimensions,\n emitMetrics,\n type TelemetryClient,\n getBuildType,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Command } from \"@oclif/core\";\nimport {\n getDefaultEnvironment,\n getOrCreateUserUUID,\n getGlobalTelemetryPreference,\n} from \"./utils/globalConfig\";\n\n/**\n * Create a telemetry client for CLI usage\n */\nexport function createCLITelemetryClient(): TelemetryClient {\n // Get user UUID from CLI's globalConfig (handles I/O)\n const userUUID = getOrCreateUserUUID();\n const environment = createAppEnvironment(userUUID);\n\n // Get telemetry preference from CLI's globalConfig\n const telemetryEnabled = getGlobalTelemetryPreference();\n\n return createTelemetryClient(environment, \"ecloud-cli\", {\n telemetryEnabled: telemetryEnabled !== false, // Enabled by default, disabled only if explicitly set to false\n });\n}\n\n/**\n * Wrap a command execution with telemetry\n *\n * @param command - The CLI command instance\n * @param action - The command action to execute\n * @returns The result of the action\n */\nexport async function withTelemetry<T>(command: Command, action: () => Promise<T>): Promise<T> {\n const client = createCLITelemetryClient();\n const metrics = createMetricsContext();\n\n // Set source to identify CLI usage\n metrics.properties[\"source\"] = \"ecloud-cli\";\n\n // Set command name in properties\n metrics.properties[\"command\"] = command.id || command.constructor.name;\n\n // Set environment in properties\n const environment = getDefaultEnvironment() || \"sepolia\";\n metrics.properties[\"environment\"] = environment;\n\n // Set buildType in properties\n const buildType = getBuildType() || \"prod\";\n metrics.properties[\"build_type\"] = buildType;\n\n // Set CLI version if available\n const cliVersion = command.config.version;\n if (cliVersion) {\n metrics.properties[\"cli_version\"] = cliVersion;\n }\n\n // Add initial count metric\n addMetric(metrics, \"Count\", 1);\n\n let actionError: Error | undefined;\n let result: T;\n\n try {\n result = await action();\n return result;\n } catch (err) {\n actionError = err instanceof Error ? err : new Error(String(err));\n throw err;\n } finally {\n // Add result metric\n const resultValue = actionError ? \"Failure\" : \"Success\";\n const dimensions: Record<string, string> = {};\n if (actionError) {\n dimensions[\"error\"] = actionError.message;\n }\n addMetricWithDimensions(metrics, resultValue, 1, dimensions);\n\n // Add duration metric\n const duration = Date.now() - metrics.startTime.getTime();\n addMetric(metrics, \"DurationMilliseconds\", duration);\n\n // Emit all metrics\n try {\n await emitMetrics(client, metrics);\n await client.close();\n } catch {\n // Silently ignore telemetry errors\n }\n }\n}\n","/**\n * Global configuration management\n *\n * Stores user-level configuration that persists across all CLI usage.\n * - $XDG_CONFIG_HOME/ecloud[BuildSuffix]/config.yaml (if XDG_CONFIG_HOME is set)\n * - Or ~/.config/ecloud[BuildSuffix]/config.yaml (fallback)\n *\n * Where BuildSuffix is:\n * - \"\" (empty) for production builds\n * - \"-dev\" for development builds\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { load as loadYaml, dump as dumpYaml } from \"js-yaml\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport * as crypto from \"crypto\";\nconst GLOBAL_CONFIG_FILE = \"config.yaml\";\n\nexport interface ProfileCacheEntry {\n updated_at: number; // Unix timestamp in milliseconds\n profiles: { [appId: string]: string }; // appId -> profile name\n}\n\nexport interface GlobalConfig {\n first_run?: boolean;\n telemetry_enabled?: boolean;\n user_uuid?: string;\n default_environment?: string;\n last_version_check?: number;\n last_known_version?: string;\n profile_cache?: {\n [environment: string]: ProfileCacheEntry;\n };\n directory_links?: {\n [environment: string]: {\n [directoryPath: string]: string;\n };\n };\n}\n\n// Profile cache TTL: 24 hours in milliseconds\nconst PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Get the XDG-compliant directory where global ecloud config should be stored\n */\nfunction getGlobalConfigDir(): string {\n // First check XDG_CONFIG_HOME\n const configHome = process.env.XDG_CONFIG_HOME;\n\n let baseDir: string;\n if (configHome && path.isAbsolute(configHome)) {\n baseDir = configHome;\n } else {\n // Fall back to ~/.config\n baseDir = path.join(os.homedir(), \".config\");\n }\n\n // Use environment-specific config directory\n const buildType = getBuildType();\n const buildSuffix = buildType === \"dev\" ? \"-dev\" : \"\";\n const configDirName = `ecloud${buildSuffix}`;\n\n return path.join(baseDir, configDirName);\n}\n\n/**\n * Get the full path to the global config file\n */\nfunction getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\n/**\n * Load global configuration, creating defaults if needed\n */\nexport function loadGlobalConfig(): GlobalConfig {\n const configPath = getGlobalConfigPath();\n\n // If file doesn't exist, return defaults for first run\n if (!fs.existsSync(configPath)) {\n return {\n first_run: true,\n };\n }\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n const config = loadYaml(content) as GlobalConfig;\n return config || { first_run: true };\n } catch {\n // If parsing fails, return defaults\n return {\n first_run: true,\n };\n }\n}\n\n/**\n * Save global configuration to disk\n */\nexport function saveGlobalConfig(config: GlobalConfig): void {\n const configPath = getGlobalConfigPath();\n\n // Ensure directory exists\n const configDir = path.dirname(configPath);\n fs.mkdirSync(configDir, { recursive: true, mode: 0o755 });\n\n // Write config file\n const content = dumpYaml(config, { lineWidth: -1 });\n fs.writeFileSync(configPath, content, { mode: 0o644 });\n}\n\nfunction normalizeDirectoryPath(directoryPath: string): string {\n const resolved = path.resolve(directoryPath);\n try {\n return fs.realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\n/**\n * Get linked app ID for a directory in an environment\n */\nexport function getLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n): string | null {\n if (!directoryPath) {\n return null;\n }\n\n const config = loadGlobalConfig();\n const links = config.directory_links?.[environment];\n if (!links) {\n return null;\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n const appId = links[normalizedPath];\n return appId || null;\n}\n\n/**\n * Link a directory to an app ID in an environment\n */\nexport function setLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n appId: string,\n): void {\n if (!directoryPath || !environment) {\n return;\n }\n\n const config = loadGlobalConfig();\n if (!config.directory_links) {\n config.directory_links = {};\n }\n if (!config.directory_links[environment]) {\n config.directory_links[environment] = {};\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n // Normalize appId to lowercase for consistent lookups\n config.directory_links[environment][normalizedPath] = appId.toLowerCase();\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user's preferred deployment environment\n */\nexport function getDefaultEnvironment(): string | undefined {\n const config = loadGlobalConfig();\n return config.default_environment;\n}\n\n/**\n * Set the user's preferred deployment environment\n */\nexport function setDefaultEnvironment(environment: string): void {\n const config = loadGlobalConfig();\n config.default_environment = environment;\n config.first_run = false; // No longer first run after setting environment\n saveGlobalConfig(config);\n}\n\n/**\n * Check if this is the user's first time running the CLI\n */\nexport function isFirstRun(): boolean {\n const config = loadGlobalConfig();\n return config.first_run === true;\n}\n\n/**\n * Mark that the first run has been completed\n */\nexport function markFirstRunComplete(): void {\n const config = loadGlobalConfig();\n config.first_run = false;\n saveGlobalConfig(config);\n}\n\n/**\n * Get the global telemetry preference\n */\nexport function getGlobalTelemetryPreference(): boolean | undefined {\n const config = loadGlobalConfig();\n return config.telemetry_enabled;\n}\n\n/**\n * Set the global telemetry preference\n */\nexport function setGlobalTelemetryPreference(enabled: boolean): void {\n const config = loadGlobalConfig();\n config.telemetry_enabled = enabled;\n config.first_run = false; // No longer first run after setting preference\n saveGlobalConfig(config);\n}\n\n// ==================== Profile Cache Functions ====================\n\n/**\n * Get cached profile names for an environment\n * Returns null if cache is missing or expired (older than 24 hours)\n */\nexport function getProfileCache(environment: string): Record<string, string> | null {\n const config = loadGlobalConfig();\n const cacheEntry = config.profile_cache?.[environment];\n\n if (!cacheEntry) {\n return null;\n }\n\n // Check if cache is expired\n const now = Date.now();\n if (now - cacheEntry.updated_at > PROFILE_CACHE_TTL_MS) {\n return null;\n }\n\n return cacheEntry.profiles;\n}\n\n/**\n * Set cached profile names for an environment\n */\nexport function setProfileCache(environment: string, profiles: Record<string, string>): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles,\n };\n\n saveGlobalConfig(config);\n}\n\n/**\n * Invalidate profile cache for a specific environment or all environments\n */\nexport function invalidateProfileCache(environment?: string): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n return;\n }\n\n if (environment) {\n // Invalidate specific environment\n delete config.profile_cache[environment];\n } else {\n // Invalidate all environments\n config.profile_cache = {};\n }\n\n saveGlobalConfig(config);\n}\n\n/**\n * Update a single profile name in the cache\n * This is useful after deploy or profile set to update just one entry\n */\nexport function updateProfileCacheEntry(\n environment: string,\n appId: string,\n profileName: string,\n): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n if (!config.profile_cache[environment]) {\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles: {},\n };\n }\n\n // Normalize appId to lowercase for consistent lookups\n const normalizedAppId = appId.toLowerCase();\n config.profile_cache[environment].profiles[normalizedAppId] = profileName;\n config.profile_cache[environment].updated_at = Date.now();\n\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user UUID from global config, or generate a new one if it doesn't exist\n */\nexport function getOrCreateUserUUID(): string {\n const config = loadGlobalConfig();\n if (config.user_uuid) {\n return config.user_uuid;\n }\n\n // Generate a new UUID (v4)\n const uuid = generateUUID();\n\n // Save it to config\n config.user_uuid = uuid;\n config.first_run = false;\n saveGlobalConfig(config);\n\n return uuid;\n}\n\n/**\n * Generate a UUID v4\n */\nfunction generateUUID(): string {\n // UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n // Use cryptographically secure random values.\n const bytes = crypto.randomBytes(16);\n // Per RFC 4122 section 4.4, set bits for version and `clock_seq_hi_and_reserved`\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\n return (\n hex.slice(0, 4).join(\"\") +\n hex.slice(4, 6).join(\"\") +\n \"-\" +\n hex.slice(6, 8).join(\"\") +\n \"-\" +\n hex.slice(8, 10).join(\"\") +\n \"-\" +\n hex.slice(10, 12).join(\"\") +\n \"-\" +\n hex.slice(12, 16).join(\"\")\n );\n}\n\n/**\n * Save user UUID to global config (preserves existing UUID if present)\n */\nexport function saveUserUUID(userUUID: string): void {\n const config = loadGlobalConfig();\n // Only update if not already set\n if (!config.user_uuid) {\n config.user_uuid = userUUID;\n saveGlobalConfig(config);\n }\n}\n","import { Hook } from \"@oclif/core\";\nimport chalk from \"chalk\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport { getCliVersion } from \"../../utils/version\";\nimport { upgradePackage } from \"../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../utils/globalConfig\";\n\nconst SKIP_COMMANDS = new Set([\"upgrade\", \"version\"]);\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@layr-labs/ecloud-cli\";\nconst VERSION_CHECK_TIMEOUT_MS = 3000;\nconst VERSION_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\nfunction parseVersion(v: string): { major: number; minor: number; patch: number; prerelease: string | null } {\n const clean = v.replace(/^v/, \"\");\n const [core, ...rest] = clean.split(\"-\");\n const [major = 0, minor = 0, patch = 0] = core.split(\".\").map(Number);\n const prerelease = rest.length > 0 ? rest.join(\"-\") : null;\n return { major, minor, patch, prerelease };\n}\n\nfunction comparePrerelease(a: string | null, b: string | null): number {\n // No prerelease = release, which is higher than any prerelease\n if (a === null && b === null) return 0;\n if (a === null) return 1; // a is release, b is prerelease → a > b\n if (b === null) return -1; // a is prerelease, b is release → a < b\n\n // Compare prerelease segments (e.g. \"dev.1\" vs \"dev.2\")\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i];\n const bp = bParts[i];\n if (ap === undefined) return -1;\n if (bp === undefined) return 1;\n const aNum = Number(ap);\n const bNum = Number(bp);\n if (!isNaN(aNum) && !isNaN(bNum)) {\n if (aNum !== bNum) return aNum - bNum;\n } else {\n if (ap < bp) return -1;\n if (ap > bp) return 1;\n }\n }\n return 0;\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const c = parseVersion(current);\n const l = parseVersion(latest);\n\n if (l.major !== c.major) return l.major > c.major;\n if (l.minor !== c.minor) return l.minor > c.minor;\n if (l.patch !== c.patch) return l.patch > c.patch;\n return comparePrerelease(l.prerelease, c.prerelease) > 0;\n}\n\nasync function fetchLatestVersion(distTag: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), VERSION_CHECK_TIMEOUT_MS);\n\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { \"dist-tags\"?: Record<string, string> };\n return data[\"dist-tags\"]?.[distTag] ?? null;\n } catch {\n return null;\n }\n}\n\nconst hook: Hook<\"init\"> = async function (options) {\n const commandId = options.id;\n if (!commandId || SKIP_COMMANDS.has(commandId)) return;\n\n const currentVersion = getCliVersion();\n // Don't check for unpublished/development builds\n if (currentVersion === \"0.0.0\" || currentVersion === \"0.0.0-development\") return;\n\n const buildType = getBuildType();\n const distTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n const globalConfig = loadGlobalConfig();\n const now = Date.now();\n const cacheIsFresh =\n globalConfig.last_version_check != null &&\n now - globalConfig.last_version_check < VERSION_CHECK_INTERVAL_MS;\n\n let latestVersion: string | null;\n if (cacheIsFresh && globalConfig.last_known_version) {\n latestVersion = globalConfig.last_known_version;\n } else {\n latestVersion = await fetchLatestVersion(distTag);\n if (latestVersion) {\n globalConfig.last_version_check = now;\n globalConfig.last_known_version = latestVersion;\n saveGlobalConfig(globalConfig);\n }\n }\n\n if (!latestVersion || !isNewerVersion(currentVersion, latestVersion)) return;\n\n this.log(\n chalk.yellow(\n `\\nA new version of ecloud-cli is available: ${chalk.red(currentVersion)} -> ${chalk.green(latestVersion)}`,\n ),\n );\n\n const shouldUpdate = await confirm({\n message: \"Would you like to update now?\",\n default: true,\n });\n\n if (shouldUpdate) {\n try {\n upgradePackage(undefined, distTag);\n this.log(`\\n${chalk.green(\"Upgrade successful!\")}`);\n this.exit(0);\n } catch {\n this.log(`\\n${chalk.yellow(\"Upgrade failed. Continuing with current version...\")}\\n`);\n }\n } else {\n // Snooze the prompt for another 24 hours\n globalConfig.last_version_check = now;\n saveGlobalConfig(globalConfig);\n }\n};\n\nexport default hook;\n"],"mappings":"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","names":["confirm","getBuildType","existsSync","getBuildType","getBuildType","getBuildType","existsSync","getBuildType","chalk","getBuildType","getBuildType","chalk","getBuildType","confirm"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/hooks/init/__tests__/version-check.test.ts","../../../../src/utils/version.ts","../../../../src/commands/upgrade.ts","../../../../src/telemetry.ts","../../../../src/utils/globalConfig.ts","../../../../src/hooks/init/version-check.ts"],"sourcesContent":["import { describe, it, expect, vi, beforeEach, type Mock } from \"vitest\";\n\nvi.mock(\"@inquirer/prompts\", () => ({\n confirm: vi.fn(),\n}));\n\nvi.mock(\"@layr-labs/ecloud-sdk\", () => ({\n getBuildType: vi.fn(() => \"prod\"),\n}));\n\nvi.mock(\"../../../utils/version\", () => ({\n getCliVersion: vi.fn(() => \"1.0.0\"),\n}));\n\nvi.mock(\"../../../commands/upgrade\", () => ({\n upgradePackage: vi.fn(),\n}));\n\nvi.mock(\"../../../utils/globalConfig\", () => ({\n loadGlobalConfig: vi.fn(() => ({})),\n saveGlobalConfig: vi.fn(),\n}));\n\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport { getCliVersion } from \"../../../utils/version\";\nimport { upgradePackage } from \"../../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../../utils/globalConfig\";\n\n// Import the hook - we need to call it manually\nimport hook from \"../version-check\";\n\nfunction createMockContext() {\n return {\n log: vi.fn(),\n exit: vi.fn(),\n };\n}\n\nfunction mockFetch(distTags: Record<string, string> | null, ok = true) {\n global.fetch = vi.fn().mockResolvedValue({\n ok,\n json: async () => (distTags ? { \"dist-tags\": distTags } : {}),\n });\n}\n\ndescribe(\"version-check init hook\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n (getCliVersion as Mock).mockReturnValue(\"1.0.0\");\n (getBuildType as Mock).mockReturnValue(\"prod\");\n (loadGlobalConfig as Mock).mockReturnValue({});\n (saveGlobalConfig as Mock).mockImplementation(() => {});\n });\n\n it(\"skips check for upgrade command\", async () => {\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"upgrade\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"skips check for version command\", async () => {\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"version\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"skips check for development builds\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"0.0.0\");\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does nothing when version is up to date\", async () => {\n mockFetch({ latest: \"1.0.0\" });\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does nothing when fetch fails\", async () => {\n global.fetch = vi.fn().mockRejectedValue(new Error(\"network error\"));\n const ctx = createMockContext();\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"prompts user when new version is available\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(ctx.log).toHaveBeenCalled();\n expect(confirm).toHaveBeenCalled();\n expect(upgradePackage).not.toHaveBeenCalled();\n });\n\n it(\"upgrades when user confirms\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(true);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).toHaveBeenCalledWith(undefined, \"latest\");\n expect(ctx.exit).toHaveBeenCalledWith(0);\n });\n\n it(\"uses dev dist-tag for dev builds\", async () => {\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"2.0.0-dev.1\" });\n (confirm as Mock).mockResolvedValue(true);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).toHaveBeenCalledWith(undefined, \"dev\");\n });\n\n it(\"continues if upgrade fails\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(true);\n (upgradePackage as Mock).mockImplementation(() => {\n throw new Error(\"upgrade failed\");\n });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(ctx.exit).not.toHaveBeenCalled();\n expect(ctx.log).toHaveBeenCalledWith(expect.stringContaining(\"Upgrade failed\"));\n });\n\n it(\"detects newer major version\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects newer minor version\", async () => {\n mockFetch({ latest: \"1.1.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects newer patch version\", async () => {\n mockFetch({ latest: \"1.0.1\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"does not prompt when current is newer\", async () => {\n mockFetch({ latest: \"0.9.0\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"saves fetched version to global config\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(saveGlobalConfig).toHaveBeenCalledWith(\n expect.objectContaining({\n last_known_version: \"2.0.0\",\n last_version_check: expect.any(Number),\n }),\n );\n });\n\n it(\"uses cached version when check is fresh\", async () => {\n global.fetch = vi.fn();\n (loadGlobalConfig as Mock).mockReturnValue({\n last_version_check: Date.now() - 1000,\n last_known_version: \"2.0.0\",\n });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(global.fetch).not.toHaveBeenCalled();\n expect(confirm).toHaveBeenCalled();\n expect(ctx.log).toHaveBeenCalled();\n });\n\n it(\"detects newer dev prerelease version\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.2\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"detects release as newer than prerelease with same version\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(confirm).toHaveBeenCalled();\n });\n\n it(\"does not prompt when current dev prerelease is same as latest\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.1\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.1\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does not prompt when current dev prerelease is newer than latest\", async () => {\n (getCliVersion as Mock).mockReturnValue(\"1.0.0-dev.3\");\n (getBuildType as Mock).mockReturnValue(\"dev\");\n mockFetch({ dev: \"1.0.0-dev.2\" });\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n expect(ctx.log).not.toHaveBeenCalled();\n });\n\n it(\"does not re-prompt after user declines (snoozes for 24h)\", async () => {\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(upgradePackage).not.toHaveBeenCalled();\n // Should save last_version_check to snooze the prompt\n expect(saveGlobalConfig).toHaveBeenLastCalledWith(\n expect.objectContaining({\n last_version_check: expect.any(Number),\n }),\n );\n // Verify the timestamp is recent (within last 5 seconds)\n const savedConfig = (saveGlobalConfig as Mock).mock.calls.at(-1)?.[0];\n expect(savedConfig.last_version_check).toBeGreaterThan(Date.now() - 5000);\n });\n\n it(\"re-fetches when cache is stale\", async () => {\n const twentyFiveHoursAgo = Date.now() - 25 * 60 * 60 * 1000;\n (loadGlobalConfig as Mock).mockReturnValue({\n last_version_check: twentyFiveHoursAgo,\n last_known_version: \"1.5.0\",\n });\n mockFetch({ latest: \"2.0.0\" });\n (confirm as Mock).mockResolvedValue(false);\n const ctx = createMockContext();\n\n await hook.call(ctx as any, { id: \"auth:login\" } as any);\n\n expect(global.fetch).toHaveBeenCalled();\n expect(saveGlobalConfig).toHaveBeenCalledWith(\n expect.objectContaining({\n last_known_version: \"2.0.0\",\n }),\n );\n });\n});\n","/**\n * CLI version utilities\n *\n * CLI_VERSION_BUILD_TIME is replaced at build time by tsup's define option\n */\n\n// @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time by tsup\ndeclare const CLI_VERSION_BUILD_TIME: string | undefined;\n\n/**\n * Get the CLI version\n */\nexport function getCliVersion(): string {\n // @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time\n return typeof CLI_VERSION_BUILD_TIME !== \"undefined\" ? CLI_VERSION_BUILD_TIME : \"0.0.0\";\n}\n\n/**\n * Get the x-client-id header value for API calls\n */\nexport function getClientId(): string {\n return `ecloud-cli/v${getCliVersion()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport chalk from \"chalk\";\nimport { withTelemetry } from \"../telemetry\";\n\n// Package being upgraded\nconst ecloudCLIPackage = \"@layr-labs/ecloud-cli\";\n\n// Possible PackManagers being covered\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"yarnBerry\" | \"bun\" | \"unknown\";\n\n// Detect package-manager from UA, check for bun as special case\nexport function detectPM(): PackageManager {\n const ua = process.env.npm_config_user_agent ?? \"\";\n\n if (ua.includes(\"pnpm/\")) return \"pnpm\";\n if (ua.includes(\"yarn/1\")) return \"yarn\";\n if (ua.match(/yarn\\/[23]/)) return \"yarnBerry\";\n if (ua.includes(\"npm/\")) return \"npm\";\n\n if (isBun()) return \"bun\";\n\n return \"unknown\";\n}\n\n// Detect bun using env falling back to checking for bun binary\nfunction isBun(): boolean {\n const execPath = process.execPath?.toLowerCase() ?? \"\";\n if (execPath.includes(\"bun\")) return true;\n\n if (process.env.BUN_INSTALL || process.env.BUN_RUNTIME) return true;\n\n try {\n const cmd = process.platform === \"win32\" ? \"where bun\" : \"which bun\";\n const p = execSync(cmd).toString().split(/\\r?\\n/)[0]?.trim();\n if (p && existsSync(p)) return true;\n } catch {\n // ignore\n }\n\n return false;\n}\n\n// Unified \"upgrade global to latest\" by manager\nexport function upgradePackage(packageManager?: string, buildTag = \"latest\"): void {\n const pm = packageManager ?? detectPM();\n\n const cmd = (() => {\n switch (pm) {\n case \"npm\":\n return `npm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"pnpm\":\n return `pnpm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"yarn\":\n return `yarn global add ${ecloudCLIPackage}@${buildTag}`;\n case \"yarnBerry\":\n // best effort, behaves more like a disposable global\n return `yarn dlx ${ecloudCLIPackage}@${buildTag}`;\n case \"bun\":\n return `bun add -g ${ecloudCLIPackage}@${buildTag}`;\n case \"unknown\":\n default:\n throw new Error();\n }\n })();\n\n execSync(cmd, { stdio: \"inherit\" });\n}\n\n// export Upgrade command to perform upgradePackage() call\nexport default class Upgrade extends Command {\n static description = \"Upgrade ecloud-cli package\";\n\n static flags = {\n \"package-manager\": Flags.string({\n required: false,\n description: \"Explicitly set package-manager to use for upgrade\",\n options: [\"npm\", \"pnpm\", \"yarn\", \"yarnBerry\", \"bun\"],\n env: \"PACKAGE_MANAGER\",\n }),\n };\n\n async run() {\n return withTelemetry(this, async () => {\n const { flags } = await this.parse(Upgrade);\n\n const buildType = getBuildType();\n const buildTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n try {\n upgradePackage(flags[\"package-manager\"], buildTag);\n this.log(`\\n${chalk.green(`Upgrade successful!`)}`);\n } catch (e) {\n this.log(`\\n${chalk.red(`Upgrade failed!`)}`);\n this.log(\n `\\n${chalk.red(`Cannot determine package manager to upgrade ${ecloudCLIPackage}.`)}`,\n );\n this.log(\n `\\n${chalk.red(`Use ${chalk.yellow(\"`package-manager`\")} flag to instruct upgrade (<supported managers: npm|pnpm|yarn|yarnBerry|bun>).`)}\\n`,\n );\n throw e;\n }\n });\n }\n}\n","/**\n * Telemetry utilities for CLI commands\n *\n * Provides helpers to wrap command execution with telemetry tracking\n */\n\nimport {\n createTelemetryClient,\n createAppEnvironment,\n createMetricsContext,\n addMetric,\n addMetricWithDimensions,\n emitMetrics,\n type TelemetryClient,\n getBuildType,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Command } from \"@oclif/core\";\nimport {\n getDefaultEnvironment,\n getOrCreateUserUUID,\n getGlobalTelemetryPreference,\n} from \"./utils/globalConfig\";\n\n/**\n * Create a telemetry client for CLI usage\n */\nexport function createCLITelemetryClient(): TelemetryClient {\n // Get user UUID from CLI's globalConfig (handles I/O)\n const userUUID = getOrCreateUserUUID();\n const environment = createAppEnvironment(userUUID);\n\n // Get telemetry preference from CLI's globalConfig\n const telemetryEnabled = getGlobalTelemetryPreference();\n\n return createTelemetryClient(environment, \"ecloud-cli\", {\n telemetryEnabled: telemetryEnabled !== false, // Enabled by default, disabled only if explicitly set to false\n });\n}\n\n/**\n * Wrap a command execution with telemetry\n *\n * @param command - The CLI command instance\n * @param action - The command action to execute\n * @returns The result of the action\n */\nexport async function withTelemetry<T>(command: Command, action: () => Promise<T>): Promise<T> {\n const client = createCLITelemetryClient();\n const metrics = createMetricsContext();\n\n // Set source to identify CLI usage\n metrics.properties[\"source\"] = \"ecloud-cli\";\n\n // Set command name in properties\n metrics.properties[\"command\"] = command.id || command.constructor.name;\n\n // Set environment in properties\n const environment = getDefaultEnvironment() || \"sepolia\";\n metrics.properties[\"environment\"] = environment;\n\n // Set buildType in properties\n const buildType = getBuildType() || \"prod\";\n metrics.properties[\"build_type\"] = buildType;\n\n // Set CLI version if available\n const cliVersion = command.config.version;\n if (cliVersion) {\n metrics.properties[\"cli_version\"] = cliVersion;\n }\n\n // Add initial count metric\n addMetric(metrics, \"Count\", 1);\n\n let actionError: Error | undefined;\n let result: T;\n\n try {\n result = await action();\n return result;\n } catch (err) {\n actionError = err instanceof Error ? err : new Error(String(err));\n throw err;\n } finally {\n // Add result metric\n const resultValue = actionError ? \"Failure\" : \"Success\";\n const dimensions: Record<string, string> = {};\n if (actionError) {\n dimensions[\"error\"] = actionError.message;\n }\n addMetricWithDimensions(metrics, resultValue, 1, dimensions);\n\n // Add duration metric\n const duration = Date.now() - metrics.startTime.getTime();\n addMetric(metrics, \"DurationMilliseconds\", duration);\n\n // Emit all metrics\n try {\n await emitMetrics(client, metrics);\n await client.close();\n } catch {\n // Silently ignore telemetry errors\n }\n }\n}\n","/**\n * Global configuration management\n *\n * Stores user-level configuration that persists across all CLI usage.\n * - $XDG_CONFIG_HOME/ecloud[BuildSuffix]/config.yaml (if XDG_CONFIG_HOME is set)\n * - Or ~/.config/ecloud[BuildSuffix]/config.yaml (fallback)\n *\n * Where BuildSuffix is:\n * - \"\" (empty) for production builds\n * - \"-dev\" for development builds\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { load as loadYaml, dump as dumpYaml } from \"js-yaml\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport * as crypto from \"crypto\";\nconst GLOBAL_CONFIG_FILE = \"config.yaml\";\n\nexport interface ProfileCacheEntry {\n updated_at: number; // Unix timestamp in milliseconds\n profiles: { [appId: string]: string }; // appId -> profile name\n}\n\nexport interface GlobalConfig {\n first_run?: boolean;\n telemetry_enabled?: boolean;\n user_uuid?: string;\n default_environment?: string;\n last_version_check?: number;\n last_known_version?: string;\n profile_cache?: {\n [environment: string]: ProfileCacheEntry;\n };\n directory_links?: {\n [environment: string]: {\n [directoryPath: string]: string;\n };\n };\n}\n\n// Profile cache TTL: 24 hours in milliseconds\nconst PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Get the XDG-compliant directory where global ecloud config should be stored\n */\nfunction getGlobalConfigDir(): string {\n // First check XDG_CONFIG_HOME\n const configHome = process.env.XDG_CONFIG_HOME;\n\n let baseDir: string;\n if (configHome && path.isAbsolute(configHome)) {\n baseDir = configHome;\n } else {\n // Fall back to ~/.config\n baseDir = path.join(os.homedir(), \".config\");\n }\n\n // Use environment-specific config directory\n const buildType = getBuildType();\n const buildSuffix = buildType === \"dev\" ? \"-dev\" : \"\";\n const configDirName = `ecloud${buildSuffix}`;\n\n return path.join(baseDir, configDirName);\n}\n\n/**\n * Get the full path to the global config file\n */\nfunction getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\n/**\n * Load global configuration, creating defaults if needed\n */\nexport function loadGlobalConfig(): GlobalConfig {\n const configPath = getGlobalConfigPath();\n\n // If file doesn't exist, return defaults for first run\n if (!fs.existsSync(configPath)) {\n return {\n first_run: true,\n };\n }\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n const config = loadYaml(content) as GlobalConfig;\n return config || { first_run: true };\n } catch {\n // If parsing fails, return defaults\n return {\n first_run: true,\n };\n }\n}\n\n/**\n * Save global configuration to disk\n */\nexport function saveGlobalConfig(config: GlobalConfig): void {\n const configPath = getGlobalConfigPath();\n\n // Ensure directory exists\n const configDir = path.dirname(configPath);\n fs.mkdirSync(configDir, { recursive: true, mode: 0o755 });\n\n // Write config file\n const content = dumpYaml(config, { lineWidth: -1 });\n fs.writeFileSync(configPath, content, { mode: 0o644 });\n}\n\nfunction normalizeDirectoryPath(directoryPath: string): string {\n const resolved = path.resolve(directoryPath);\n try {\n return fs.realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\n/**\n * Get linked app ID for a directory in an environment\n */\nexport function getLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n): string | null {\n if (!directoryPath) {\n return null;\n }\n\n const config = loadGlobalConfig();\n const links = config.directory_links?.[environment];\n if (!links) {\n return null;\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n const appId = links[normalizedPath];\n return appId || null;\n}\n\n/**\n * Link a directory to an app ID in an environment\n */\nexport function setLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n appId: string,\n): void {\n if (!directoryPath || !environment) {\n return;\n }\n\n const config = loadGlobalConfig();\n if (!config.directory_links) {\n config.directory_links = {};\n }\n if (!config.directory_links[environment]) {\n config.directory_links[environment] = {};\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n // Normalize appId to lowercase for consistent lookups\n config.directory_links[environment][normalizedPath] = appId.toLowerCase();\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user's preferred deployment environment\n */\nexport function getDefaultEnvironment(): string | undefined {\n const config = loadGlobalConfig();\n return config.default_environment;\n}\n\n/**\n * Set the user's preferred deployment environment\n */\nexport function setDefaultEnvironment(environment: string): void {\n const config = loadGlobalConfig();\n config.default_environment = environment;\n config.first_run = false; // No longer first run after setting environment\n saveGlobalConfig(config);\n}\n\n/**\n * Check if this is the user's first time running the CLI\n */\nexport function isFirstRun(): boolean {\n const config = loadGlobalConfig();\n return config.first_run === true;\n}\n\n/**\n * Mark that the first run has been completed\n */\nexport function markFirstRunComplete(): void {\n const config = loadGlobalConfig();\n config.first_run = false;\n saveGlobalConfig(config);\n}\n\n/**\n * Get the global telemetry preference\n */\nexport function getGlobalTelemetryPreference(): boolean | undefined {\n const config = loadGlobalConfig();\n return config.telemetry_enabled;\n}\n\n/**\n * Set the global telemetry preference\n */\nexport function setGlobalTelemetryPreference(enabled: boolean): void {\n const config = loadGlobalConfig();\n config.telemetry_enabled = enabled;\n config.first_run = false; // No longer first run after setting preference\n saveGlobalConfig(config);\n}\n\n// ==================== Profile Cache Functions ====================\n\n/**\n * Get cached profile names for an environment\n * Returns null if cache is missing or expired (older than 24 hours)\n */\nexport function getProfileCache(environment: string): Record<string, string> | null {\n const config = loadGlobalConfig();\n const cacheEntry = config.profile_cache?.[environment];\n\n if (!cacheEntry) {\n return null;\n }\n\n // Check if cache is expired\n const now = Date.now();\n if (now - cacheEntry.updated_at > PROFILE_CACHE_TTL_MS) {\n return null;\n }\n\n return cacheEntry.profiles;\n}\n\n/**\n * Set cached profile names for an environment\n */\nexport function setProfileCache(environment: string, profiles: Record<string, string>): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles,\n };\n\n saveGlobalConfig(config);\n}\n\n/**\n * Invalidate profile cache for a specific environment or all environments\n */\nexport function invalidateProfileCache(environment?: string): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n return;\n }\n\n if (environment) {\n // Invalidate specific environment\n delete config.profile_cache[environment];\n } else {\n // Invalidate all environments\n config.profile_cache = {};\n }\n\n saveGlobalConfig(config);\n}\n\n/**\n * Update a single profile name in the cache\n * This is useful after deploy or profile set to update just one entry\n */\nexport function updateProfileCacheEntry(\n environment: string,\n appId: string,\n profileName: string,\n): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n if (!config.profile_cache[environment]) {\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles: {},\n };\n }\n\n // Normalize appId to lowercase for consistent lookups\n const normalizedAppId = appId.toLowerCase();\n config.profile_cache[environment].profiles[normalizedAppId] = profileName;\n config.profile_cache[environment].updated_at = Date.now();\n\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user UUID from global config, or generate a new one if it doesn't exist\n */\nexport function getOrCreateUserUUID(): string {\n const config = loadGlobalConfig();\n if (config.user_uuid) {\n return config.user_uuid;\n }\n\n // Generate a new UUID (v4)\n const uuid = generateUUID();\n\n // Save it to config\n config.user_uuid = uuid;\n config.first_run = false;\n saveGlobalConfig(config);\n\n return uuid;\n}\n\n/**\n * Generate a UUID v4\n */\nfunction generateUUID(): string {\n // UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n // Use cryptographically secure random values.\n const bytes = crypto.randomBytes(16);\n // Per RFC 4122 section 4.4, set bits for version and `clock_seq_hi_and_reserved`\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\n return (\n hex.slice(0, 4).join(\"\") +\n hex.slice(4, 6).join(\"\") +\n \"-\" +\n hex.slice(6, 8).join(\"\") +\n \"-\" +\n hex.slice(8, 10).join(\"\") +\n \"-\" +\n hex.slice(10, 12).join(\"\") +\n \"-\" +\n hex.slice(12, 16).join(\"\")\n );\n}\n\n/**\n * Save user UUID to global config (preserves existing UUID if present)\n */\nexport function saveUserUUID(userUUID: string): void {\n const config = loadGlobalConfig();\n // Only update if not already set\n if (!config.user_uuid) {\n config.user_uuid = userUUID;\n saveGlobalConfig(config);\n }\n}\n","import { Hook } from \"@oclif/core\";\nimport chalk from \"chalk\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport { getCliVersion } from \"../../utils/version\";\nimport { upgradePackage } from \"../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../utils/globalConfig\";\n\nconst SKIP_COMMANDS = new Set([\"upgrade\", \"version\"]);\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@layr-labs/ecloud-cli\";\nconst VERSION_CHECK_TIMEOUT_MS = 3000;\nconst VERSION_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\nfunction parseVersion(v: string): { major: number; minor: number; patch: number; prerelease: string | null } {\n const clean = v.replace(/^v/, \"\");\n const [core, ...rest] = clean.split(\"-\");\n const [major = 0, minor = 0, patch = 0] = core.split(\".\").map(Number);\n const prerelease = rest.length > 0 ? rest.join(\"-\") : null;\n return { major, minor, patch, prerelease };\n}\n\nfunction comparePrerelease(a: string | null, b: string | null): number {\n // No prerelease = release, which is higher than any prerelease\n if (a === null && b === null) return 0;\n if (a === null) return 1; // a is release, b is prerelease → a > b\n if (b === null) return -1; // a is prerelease, b is release → a < b\n\n // Compare prerelease segments (e.g. \"dev.1\" vs \"dev.2\")\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i];\n const bp = bParts[i];\n if (ap === undefined) return -1;\n if (bp === undefined) return 1;\n const aNum = Number(ap);\n const bNum = Number(bp);\n if (!isNaN(aNum) && !isNaN(bNum)) {\n if (aNum !== bNum) return aNum - bNum;\n } else {\n if (ap < bp) return -1;\n if (ap > bp) return 1;\n }\n }\n return 0;\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const c = parseVersion(current);\n const l = parseVersion(latest);\n\n if (l.major !== c.major) return l.major > c.major;\n if (l.minor !== c.minor) return l.minor > c.minor;\n if (l.patch !== c.patch) return l.patch > c.patch;\n return comparePrerelease(l.prerelease, c.prerelease) > 0;\n}\n\nasync function fetchLatestVersion(distTag: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), VERSION_CHECK_TIMEOUT_MS);\n\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { \"dist-tags\"?: Record<string, string> };\n return data[\"dist-tags\"]?.[distTag] ?? null;\n } catch {\n return null;\n }\n}\n\nconst hook: Hook<\"init\"> = async function (options) {\n const commandId = options.id;\n if (!commandId || SKIP_COMMANDS.has(commandId)) return;\n\n const currentVersion = getCliVersion();\n // Don't check for unpublished/development builds\n if (currentVersion === \"0.0.0\" || currentVersion === \"0.0.0-development\") return;\n\n const buildType = getBuildType();\n const distTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n const globalConfig = loadGlobalConfig();\n const now = Date.now();\n const cacheIsFresh =\n globalConfig.last_version_check != null &&\n now - globalConfig.last_version_check < VERSION_CHECK_INTERVAL_MS;\n\n let latestVersion: string | null;\n if (cacheIsFresh && globalConfig.last_known_version) {\n latestVersion = globalConfig.last_known_version;\n } else {\n latestVersion = await fetchLatestVersion(distTag);\n if (latestVersion) {\n globalConfig.last_version_check = now;\n globalConfig.last_known_version = latestVersion;\n saveGlobalConfig(globalConfig);\n }\n }\n\n if (!latestVersion || !isNewerVersion(currentVersion, latestVersion)) return;\n\n this.log(\n chalk.yellow(\n `\\nA new version of ecloud-cli is available: ${chalk.red(currentVersion)} -> ${chalk.green(latestVersion)}`,\n ),\n );\n\n const shouldUpdate = await confirm({\n message: \"Would you like to update now?\",\n default: true,\n });\n\n if (shouldUpdate) {\n try {\n upgradePackage(undefined, distTag);\n this.log(`\\n${chalk.green(\"Upgrade successful!\")}`);\n this.exit(0);\n } catch {\n this.log(`\\n${chalk.yellow(\"Upgrade failed. Continuing with current version...\")}\\n`);\n }\n } else {\n // Snooze the prompt for another 24 hours\n globalConfig.last_version_check = now;\n saveGlobalConfig(globalConfig);\n }\n};\n\nexport default hook;\n"],"mappings":"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","names":["confirm","getBuildType","existsSync","getBuildType","getBuildType","getBuildType","existsSync","getBuildType","chalk","getBuildType","getBuildType","chalk","getBuildType","confirm"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/init/version-check.ts","../../../src/utils/version.ts","../../../src/commands/upgrade.ts","../../../src/telemetry.ts","../../../src/utils/globalConfig.ts"],"sourcesContent":["import { Hook } from \"@oclif/core\";\nimport chalk from \"chalk\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport { getCliVersion } from \"../../utils/version\";\nimport { upgradePackage } from \"../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../utils/globalConfig\";\n\nconst SKIP_COMMANDS = new Set([\"upgrade\", \"version\"]);\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@layr-labs/ecloud-cli\";\nconst VERSION_CHECK_TIMEOUT_MS = 3000;\nconst VERSION_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\nfunction parseVersion(v: string): { major: number; minor: number; patch: number; prerelease: string | null } {\n const clean = v.replace(/^v/, \"\");\n const [core, ...rest] = clean.split(\"-\");\n const [major = 0, minor = 0, patch = 0] = core.split(\".\").map(Number);\n const prerelease = rest.length > 0 ? rest.join(\"-\") : null;\n return { major, minor, patch, prerelease };\n}\n\nfunction comparePrerelease(a: string | null, b: string | null): number {\n // No prerelease = release, which is higher than any prerelease\n if (a === null && b === null) return 0;\n if (a === null) return 1; // a is release, b is prerelease → a > b\n if (b === null) return -1; // a is prerelease, b is release → a < b\n\n // Compare prerelease segments (e.g. \"dev.1\" vs \"dev.2\")\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i];\n const bp = bParts[i];\n if (ap === undefined) return -1;\n if (bp === undefined) return 1;\n const aNum = Number(ap);\n const bNum = Number(bp);\n if (!isNaN(aNum) && !isNaN(bNum)) {\n if (aNum !== bNum) return aNum - bNum;\n } else {\n if (ap < bp) return -1;\n if (ap > bp) return 1;\n }\n }\n return 0;\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const c = parseVersion(current);\n const l = parseVersion(latest);\n\n if (l.major !== c.major) return l.major > c.major;\n if (l.minor !== c.minor) return l.minor > c.minor;\n if (l.patch !== c.patch) return l.patch > c.patch;\n return comparePrerelease(l.prerelease, c.prerelease) > 0;\n}\n\nasync function fetchLatestVersion(distTag: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), VERSION_CHECK_TIMEOUT_MS);\n\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { \"dist-tags\"?: Record<string, string> };\n return data[\"dist-tags\"]?.[distTag] ?? null;\n } catch {\n return null;\n }\n}\n\nconst hook: Hook<\"init\"> = async function (options) {\n const commandId = options.id;\n if (!commandId || SKIP_COMMANDS.has(commandId)) return;\n\n const currentVersion = getCliVersion();\n // Don't check for unpublished/development builds\n if (currentVersion === \"0.0.0\" || currentVersion === \"0.0.0-development\") return;\n\n const buildType = getBuildType();\n const distTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n const globalConfig = loadGlobalConfig();\n const now = Date.now();\n const cacheIsFresh =\n globalConfig.last_version_check != null &&\n now - globalConfig.last_version_check < VERSION_CHECK_INTERVAL_MS;\n\n let latestVersion: string | null;\n if (cacheIsFresh && globalConfig.last_known_version) {\n latestVersion = globalConfig.last_known_version;\n } else {\n latestVersion = await fetchLatestVersion(distTag);\n if (latestVersion) {\n globalConfig.last_version_check = now;\n globalConfig.last_known_version = latestVersion;\n saveGlobalConfig(globalConfig);\n }\n }\n\n if (!latestVersion || !isNewerVersion(currentVersion, latestVersion)) return;\n\n this.log(\n chalk.yellow(\n `\\nA new version of ecloud-cli is available: ${chalk.red(currentVersion)} -> ${chalk.green(latestVersion)}`,\n ),\n );\n\n const shouldUpdate = await confirm({\n message: \"Would you like to update now?\",\n default: true,\n });\n\n if (shouldUpdate) {\n try {\n upgradePackage(undefined, distTag);\n this.log(`\\n${chalk.green(\"Upgrade successful!\")}`);\n this.exit(0);\n } catch {\n this.log(`\\n${chalk.yellow(\"Upgrade failed. Continuing with current version...\")}\\n`);\n }\n } else {\n // Snooze the prompt for another 24 hours\n globalConfig.last_version_check = now;\n saveGlobalConfig(globalConfig);\n }\n};\n\nexport default hook;\n","/**\n * CLI version utilities\n *\n * CLI_VERSION_BUILD_TIME is replaced at build time by tsup's define option\n */\n\n// @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time by tsup\ndeclare const CLI_VERSION_BUILD_TIME: string | undefined;\n\n/**\n * Get the CLI version\n */\nexport function getCliVersion(): string {\n // @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time\n return typeof CLI_VERSION_BUILD_TIME !== \"undefined\" ? CLI_VERSION_BUILD_TIME : \"0.0.0\";\n}\n\n/**\n * Get the x-client-id header value for API calls\n */\nexport function getClientId(): string {\n return `ecloud-cli/v${getCliVersion()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport chalk from \"chalk\";\nimport { withTelemetry } from \"../telemetry\";\n\n// Package being upgraded\nconst ecloudCLIPackage = \"@layr-labs/ecloud-cli\";\n\n// Possible PackManagers being covered\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"yarnBerry\" | \"bun\" | \"unknown\";\n\n// Detect package-manager from UA, check for bun as special case\nexport function detectPM(): PackageManager {\n const ua = process.env.npm_config_user_agent ?? \"\";\n\n if (ua.includes(\"pnpm/\")) return \"pnpm\";\n if (ua.includes(\"yarn/1\")) return \"yarn\";\n if (ua.match(/yarn\\/[23]/)) return \"yarnBerry\";\n if (ua.includes(\"npm/\")) return \"npm\";\n\n if (isBun()) return \"bun\";\n\n return \"unknown\";\n}\n\n// Detect bun using env falling back to checking for bun binary\nfunction isBun(): boolean {\n const execPath = process.execPath?.toLowerCase() ?? \"\";\n if (execPath.includes(\"bun\")) return true;\n\n if (process.env.BUN_INSTALL || process.env.BUN_RUNTIME) return true;\n\n try {\n const cmd = process.platform === \"win32\" ? \"where bun\" : \"which bun\";\n const p = execSync(cmd).toString().split(/\\r?\\n/)[0]?.trim();\n if (p && existsSync(p)) return true;\n } catch {\n // ignore\n }\n\n return false;\n}\n\n// Unified \"upgrade global to latest\" by manager\nexport function upgradePackage(packageManager?: string, buildTag = \"latest\"): void {\n const pm = packageManager ?? detectPM();\n\n const cmd = (() => {\n switch (pm) {\n case \"npm\":\n return `npm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"pnpm\":\n return `pnpm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"yarn\":\n return `yarn global add ${ecloudCLIPackage}@${buildTag}`;\n case \"yarnBerry\":\n // best effort, behaves more like a disposable global\n return `yarn dlx ${ecloudCLIPackage}@${buildTag}`;\n case \"bun\":\n return `bun add -g ${ecloudCLIPackage}@${buildTag}`;\n case \"unknown\":\n default:\n throw new Error();\n }\n })();\n\n execSync(cmd, { stdio: \"inherit\" });\n}\n\n// export Upgrade command to perform upgradePackage() call\nexport default class Upgrade extends Command {\n static description = \"Upgrade ecloud-cli package\";\n\n static flags = {\n \"package-manager\": Flags.string({\n required: false,\n description: \"Explicitly set package-manager to use for upgrade\",\n options: [\"npm\", \"pnpm\", \"yarn\", \"yarnBerry\", \"bun\"],\n env: \"PACKAGE_MANAGER\",\n }),\n };\n\n async run() {\n return withTelemetry(this, async () => {\n const { flags } = await this.parse(Upgrade);\n\n const buildType = getBuildType();\n const buildTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n try {\n upgradePackage(flags[\"package-manager\"], buildTag);\n this.log(`\\n${chalk.green(`Upgrade successful!`)}`);\n } catch (e) {\n this.log(`\\n${chalk.red(`Upgrade failed!`)}`);\n this.log(\n `\\n${chalk.red(`Cannot determine package manager to upgrade ${ecloudCLIPackage}.`)}`,\n );\n this.log(\n `\\n${chalk.red(`Use ${chalk.yellow(\"`package-manager`\")} flag to instruct upgrade (<supported managers: npm|pnpm|yarn|yarnBerry|bun>).`)}\\n`,\n );\n throw e;\n }\n });\n }\n}\n","/**\n * Telemetry utilities for CLI commands\n *\n * Provides helpers to wrap command execution with telemetry tracking\n */\n\nimport {\n createTelemetryClient,\n createAppEnvironment,\n createMetricsContext,\n addMetric,\n addMetricWithDimensions,\n emitMetrics,\n type TelemetryClient,\n getBuildType,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Command } from \"@oclif/core\";\nimport {\n getDefaultEnvironment,\n getOrCreateUserUUID,\n getGlobalTelemetryPreference,\n} from \"./utils/globalConfig\";\n\n/**\n * Create a telemetry client for CLI usage\n */\nexport function createCLITelemetryClient(): TelemetryClient {\n // Get user UUID from CLI's globalConfig (handles I/O)\n const userUUID = getOrCreateUserUUID();\n const environment = createAppEnvironment(userUUID);\n\n // Get telemetry preference from CLI's globalConfig\n const telemetryEnabled = getGlobalTelemetryPreference();\n\n return createTelemetryClient(environment, \"ecloud-cli\", {\n telemetryEnabled: telemetryEnabled !== false, // Enabled by default, disabled only if explicitly set to false\n });\n}\n\n/**\n * Wrap a command execution with telemetry\n *\n * @param command - The CLI command instance\n * @param action - The command action to execute\n * @returns The result of the action\n */\nexport async function withTelemetry<T>(command: Command, action: () => Promise<T>): Promise<T> {\n const client = createCLITelemetryClient();\n const metrics = createMetricsContext();\n\n // Set source to identify CLI usage\n metrics.properties[\"source\"] = \"ecloud-cli\";\n\n // Set command name in properties\n metrics.properties[\"command\"] = command.id || command.constructor.name;\n\n // Set environment in properties\n const environment = getDefaultEnvironment() || \"sepolia\";\n metrics.properties[\"environment\"] = environment;\n\n // Set buildType in properties\n const buildType = getBuildType() || \"prod\";\n metrics.properties[\"build_type\"] = buildType;\n\n // Set CLI version if available\n const cliVersion = command.config.version;\n if (cliVersion) {\n metrics.properties[\"cli_version\"] = cliVersion;\n }\n\n // Add initial count metric\n addMetric(metrics, \"Count\", 1);\n\n let actionError: Error | undefined;\n let result: T;\n\n try {\n result = await action();\n return result;\n } catch (err) {\n actionError = err instanceof Error ? err : new Error(String(err));\n throw err;\n } finally {\n // Add result metric\n const resultValue = actionError ? \"Failure\" : \"Success\";\n const dimensions: Record<string, string> = {};\n if (actionError) {\n dimensions[\"error\"] = actionError.message;\n }\n addMetricWithDimensions(metrics, resultValue, 1, dimensions);\n\n // Add duration metric\n const duration = Date.now() - metrics.startTime.getTime();\n addMetric(metrics, \"DurationMilliseconds\", duration);\n\n // Emit all metrics\n try {\n await emitMetrics(client, metrics);\n await client.close();\n } catch {\n // Silently ignore telemetry errors\n }\n }\n}\n","/**\n * Global configuration management\n *\n * Stores user-level configuration that persists across all CLI usage.\n * - $XDG_CONFIG_HOME/ecloud[BuildSuffix]/config.yaml (if XDG_CONFIG_HOME is set)\n * - Or ~/.config/ecloud[BuildSuffix]/config.yaml (fallback)\n *\n * Where BuildSuffix is:\n * - \"\" (empty) for production builds\n * - \"-dev\" for development builds\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { load as loadYaml, dump as dumpYaml } from \"js-yaml\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport * as crypto from \"crypto\";\nconst GLOBAL_CONFIG_FILE = \"config.yaml\";\n\nexport interface ProfileCacheEntry {\n updated_at: number; // Unix timestamp in milliseconds\n profiles: { [appId: string]: string }; // appId -> profile name\n}\n\nexport interface GlobalConfig {\n first_run?: boolean;\n telemetry_enabled?: boolean;\n user_uuid?: string;\n default_environment?: string;\n last_version_check?: number;\n last_known_version?: string;\n profile_cache?: {\n [environment: string]: ProfileCacheEntry;\n };\n directory_links?: {\n [environment: string]: {\n [directoryPath: string]: string;\n };\n };\n}\n\n// Profile cache TTL: 24 hours in milliseconds\nconst PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Get the XDG-compliant directory where global ecloud config should be stored\n */\nfunction getGlobalConfigDir(): string {\n // First check XDG_CONFIG_HOME\n const configHome = process.env.XDG_CONFIG_HOME;\n\n let baseDir: string;\n if (configHome && path.isAbsolute(configHome)) {\n baseDir = configHome;\n } else {\n // Fall back to ~/.config\n baseDir = path.join(os.homedir(), \".config\");\n }\n\n // Use environment-specific config directory\n const buildType = getBuildType();\n const buildSuffix = buildType === \"dev\" ? \"-dev\" : \"\";\n const configDirName = `ecloud${buildSuffix}`;\n\n return path.join(baseDir, configDirName);\n}\n\n/**\n * Get the full path to the global config file\n */\nfunction getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\n/**\n * Load global configuration, creating defaults if needed\n */\nexport function loadGlobalConfig(): GlobalConfig {\n const configPath = getGlobalConfigPath();\n\n // If file doesn't exist, return defaults for first run\n if (!fs.existsSync(configPath)) {\n return {\n first_run: true,\n };\n }\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n const config = loadYaml(content) as GlobalConfig;\n return config || { first_run: true };\n } catch {\n // If parsing fails, return defaults\n return {\n first_run: true,\n };\n }\n}\n\n/**\n * Save global configuration to disk\n */\nexport function saveGlobalConfig(config: GlobalConfig): void {\n const configPath = getGlobalConfigPath();\n\n // Ensure directory exists\n const configDir = path.dirname(configPath);\n fs.mkdirSync(configDir, { recursive: true, mode: 0o755 });\n\n // Write config file\n const content = dumpYaml(config, { lineWidth: -1 });\n fs.writeFileSync(configPath, content, { mode: 0o644 });\n}\n\nfunction normalizeDirectoryPath(directoryPath: string): string {\n const resolved = path.resolve(directoryPath);\n try {\n return fs.realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\n/**\n * Get linked app ID for a directory in an environment\n */\nexport function getLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n): string | null {\n if (!directoryPath) {\n return null;\n }\n\n const config = loadGlobalConfig();\n const links = config.directory_links?.[environment];\n if (!links) {\n return null;\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n const appId = links[normalizedPath];\n return appId || null;\n}\n\n/**\n * Link a directory to an app ID in an environment\n */\nexport function setLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n appId: string,\n): void {\n if (!directoryPath || !environment) {\n return;\n }\n\n const config = loadGlobalConfig();\n if (!config.directory_links) {\n config.directory_links = {};\n }\n if (!config.directory_links[environment]) {\n config.directory_links[environment] = {};\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n // Normalize appId to lowercase for consistent lookups\n config.directory_links[environment][normalizedPath] = appId.toLowerCase();\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user's preferred deployment environment\n */\nexport function getDefaultEnvironment(): string | undefined {\n const config = loadGlobalConfig();\n return config.default_environment;\n}\n\n/**\n * Set the user's preferred deployment environment\n */\nexport function setDefaultEnvironment(environment: string): void {\n const config = loadGlobalConfig();\n config.default_environment = environment;\n config.first_run = false; // No longer first run after setting environment\n saveGlobalConfig(config);\n}\n\n/**\n * Check if this is the user's first time running the CLI\n */\nexport function isFirstRun(): boolean {\n const config = loadGlobalConfig();\n return config.first_run === true;\n}\n\n/**\n * Mark that the first run has been completed\n */\nexport function markFirstRunComplete(): void {\n const config = loadGlobalConfig();\n config.first_run = false;\n saveGlobalConfig(config);\n}\n\n/**\n * Get the global telemetry preference\n */\nexport function getGlobalTelemetryPreference(): boolean | undefined {\n const config = loadGlobalConfig();\n return config.telemetry_enabled;\n}\n\n/**\n * Set the global telemetry preference\n */\nexport function setGlobalTelemetryPreference(enabled: boolean): void {\n const config = loadGlobalConfig();\n config.telemetry_enabled = enabled;\n config.first_run = false; // No longer first run after setting preference\n saveGlobalConfig(config);\n}\n\n// ==================== Profile Cache Functions ====================\n\n/**\n * Get cached profile names for an environment\n * Returns null if cache is missing or expired (older than 24 hours)\n */\nexport function getProfileCache(environment: string): Record<string, string> | null {\n const config = loadGlobalConfig();\n const cacheEntry = config.profile_cache?.[environment];\n\n if (!cacheEntry) {\n return null;\n }\n\n // Check if cache is expired\n const now = Date.now();\n if (now - cacheEntry.updated_at > PROFILE_CACHE_TTL_MS) {\n return null;\n }\n\n return cacheEntry.profiles;\n}\n\n/**\n * Set cached profile names for an environment\n */\nexport function setProfileCache(environment: string, profiles: Record<string, string>): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles,\n };\n\n saveGlobalConfig(config);\n}\n\n/**\n * Invalidate profile cache for a specific environment or all environments\n */\nexport function invalidateProfileCache(environment?: string): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n return;\n }\n\n if (environment) {\n // Invalidate specific environment\n delete config.profile_cache[environment];\n } else {\n // Invalidate all environments\n config.profile_cache = {};\n }\n\n saveGlobalConfig(config);\n}\n\n/**\n * Update a single profile name in the cache\n * This is useful after deploy or profile set to update just one entry\n */\nexport function updateProfileCacheEntry(\n environment: string,\n appId: string,\n profileName: string,\n): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n if (!config.profile_cache[environment]) {\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles: {},\n };\n }\n\n // Normalize appId to lowercase for consistent lookups\n const normalizedAppId = appId.toLowerCase();\n config.profile_cache[environment].profiles[normalizedAppId] = profileName;\n config.profile_cache[environment].updated_at = Date.now();\n\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user UUID from global config, or generate a new one if it doesn't exist\n */\nexport function getOrCreateUserUUID(): string {\n const config = loadGlobalConfig();\n if (config.user_uuid) {\n return config.user_uuid;\n }\n\n // Generate a new UUID (v4)\n const uuid = generateUUID();\n\n // Save it to config\n config.user_uuid = uuid;\n config.first_run = false;\n saveGlobalConfig(config);\n\n return uuid;\n}\n\n/**\n * Generate a UUID v4\n */\nfunction generateUUID(): string {\n // UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n // Use cryptographically secure random values.\n const bytes = crypto.randomBytes(16);\n // Per RFC 4122 section 4.4, set bits for version and `clock_seq_hi_and_reserved`\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\n return (\n hex.slice(0, 4).join(\"\") +\n hex.slice(4, 6).join(\"\") +\n \"-\" +\n hex.slice(6, 8).join(\"\") +\n \"-\" +\n hex.slice(8, 10).join(\"\") +\n \"-\" +\n hex.slice(10, 12).join(\"\") +\n \"-\" +\n hex.slice(12, 16).join(\"\")\n );\n}\n\n/**\n * Save user UUID to global config (preserves existing UUID if present)\n */\nexport function saveUserUUID(userUUID: string): void {\n const config = loadGlobalConfig();\n // Only update if not already set\n if (!config.user_uuid) {\n config.user_uuid = userUUID;\n saveGlobalConfig(config);\n }\n}\n"],"mappings":"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","names":["chalk","getBuildType","existsSync","getBuildType","getBuildType","getBuildType","existsSync","getBuildType","getBuildType","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/init/version-check.ts","../../../src/utils/version.ts","../../../src/commands/upgrade.ts","../../../src/telemetry.ts","../../../src/utils/globalConfig.ts"],"sourcesContent":["import { Hook } from \"@oclif/core\";\nimport chalk from \"chalk\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport { getCliVersion } from \"../../utils/version\";\nimport { upgradePackage } from \"../../commands/upgrade\";\nimport { loadGlobalConfig, saveGlobalConfig } from \"../../utils/globalConfig\";\n\nconst SKIP_COMMANDS = new Set([\"upgrade\", \"version\"]);\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@layr-labs/ecloud-cli\";\nconst VERSION_CHECK_TIMEOUT_MS = 3000;\nconst VERSION_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\nfunction parseVersion(v: string): { major: number; minor: number; patch: number; prerelease: string | null } {\n const clean = v.replace(/^v/, \"\");\n const [core, ...rest] = clean.split(\"-\");\n const [major = 0, minor = 0, patch = 0] = core.split(\".\").map(Number);\n const prerelease = rest.length > 0 ? rest.join(\"-\") : null;\n return { major, minor, patch, prerelease };\n}\n\nfunction comparePrerelease(a: string | null, b: string | null): number {\n // No prerelease = release, which is higher than any prerelease\n if (a === null && b === null) return 0;\n if (a === null) return 1; // a is release, b is prerelease → a > b\n if (b === null) return -1; // a is prerelease, b is release → a < b\n\n // Compare prerelease segments (e.g. \"dev.1\" vs \"dev.2\")\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i];\n const bp = bParts[i];\n if (ap === undefined) return -1;\n if (bp === undefined) return 1;\n const aNum = Number(ap);\n const bNum = Number(bp);\n if (!isNaN(aNum) && !isNaN(bNum)) {\n if (aNum !== bNum) return aNum - bNum;\n } else {\n if (ap < bp) return -1;\n if (ap > bp) return 1;\n }\n }\n return 0;\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const c = parseVersion(current);\n const l = parseVersion(latest);\n\n if (l.major !== c.major) return l.major > c.major;\n if (l.minor !== c.minor) return l.minor > c.minor;\n if (l.patch !== c.patch) return l.patch > c.patch;\n return comparePrerelease(l.prerelease, c.prerelease) > 0;\n}\n\nasync function fetchLatestVersion(distTag: string): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), VERSION_CHECK_TIMEOUT_MS);\n\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const data = (await response.json()) as { \"dist-tags\"?: Record<string, string> };\n return data[\"dist-tags\"]?.[distTag] ?? null;\n } catch {\n return null;\n }\n}\n\nconst hook: Hook<\"init\"> = async function (options) {\n const commandId = options.id;\n if (!commandId || SKIP_COMMANDS.has(commandId)) return;\n\n const currentVersion = getCliVersion();\n // Don't check for unpublished/development builds\n if (currentVersion === \"0.0.0\" || currentVersion === \"0.0.0-development\") return;\n\n const buildType = getBuildType();\n const distTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n const globalConfig = loadGlobalConfig();\n const now = Date.now();\n const cacheIsFresh =\n globalConfig.last_version_check != null &&\n now - globalConfig.last_version_check < VERSION_CHECK_INTERVAL_MS;\n\n let latestVersion: string | null;\n if (cacheIsFresh && globalConfig.last_known_version) {\n latestVersion = globalConfig.last_known_version;\n } else {\n latestVersion = await fetchLatestVersion(distTag);\n if (latestVersion) {\n globalConfig.last_version_check = now;\n globalConfig.last_known_version = latestVersion;\n saveGlobalConfig(globalConfig);\n }\n }\n\n if (!latestVersion || !isNewerVersion(currentVersion, latestVersion)) return;\n\n this.log(\n chalk.yellow(\n `\\nA new version of ecloud-cli is available: ${chalk.red(currentVersion)} -> ${chalk.green(latestVersion)}`,\n ),\n );\n\n const shouldUpdate = await confirm({\n message: \"Would you like to update now?\",\n default: true,\n });\n\n if (shouldUpdate) {\n try {\n upgradePackage(undefined, distTag);\n this.log(`\\n${chalk.green(\"Upgrade successful!\")}`);\n this.exit(0);\n } catch {\n this.log(`\\n${chalk.yellow(\"Upgrade failed. Continuing with current version...\")}\\n`);\n }\n } else {\n // Snooze the prompt for another 24 hours\n globalConfig.last_version_check = now;\n saveGlobalConfig(globalConfig);\n }\n};\n\nexport default hook;\n","/**\n * CLI version utilities\n *\n * CLI_VERSION_BUILD_TIME is replaced at build time by tsup's define option\n */\n\n// @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time by tsup\ndeclare const CLI_VERSION_BUILD_TIME: string | undefined;\n\n/**\n * Get the CLI version\n */\nexport function getCliVersion(): string {\n // @ts-ignore - CLI_VERSION_BUILD_TIME is injected at build time\n return typeof CLI_VERSION_BUILD_TIME !== \"undefined\" ? CLI_VERSION_BUILD_TIME : \"0.0.0\";\n}\n\n/**\n * Get the x-client-id header value for API calls\n */\nexport function getClientId(): string {\n return `ecloud-cli/v${getCliVersion()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\n\nimport chalk from \"chalk\";\nimport { withTelemetry } from \"../telemetry\";\n\n// Package being upgraded\nconst ecloudCLIPackage = \"@layr-labs/ecloud-cli\";\n\n// Possible PackManagers being covered\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"yarnBerry\" | \"bun\" | \"unknown\";\n\n// Detect package-manager from UA, check for bun as special case\nexport function detectPM(): PackageManager {\n const ua = process.env.npm_config_user_agent ?? \"\";\n\n if (ua.includes(\"pnpm/\")) return \"pnpm\";\n if (ua.includes(\"yarn/1\")) return \"yarn\";\n if (ua.match(/yarn\\/[23]/)) return \"yarnBerry\";\n if (ua.includes(\"npm/\")) return \"npm\";\n\n if (isBun()) return \"bun\";\n\n return \"unknown\";\n}\n\n// Detect bun using env falling back to checking for bun binary\nfunction isBun(): boolean {\n const execPath = process.execPath?.toLowerCase() ?? \"\";\n if (execPath.includes(\"bun\")) return true;\n\n if (process.env.BUN_INSTALL || process.env.BUN_RUNTIME) return true;\n\n try {\n const cmd = process.platform === \"win32\" ? \"where bun\" : \"which bun\";\n const p = execSync(cmd).toString().split(/\\r?\\n/)[0]?.trim();\n if (p && existsSync(p)) return true;\n } catch {\n // ignore\n }\n\n return false;\n}\n\n// Unified \"upgrade global to latest\" by manager\nexport function upgradePackage(packageManager?: string, buildTag = \"latest\"): void {\n const pm = packageManager ?? detectPM();\n\n const cmd = (() => {\n switch (pm) {\n case \"npm\":\n return `npm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"pnpm\":\n return `pnpm install -g ${ecloudCLIPackage}@${buildTag}`;\n case \"yarn\":\n return `yarn global add ${ecloudCLIPackage}@${buildTag}`;\n case \"yarnBerry\":\n // best effort, behaves more like a disposable global\n return `yarn dlx ${ecloudCLIPackage}@${buildTag}`;\n case \"bun\":\n return `bun add -g ${ecloudCLIPackage}@${buildTag}`;\n case \"unknown\":\n default:\n throw new Error();\n }\n })();\n\n execSync(cmd, { stdio: \"inherit\" });\n}\n\n// export Upgrade command to perform upgradePackage() call\nexport default class Upgrade extends Command {\n static description = \"Upgrade ecloud-cli package\";\n\n static flags = {\n \"package-manager\": Flags.string({\n required: false,\n description: \"Explicitly set package-manager to use for upgrade\",\n options: [\"npm\", \"pnpm\", \"yarn\", \"yarnBerry\", \"bun\"],\n env: \"PACKAGE_MANAGER\",\n }),\n };\n\n async run() {\n return withTelemetry(this, async () => {\n const { flags } = await this.parse(Upgrade);\n\n const buildType = getBuildType();\n const buildTag = buildType === \"dev\" ? \"dev\" : \"latest\";\n\n try {\n upgradePackage(flags[\"package-manager\"], buildTag);\n this.log(`\\n${chalk.green(`Upgrade successful!`)}`);\n } catch (e) {\n this.log(`\\n${chalk.red(`Upgrade failed!`)}`);\n this.log(\n `\\n${chalk.red(`Cannot determine package manager to upgrade ${ecloudCLIPackage}.`)}`,\n );\n this.log(\n `\\n${chalk.red(`Use ${chalk.yellow(\"`package-manager`\")} flag to instruct upgrade (<supported managers: npm|pnpm|yarn|yarnBerry|bun>).`)}\\n`,\n );\n throw e;\n }\n });\n }\n}\n","/**\n * Telemetry utilities for CLI commands\n *\n * Provides helpers to wrap command execution with telemetry tracking\n */\n\nimport {\n createTelemetryClient,\n createAppEnvironment,\n createMetricsContext,\n addMetric,\n addMetricWithDimensions,\n emitMetrics,\n type TelemetryClient,\n getBuildType,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Command } from \"@oclif/core\";\nimport {\n getDefaultEnvironment,\n getOrCreateUserUUID,\n getGlobalTelemetryPreference,\n} from \"./utils/globalConfig\";\n\n/**\n * Create a telemetry client for CLI usage\n */\nexport function createCLITelemetryClient(): TelemetryClient {\n // Get user UUID from CLI's globalConfig (handles I/O)\n const userUUID = getOrCreateUserUUID();\n const environment = createAppEnvironment(userUUID);\n\n // Get telemetry preference from CLI's globalConfig\n const telemetryEnabled = getGlobalTelemetryPreference();\n\n return createTelemetryClient(environment, \"ecloud-cli\", {\n telemetryEnabled: telemetryEnabled !== false, // Enabled by default, disabled only if explicitly set to false\n });\n}\n\n/**\n * Wrap a command execution with telemetry\n *\n * @param command - The CLI command instance\n * @param action - The command action to execute\n * @returns The result of the action\n */\nexport async function withTelemetry<T>(command: Command, action: () => Promise<T>): Promise<T> {\n const client = createCLITelemetryClient();\n const metrics = createMetricsContext();\n\n // Set source to identify CLI usage\n metrics.properties[\"source\"] = \"ecloud-cli\";\n\n // Set command name in properties\n metrics.properties[\"command\"] = command.id || command.constructor.name;\n\n // Set environment in properties\n const environment = getDefaultEnvironment() || \"sepolia\";\n metrics.properties[\"environment\"] = environment;\n\n // Set buildType in properties\n const buildType = getBuildType() || \"prod\";\n metrics.properties[\"build_type\"] = buildType;\n\n // Set CLI version if available\n const cliVersion = command.config.version;\n if (cliVersion) {\n metrics.properties[\"cli_version\"] = cliVersion;\n }\n\n // Add initial count metric\n addMetric(metrics, \"Count\", 1);\n\n let actionError: Error | undefined;\n let result: T;\n\n try {\n result = await action();\n return result;\n } catch (err) {\n actionError = err instanceof Error ? err : new Error(String(err));\n throw err;\n } finally {\n // Add result metric\n const resultValue = actionError ? \"Failure\" : \"Success\";\n const dimensions: Record<string, string> = {};\n if (actionError) {\n dimensions[\"error\"] = actionError.message;\n }\n addMetricWithDimensions(metrics, resultValue, 1, dimensions);\n\n // Add duration metric\n const duration = Date.now() - metrics.startTime.getTime();\n addMetric(metrics, \"DurationMilliseconds\", duration);\n\n // Emit all metrics\n try {\n await emitMetrics(client, metrics);\n await client.close();\n } catch {\n // Silently ignore telemetry errors\n }\n }\n}\n","/**\n * Global configuration management\n *\n * Stores user-level configuration that persists across all CLI usage.\n * - $XDG_CONFIG_HOME/ecloud[BuildSuffix]/config.yaml (if XDG_CONFIG_HOME is set)\n * - Or ~/.config/ecloud[BuildSuffix]/config.yaml (fallback)\n *\n * Where BuildSuffix is:\n * - \"\" (empty) for production builds\n * - \"-dev\" for development builds\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { load as loadYaml, dump as dumpYaml } from \"js-yaml\";\nimport { getBuildType } from \"@layr-labs/ecloud-sdk\";\nimport * as crypto from \"crypto\";\nconst GLOBAL_CONFIG_FILE = \"config.yaml\";\n\nexport interface ProfileCacheEntry {\n updated_at: number; // Unix timestamp in milliseconds\n profiles: { [appId: string]: string }; // appId -> profile name\n}\n\nexport interface GlobalConfig {\n first_run?: boolean;\n telemetry_enabled?: boolean;\n user_uuid?: string;\n default_environment?: string;\n last_version_check?: number;\n last_known_version?: string;\n profile_cache?: {\n [environment: string]: ProfileCacheEntry;\n };\n directory_links?: {\n [environment: string]: {\n [directoryPath: string]: string;\n };\n };\n}\n\n// Profile cache TTL: 24 hours in milliseconds\nconst PROFILE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Get the XDG-compliant directory where global ecloud config should be stored\n */\nfunction getGlobalConfigDir(): string {\n // First check XDG_CONFIG_HOME\n const configHome = process.env.XDG_CONFIG_HOME;\n\n let baseDir: string;\n if (configHome && path.isAbsolute(configHome)) {\n baseDir = configHome;\n } else {\n // Fall back to ~/.config\n baseDir = path.join(os.homedir(), \".config\");\n }\n\n // Use environment-specific config directory\n const buildType = getBuildType();\n const buildSuffix = buildType === \"dev\" ? \"-dev\" : \"\";\n const configDirName = `ecloud${buildSuffix}`;\n\n return path.join(baseDir, configDirName);\n}\n\n/**\n * Get the full path to the global config file\n */\nfunction getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\n/**\n * Load global configuration, creating defaults if needed\n */\nexport function loadGlobalConfig(): GlobalConfig {\n const configPath = getGlobalConfigPath();\n\n // If file doesn't exist, return defaults for first run\n if (!fs.existsSync(configPath)) {\n return {\n first_run: true,\n };\n }\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n const config = loadYaml(content) as GlobalConfig;\n return config || { first_run: true };\n } catch {\n // If parsing fails, return defaults\n return {\n first_run: true,\n };\n }\n}\n\n/**\n * Save global configuration to disk\n */\nexport function saveGlobalConfig(config: GlobalConfig): void {\n const configPath = getGlobalConfigPath();\n\n // Ensure directory exists\n const configDir = path.dirname(configPath);\n fs.mkdirSync(configDir, { recursive: true, mode: 0o755 });\n\n // Write config file\n const content = dumpYaml(config, { lineWidth: -1 });\n fs.writeFileSync(configPath, content, { mode: 0o644 });\n}\n\nfunction normalizeDirectoryPath(directoryPath: string): string {\n const resolved = path.resolve(directoryPath);\n try {\n return fs.realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\n/**\n * Get linked app ID for a directory in an environment\n */\nexport function getLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n): string | null {\n if (!directoryPath) {\n return null;\n }\n\n const config = loadGlobalConfig();\n const links = config.directory_links?.[environment];\n if (!links) {\n return null;\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n const appId = links[normalizedPath];\n return appId || null;\n}\n\n/**\n * Link a directory to an app ID in an environment\n */\nexport function setLinkedAppForDirectory(\n environment: string,\n directoryPath: string,\n appId: string,\n): void {\n if (!directoryPath || !environment) {\n return;\n }\n\n const config = loadGlobalConfig();\n if (!config.directory_links) {\n config.directory_links = {};\n }\n if (!config.directory_links[environment]) {\n config.directory_links[environment] = {};\n }\n\n const normalizedPath = normalizeDirectoryPath(directoryPath);\n // Normalize appId to lowercase for consistent lookups\n config.directory_links[environment][normalizedPath] = appId.toLowerCase();\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user's preferred deployment environment\n */\nexport function getDefaultEnvironment(): string | undefined {\n const config = loadGlobalConfig();\n return config.default_environment;\n}\n\n/**\n * Set the user's preferred deployment environment\n */\nexport function setDefaultEnvironment(environment: string): void {\n const config = loadGlobalConfig();\n config.default_environment = environment;\n config.first_run = false; // No longer first run after setting environment\n saveGlobalConfig(config);\n}\n\n/**\n * Check if this is the user's first time running the CLI\n */\nexport function isFirstRun(): boolean {\n const config = loadGlobalConfig();\n return config.first_run === true;\n}\n\n/**\n * Mark that the first run has been completed\n */\nexport function markFirstRunComplete(): void {\n const config = loadGlobalConfig();\n config.first_run = false;\n saveGlobalConfig(config);\n}\n\n/**\n * Get the global telemetry preference\n */\nexport function getGlobalTelemetryPreference(): boolean | undefined {\n const config = loadGlobalConfig();\n return config.telemetry_enabled;\n}\n\n/**\n * Set the global telemetry preference\n */\nexport function setGlobalTelemetryPreference(enabled: boolean): void {\n const config = loadGlobalConfig();\n config.telemetry_enabled = enabled;\n config.first_run = false; // No longer first run after setting preference\n saveGlobalConfig(config);\n}\n\n// ==================== Profile Cache Functions ====================\n\n/**\n * Get cached profile names for an environment\n * Returns null if cache is missing or expired (older than 24 hours)\n */\nexport function getProfileCache(environment: string): Record<string, string> | null {\n const config = loadGlobalConfig();\n const cacheEntry = config.profile_cache?.[environment];\n\n if (!cacheEntry) {\n return null;\n }\n\n // Check if cache is expired\n const now = Date.now();\n if (now - cacheEntry.updated_at > PROFILE_CACHE_TTL_MS) {\n return null;\n }\n\n return cacheEntry.profiles;\n}\n\n/**\n * Set cached profile names for an environment\n */\nexport function setProfileCache(environment: string, profiles: Record<string, string>): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles,\n };\n\n saveGlobalConfig(config);\n}\n\n/**\n * Invalidate profile cache for a specific environment or all environments\n */\nexport function invalidateProfileCache(environment?: string): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n return;\n }\n\n if (environment) {\n // Invalidate specific environment\n delete config.profile_cache[environment];\n } else {\n // Invalidate all environments\n config.profile_cache = {};\n }\n\n saveGlobalConfig(config);\n}\n\n/**\n * Update a single profile name in the cache\n * This is useful after deploy or profile set to update just one entry\n */\nexport function updateProfileCacheEntry(\n environment: string,\n appId: string,\n profileName: string,\n): void {\n const config = loadGlobalConfig();\n\n if (!config.profile_cache) {\n config.profile_cache = {};\n }\n\n if (!config.profile_cache[environment]) {\n config.profile_cache[environment] = {\n updated_at: Date.now(),\n profiles: {},\n };\n }\n\n // Normalize appId to lowercase for consistent lookups\n const normalizedAppId = appId.toLowerCase();\n config.profile_cache[environment].profiles[normalizedAppId] = profileName;\n config.profile_cache[environment].updated_at = Date.now();\n\n saveGlobalConfig(config);\n}\n\n/**\n * Get the user UUID from global config, or generate a new one if it doesn't exist\n */\nexport function getOrCreateUserUUID(): string {\n const config = loadGlobalConfig();\n if (config.user_uuid) {\n return config.user_uuid;\n }\n\n // Generate a new UUID (v4)\n const uuid = generateUUID();\n\n // Save it to config\n config.user_uuid = uuid;\n config.first_run = false;\n saveGlobalConfig(config);\n\n return uuid;\n}\n\n/**\n * Generate a UUID v4\n */\nfunction generateUUID(): string {\n // UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n // Use cryptographically secure random values.\n const bytes = crypto.randomBytes(16);\n // Per RFC 4122 section 4.4, set bits for version and `clock_seq_hi_and_reserved`\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // Version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // Variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\n return (\n hex.slice(0, 4).join(\"\") +\n hex.slice(4, 6).join(\"\") +\n \"-\" +\n hex.slice(6, 8).join(\"\") +\n \"-\" +\n hex.slice(8, 10).join(\"\") +\n \"-\" +\n hex.slice(10, 12).join(\"\") +\n \"-\" +\n hex.slice(12, 16).join(\"\")\n );\n}\n\n/**\n * Save user UUID to global config (preserves existing UUID if present)\n */\nexport function saveUserUUID(userUUID: string): void {\n const config = loadGlobalConfig();\n // Only update if not already set\n if (!config.user_uuid) {\n config.user_uuid = userUUID;\n saveGlobalConfig(config);\n }\n}\n"],"mappings":"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","names":["chalk","getBuildType","existsSync","getBuildType","getBuildType","getBuildType","existsSync","getBuildType","getBuildType","chalk"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layr-labs/ecloud-cli",
|
|
3
|
-
"version": "0.4.3
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@inquirer/prompts": "^7.10.1",
|
|
16
|
-
"@layr-labs/ecloud-sdk": "0.4.3
|
|
16
|
+
"@layr-labs/ecloud-sdk": "0.4.3",
|
|
17
17
|
"@napi-rs/keyring": "^1.0.5",
|
|
18
18
|
"@oclif/core": "^4.8.0",
|
|
19
19
|
"axios": "^1.13.2",
|