@envmanager-cli/cli 0.1.1 → 0.1.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/README.md +1 -1
- package/dist/bin/envmanager.js +452 -53
- package/dist/bin/envmanager.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -149,7 +149,7 @@ Run \`envmanager login\` to re-authenticate.`);
|
|
|
149
149
|
|
|
150
150
|
// src/lib/client.ts
|
|
151
151
|
var DEFAULT_API_URL2 = "https://rhopfaburfflrdwpowcd.supabase.co";
|
|
152
|
-
var DEFAULT_ANON_KEY = "
|
|
152
|
+
var DEFAULT_ANON_KEY = "sb_publishable_Y2EpPiIN3KPjQMc1GLVXjw__ghRVLC4";
|
|
153
153
|
var LOCAL_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
|
|
154
154
|
function getApiUrl2() {
|
|
155
155
|
return process.env.ENVMANAGER_API_URL || getStoredApiUrl() || DEFAULT_API_URL2;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/client.ts","../src/lib/credentials.ts","../src/lib/auth.ts","../src/lib/config.ts"],"sourcesContent":["import { createClient as createSupabaseClient, SupabaseClient } from '@supabase/supabase-js'\nimport { getCredentials, getApiKeyFromEnv, getStoredApiUrl, getStoredApiKey } from './credentials.js'\nimport { ensureAuthenticated, exchangeApiKeyForToken, clearCachedToken } from './auth.js'\n\nconst DEFAULT_API_URL = 'https://rhopfaburfflrdwpowcd.supabase.co'\nconst DEFAULT_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJob3BmYWJ1cmZmbHJkd3Bvd2NkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mjk0NjkxNzMsImV4cCI6MjA0NTA0NTE3M30.hpEuNqNRJcbCQ_F5u_u8SYABC0Zr_pKCdHMn3lPXn4M'\nconst LOCAL_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0'\n\nfunction getApiUrl(): string {\n return process.env.ENVMANAGER_API_URL || getStoredApiUrl() || DEFAULT_API_URL\n}\n\nfunction getAnonKey(): string {\n const apiUrl = getApiUrl()\n if (apiUrl.includes('localhost') || apiUrl.includes('127.0.0.1')) {\n return LOCAL_ANON_KEY\n }\n return process.env.ENVMANAGER_ANON_KEY || DEFAULT_ANON_KEY\n}\n\nlet clientInstance: SupabaseClient | null = null\nlet currentAccessToken: string | null = null\n\nexport async function createClient(): Promise<SupabaseClient> {\n if (clientInstance) {\n return clientInstance\n }\n\n // Priority: 1. Environment API key, 2. Stored API key (from login), 3. Session tokens\n const apiKey = getApiKeyFromEnv() || getStoredApiKey()\n\n if (apiKey) {\n const tokenResponse = await exchangeApiKeyForToken(apiKey)\n currentAccessToken = tokenResponse.access_token\n\n clientInstance = createSupabaseClient(getApiUrl(), getAnonKey(), {\n global: {\n headers: {\n Authorization: `Bearer ${currentAccessToken}`\n }\n }\n })\n\n await clientInstance.realtime.setAuth(currentAccessToken)\n return clientInstance\n }\n\n // Legacy flow: session tokens\n currentAccessToken = await ensureAuthenticated()\n\n clientInstance = createSupabaseClient(getApiUrl(), getAnonKey(), {\n global: {\n headers: {\n Authorization: `Bearer ${currentAccessToken}`\n }\n }\n })\n\n await clientInstance.realtime.setAuth(currentAccessToken)\n\n return clientInstance\n}\n\nexport function getAccessToken(): string | null {\n return currentAccessToken\n}\n\nexport async function refreshClientAuth(): Promise<void> {\n if (!clientInstance) return\n\n const accessToken = await ensureAuthenticated()\n currentAccessToken = accessToken\n\n // Update the realtime connection's auth token (preserves active channels)\n await clientInstance.realtime.setAuth(accessToken)\n}\n\nexport function resetClient(): void {\n clientInstance = null\n currentAccessToken = null\n clearCachedToken()\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'fs'\nimport { homedir } from 'os'\nimport { join } from 'path'\n\nconst CONFIG_DIR = join(homedir(), '.config', 'envmanager')\nconst CREDENTIALS_FILE = join(CONFIG_DIR, 'auth.json')\n\ninterface Credentials {\n // New flow: API key based auth (preferred)\n apiKey?: string\n // Legacy flow: session tokens\n accessToken?: string\n refreshToken?: string\n expiresAt?: number\n // Common\n apiUrl?: string\n email?: string\n}\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 })\n }\n}\n\nexport function getCredentials(): Credentials | null {\n if (!existsSync(CREDENTIALS_FILE)) {\n return null\n }\n\n try {\n const content = readFileSync(CREDENTIALS_FILE, 'utf-8')\n return JSON.parse(content) as Credentials\n } catch {\n return null\n }\n}\n\nexport function saveCredentials(credentials: Credentials): void {\n ensureConfigDir()\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 0o600 })\n chmodSync(CREDENTIALS_FILE, 0o600)\n}\n\nexport function clearCredentials(): void {\n if (existsSync(CREDENTIALS_FILE)) {\n unlinkSync(CREDENTIALS_FILE)\n }\n}\n\nexport function isTokenExpired(): boolean {\n const creds = getCredentials()\n if (!creds) return true\n // API key auth doesn't expire in the same way - let the server validate\n if (creds.apiKey) return false\n if (!creds.expiresAt) return true\n return Date.now() >= creds.expiresAt\n}\n\nconst PROACTIVE_REFRESH_BUFFER_MS = 5 * 60 * 1000\n\nexport function shouldRefreshToken(): boolean {\n const creds = getCredentials()\n if (!creds) return false\n // API key auth doesn't need proactive refresh\n if (creds.apiKey) return false\n if (!creds.expiresAt) return false\n return Date.now() >= (creds.expiresAt - PROACTIVE_REFRESH_BUFFER_MS)\n}\n\nexport function getApiKeyFromEnv(): string | null {\n return process.env.ENVMANAGER_API_KEY || null\n}\n\nexport function getStoredApiKey(): string | null {\n const creds = getCredentials()\n return creds?.apiKey || null\n}\n\nexport function getStoredApiUrl(): string | null {\n const creds = getCredentials()\n return creds?.apiUrl || null\n}\n","import { createServer, IncomingMessage, ServerResponse } from 'http'\nimport { randomBytes, createHash } from 'crypto'\nimport open from 'open'\nimport { saveCredentials, getCredentials, isTokenExpired, shouldRefreshToken, getStoredApiKey, getStoredApiUrl } from './credentials.js'\n\nconst DEFAULT_APP_URL = 'https://envmanager.com'\nconst DEFAULT_API_URL = 'https://rhopfaburfflrdwpowcd.supabase.co'\n\nfunction getAppUrl(): string {\n return process.env.ENVMANAGER_APP_URL || DEFAULT_APP_URL\n}\n\nfunction getApiUrl(): string {\n return process.env.ENVMANAGER_API_URL || getStoredApiUrl() || DEFAULT_API_URL\n}\n\nfunction generateCodeVerifier(): string {\n return randomBytes(32).toString('base64url')\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return createHash('sha256').update(verifier).digest('base64url')\n}\n\nfunction generateState(): string {\n return randomBytes(16).toString('hex')\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\ninterface AuthCallbackResult {\n apiKey?: string\n accessToken?: string\n refreshToken?: string\n expiresIn?: number\n}\n\nasync function startCallbackServer(expectedState: string, port: number = 8976): Promise<AuthCallbackResult> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close()\n reject(new Error('Authentication timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`)\n \n if (url.pathname === '/callback') {\n const apiKey = url.searchParams.get('api_key')\n const accessToken = url.searchParams.get('access_token')\n const refreshToken = url.searchParams.get('refresh_token')\n const expiresIn = url.searchParams.get('expires_in')\n const state = url.searchParams.get('state')\n const error = url.searchParams.get('error')\n const errorDescription = url.searchParams.get('error_description')\n\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Authentication Failed</h1>\n <p>${escapeHtml(errorDescription || error || 'Unknown error')}</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error(errorDescription || error))\n return\n }\n\n // Accept either API key (new flow) or session tokens (legacy/fallback)\n if (!apiKey && (!accessToken || !refreshToken)) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Invalid Callback</h1>\n <p>Missing authentication credentials.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error('Invalid callback: missing credentials'))\n return\n }\n\n if (!state || state !== expectedState) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Invalid State</h1>\n <p>State mismatch - possible CSRF attack.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error('State mismatch - authentication failed'))\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Authentication Successful!</h1>\n <p>You can close this window and return to your terminal.</p>\n </body>\n </html>\n `)\n\n clearTimeout(timeout)\n server.close()\n\n // Return API key if present (new flow), otherwise return tokens (legacy)\n if (apiKey) {\n resolve({ apiKey })\n } else {\n resolve({\n accessToken: accessToken!,\n refreshToken: refreshToken!,\n expiresIn: parseInt(expiresIn || '3600', 10)\n })\n }\n } else {\n res.writeHead(404)\n res.end('Not found')\n }\n })\n\n server.listen(port, '127.0.0.1', () => {})\n \n server.on('error', (err: Error & { code?: string }) => {\n clearTimeout(timeout)\n if (err.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use. Please close the application using it.`))\n } else {\n reject(err)\n }\n })\n })\n}\n\ninterface TokenResponse {\n access_token: string\n refresh_token: string\n expires_in: number\n user?: {\n id: string\n email?: string\n }\n}\n\nasync function exchangeCodeForTokens(code: string, codeVerifier: string): Promise<TokenResponse> {\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-auth-callback`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n code,\n code_verifier: codeVerifier,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as { error?: string }\n throw new Error(errorData.error || `HTTP ${response.status}`)\n }\n\n return response.json() as Promise<TokenResponse>\n}\n\n// In-memory cache for exchanged API key tokens (process lifetime only)\nlet cachedToken: { accessToken: string; refreshToken: string; expiresAt: number } | null = null\n\nexport function clearCachedToken(): void {\n cachedToken = null\n}\n\nexport async function refreshTokens(): Promise<void> {\n const credentials = getCredentials()\n if (!credentials?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-auth-refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n refresh_token: credentials.refreshToken,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: `HTTP ${response.status}` })) as { error?: string }\n const errorMessage = errorData.error || `HTTP ${response.status}`\n throw new Error(`Token refresh failed: ${errorMessage}`)\n }\n\n const tokens = await response.json() as TokenResponse\n \n saveCredentials({\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n email: credentials.email,\n })\n}\n\nexport async function exchangeApiKeyForToken(apiKey: string): Promise<TokenResponse> {\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-api-key-auth`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as { error?: string }\n throw new Error(errorData.error || `HTTP ${response.status}`)\n }\n\n return response.json() as Promise<TokenResponse>\n}\n\nexport async function loginWithBrowser(): Promise<{ email?: string }> {\n const state = generateState()\n const port = 8976\n const redirectUri = `http://localhost:${port}/callback`\n\n const appUrl = getAppUrl()\n const authUrl = new URL(`${appUrl}/auth/cli-login`)\n authUrl.searchParams.set('redirect_uri', redirectUri)\n authUrl.searchParams.set('state', state)\n\n const serverPromise = startCallbackServer(state, port)\n\n await open(authUrl.toString())\n\n const result = await serverPromise\n\n // New flow: API key based authentication\n if (result.apiKey) {\n saveCredentials({\n apiKey: result.apiKey,\n apiUrl: getApiUrl(),\n })\n return {}\n }\n\n // Legacy flow: session tokens (fallback)\n saveCredentials({\n accessToken: result.accessToken!,\n refreshToken: result.refreshToken!,\n expiresAt: Date.now() + (result.expiresIn || 3600) * 1000,\n apiUrl: getApiUrl(),\n })\n\n return {}\n}\n\nexport async function ensureAuthenticated(): Promise<string> {\n const credentials = getCredentials()\n\n if (!credentials) {\n throw new Error('Not authenticated. Run `envmanager login` first.')\n }\n\n // New flow: API key based authentication\n const storedApiKey = getStoredApiKey()\n if (storedApiKey) {\n // Return cached token if still valid (with 5-minute buffer)\n if (cachedToken && Date.now() < cachedToken.expiresAt - 5 * 60 * 1000) {\n return cachedToken.accessToken\n }\n\n const tokens = await exchangeApiKeyForToken(storedApiKey)\n cachedToken = {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n }\n return cachedToken.accessToken\n }\n\n // Legacy flow: session token refresh\n if (shouldRefreshToken() || isTokenExpired()) {\n try {\n await refreshTokens()\n const newCreds = getCredentials()\n if (newCreds?.accessToken) {\n return newCreds.accessToken\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Session refresh failed: ${message}\\nRun \\`envmanager login\\` to re-authenticate.`)\n }\n }\n\n if (!credentials.accessToken) {\n throw new Error('Not authenticated. Run `envmanager login` first.')\n }\n\n return credentials.accessToken\n}\n\nexport async function tryRefreshToken(): Promise<boolean> {\n try {\n if (shouldRefreshToken() || isTokenExpired()) {\n await refreshTokens()\n return true\n }\n return false\n } catch {\n return false\n }\n}\n","import { existsSync, readFileSync } from 'fs'\nimport { join, dirname } from 'path'\nimport { z } from 'zod'\n\nconst ConfigSchema = z.object({\n project_id: z.string().uuid().optional(),\n project_name: z.string().optional(),\n environment: z.string().optional(),\n environment_id: z.string().uuid().optional(),\n organization_id: z.string().uuid().optional(),\n output: z.string().default('.env'),\n api_url: z.string().url().optional()\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\n\nconst CONFIG_FILENAMES = ['envmanager.json', '.envmanagerrc']\n\nfunction findConfigFile(startDir: string = process.cwd()): string | null {\n let currentDir = startDir\n \n while (currentDir !== dirname(currentDir)) {\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename)\n if (existsSync(configPath)) {\n return configPath\n }\n }\n currentDir = dirname(currentDir)\n }\n \n return null\n}\n\nexport function loadConfig(): Config | null {\n const configPath = findConfigFile()\n \n if (!configPath) {\n return null\n }\n \n try {\n const content = readFileSync(configPath, 'utf-8')\n const parsed = JSON.parse(content)\n return ConfigSchema.parse(parsed)\n } catch (error) {\n if (error instanceof z.ZodError) {\n console.error('Invalid config file:', error.errors)\n }\n return null\n }\n}\n\nexport function getConfigPath(): string | null {\n return findConfigFile()\n}\n"],"mappings":"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","names":["DEFAULT_API_URL","getApiUrl","existsSync","readFileSync","join"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/client.ts","../src/lib/credentials.ts","../src/lib/auth.ts","../src/lib/config.ts"],"sourcesContent":["import { createClient as createSupabaseClient, SupabaseClient } from '@supabase/supabase-js'\nimport { getCredentials, getApiKeyFromEnv, getStoredApiUrl, getStoredApiKey } from './credentials.js'\nimport { ensureAuthenticated, exchangeApiKeyForToken, clearCachedToken } from './auth.js'\n\nconst DEFAULT_API_URL = 'https://rhopfaburfflrdwpowcd.supabase.co'\nconst DEFAULT_ANON_KEY = 'sb_publishable_Y2EpPiIN3KPjQMc1GLVXjw__ghRVLC4'\nconst LOCAL_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0'\n\nfunction getApiUrl(): string {\n return process.env.ENVMANAGER_API_URL || getStoredApiUrl() || DEFAULT_API_URL\n}\n\nfunction getAnonKey(): string {\n const apiUrl = getApiUrl()\n if (apiUrl.includes('localhost') || apiUrl.includes('127.0.0.1')) {\n return LOCAL_ANON_KEY\n }\n return process.env.ENVMANAGER_ANON_KEY || DEFAULT_ANON_KEY\n}\n\nlet clientInstance: SupabaseClient | null = null\nlet currentAccessToken: string | null = null\n\nexport async function createClient(): Promise<SupabaseClient> {\n if (clientInstance) {\n return clientInstance\n }\n\n // Priority: 1. Environment API key, 2. Stored API key (from login), 3. Session tokens\n const apiKey = getApiKeyFromEnv() || getStoredApiKey()\n\n if (apiKey) {\n const tokenResponse = await exchangeApiKeyForToken(apiKey)\n currentAccessToken = tokenResponse.access_token\n\n clientInstance = createSupabaseClient(getApiUrl(), getAnonKey(), {\n global: {\n headers: {\n Authorization: `Bearer ${currentAccessToken}`\n }\n }\n })\n\n await clientInstance.realtime.setAuth(currentAccessToken)\n return clientInstance\n }\n\n // Legacy flow: session tokens\n currentAccessToken = await ensureAuthenticated()\n\n clientInstance = createSupabaseClient(getApiUrl(), getAnonKey(), {\n global: {\n headers: {\n Authorization: `Bearer ${currentAccessToken}`\n }\n }\n })\n\n await clientInstance.realtime.setAuth(currentAccessToken)\n\n return clientInstance\n}\n\nexport function getAccessToken(): string | null {\n return currentAccessToken\n}\n\nexport async function refreshClientAuth(): Promise<void> {\n if (!clientInstance) return\n\n const accessToken = await ensureAuthenticated()\n currentAccessToken = accessToken\n\n // Update the realtime connection's auth token (preserves active channels)\n await clientInstance.realtime.setAuth(accessToken)\n}\n\nexport function resetClient(): void {\n clientInstance = null\n currentAccessToken = null\n clearCachedToken()\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'fs'\nimport { homedir } from 'os'\nimport { join } from 'path'\n\nconst CONFIG_DIR = join(homedir(), '.config', 'envmanager')\nconst CREDENTIALS_FILE = join(CONFIG_DIR, 'auth.json')\n\ninterface Credentials {\n // New flow: API key based auth (preferred)\n apiKey?: string\n // Legacy flow: session tokens\n accessToken?: string\n refreshToken?: string\n expiresAt?: number\n // Common\n apiUrl?: string\n email?: string\n}\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 })\n }\n}\n\nexport function getCredentials(): Credentials | null {\n if (!existsSync(CREDENTIALS_FILE)) {\n return null\n }\n\n try {\n const content = readFileSync(CREDENTIALS_FILE, 'utf-8')\n return JSON.parse(content) as Credentials\n } catch {\n return null\n }\n}\n\nexport function saveCredentials(credentials: Credentials): void {\n ensureConfigDir()\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { mode: 0o600 })\n chmodSync(CREDENTIALS_FILE, 0o600)\n}\n\nexport function clearCredentials(): void {\n if (existsSync(CREDENTIALS_FILE)) {\n unlinkSync(CREDENTIALS_FILE)\n }\n}\n\nexport function isTokenExpired(): boolean {\n const creds = getCredentials()\n if (!creds) return true\n // API key auth doesn't expire in the same way - let the server validate\n if (creds.apiKey) return false\n if (!creds.expiresAt) return true\n return Date.now() >= creds.expiresAt\n}\n\nconst PROACTIVE_REFRESH_BUFFER_MS = 5 * 60 * 1000\n\nexport function shouldRefreshToken(): boolean {\n const creds = getCredentials()\n if (!creds) return false\n // API key auth doesn't need proactive refresh\n if (creds.apiKey) return false\n if (!creds.expiresAt) return false\n return Date.now() >= (creds.expiresAt - PROACTIVE_REFRESH_BUFFER_MS)\n}\n\nexport function getApiKeyFromEnv(): string | null {\n return process.env.ENVMANAGER_API_KEY || null\n}\n\nexport function getStoredApiKey(): string | null {\n const creds = getCredentials()\n return creds?.apiKey || null\n}\n\nexport function getStoredApiUrl(): string | null {\n const creds = getCredentials()\n return creds?.apiUrl || null\n}\n","import { createServer, IncomingMessage, ServerResponse } from 'http'\nimport { randomBytes, createHash } from 'crypto'\nimport open from 'open'\nimport { saveCredentials, getCredentials, isTokenExpired, shouldRefreshToken, getStoredApiKey, getStoredApiUrl } from './credentials.js'\n\nconst DEFAULT_APP_URL = 'https://envmanager.com'\nconst DEFAULT_API_URL = 'https://rhopfaburfflrdwpowcd.supabase.co'\n\nfunction getAppUrl(): string {\n return process.env.ENVMANAGER_APP_URL || DEFAULT_APP_URL\n}\n\nfunction getApiUrl(): string {\n return process.env.ENVMANAGER_API_URL || getStoredApiUrl() || DEFAULT_API_URL\n}\n\nfunction generateCodeVerifier(): string {\n return randomBytes(32).toString('base64url')\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return createHash('sha256').update(verifier).digest('base64url')\n}\n\nfunction generateState(): string {\n return randomBytes(16).toString('hex')\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\ninterface AuthCallbackResult {\n apiKey?: string\n accessToken?: string\n refreshToken?: string\n expiresIn?: number\n}\n\nasync function startCallbackServer(expectedState: string, port: number = 8976): Promise<AuthCallbackResult> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close()\n reject(new Error('Authentication timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`)\n \n if (url.pathname === '/callback') {\n const apiKey = url.searchParams.get('api_key')\n const accessToken = url.searchParams.get('access_token')\n const refreshToken = url.searchParams.get('refresh_token')\n const expiresIn = url.searchParams.get('expires_in')\n const state = url.searchParams.get('state')\n const error = url.searchParams.get('error')\n const errorDescription = url.searchParams.get('error_description')\n\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Authentication Failed</h1>\n <p>${escapeHtml(errorDescription || error || 'Unknown error')}</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error(errorDescription || error))\n return\n }\n\n // Accept either API key (new flow) or session tokens (legacy/fallback)\n if (!apiKey && (!accessToken || !refreshToken)) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Invalid Callback</h1>\n <p>Missing authentication credentials.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error('Invalid callback: missing credentials'))\n return\n }\n\n if (!state || state !== expectedState) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Invalid State</h1>\n <p>State mismatch - possible CSRF attack.</p>\n </body>\n </html>\n `)\n clearTimeout(timeout)\n server.close()\n reject(new Error('State mismatch - authentication failed'))\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html>\n <body style=\"font-family: system-ui; padding: 40px; text-align: center;\">\n <h1>Authentication Successful!</h1>\n <p>You can close this window and return to your terminal.</p>\n </body>\n </html>\n `)\n\n clearTimeout(timeout)\n server.close()\n\n // Return API key if present (new flow), otherwise return tokens (legacy)\n if (apiKey) {\n resolve({ apiKey })\n } else {\n resolve({\n accessToken: accessToken!,\n refreshToken: refreshToken!,\n expiresIn: parseInt(expiresIn || '3600', 10)\n })\n }\n } else {\n res.writeHead(404)\n res.end('Not found')\n }\n })\n\n server.listen(port, '127.0.0.1', () => {})\n \n server.on('error', (err: Error & { code?: string }) => {\n clearTimeout(timeout)\n if (err.code === 'EADDRINUSE') {\n reject(new Error(`Port ${port} is already in use. Please close the application using it.`))\n } else {\n reject(err)\n }\n })\n })\n}\n\ninterface TokenResponse {\n access_token: string\n refresh_token: string\n expires_in: number\n user?: {\n id: string\n email?: string\n }\n}\n\nasync function exchangeCodeForTokens(code: string, codeVerifier: string): Promise<TokenResponse> {\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-auth-callback`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n code,\n code_verifier: codeVerifier,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as { error?: string }\n throw new Error(errorData.error || `HTTP ${response.status}`)\n }\n\n return response.json() as Promise<TokenResponse>\n}\n\n// In-memory cache for exchanged API key tokens (process lifetime only)\nlet cachedToken: { accessToken: string; refreshToken: string; expiresAt: number } | null = null\n\nexport function clearCachedToken(): void {\n cachedToken = null\n}\n\nexport async function refreshTokens(): Promise<void> {\n const credentials = getCredentials()\n if (!credentials?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-auth-refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n refresh_token: credentials.refreshToken,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: `HTTP ${response.status}` })) as { error?: string }\n const errorMessage = errorData.error || `HTTP ${response.status}`\n throw new Error(`Token refresh failed: ${errorMessage}`)\n }\n\n const tokens = await response.json() as TokenResponse\n \n saveCredentials({\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n email: credentials.email,\n })\n}\n\nexport async function exchangeApiKeyForToken(apiKey: string): Promise<TokenResponse> {\n const apiUrl = getApiUrl()\n const response = await fetch(`${apiUrl}/functions/v1/cli-api-key-auth`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as { error?: string }\n throw new Error(errorData.error || `HTTP ${response.status}`)\n }\n\n return response.json() as Promise<TokenResponse>\n}\n\nexport async function loginWithBrowser(): Promise<{ email?: string }> {\n const state = generateState()\n const port = 8976\n const redirectUri = `http://localhost:${port}/callback`\n\n const appUrl = getAppUrl()\n const authUrl = new URL(`${appUrl}/auth/cli-login`)\n authUrl.searchParams.set('redirect_uri', redirectUri)\n authUrl.searchParams.set('state', state)\n\n const serverPromise = startCallbackServer(state, port)\n\n await open(authUrl.toString())\n\n const result = await serverPromise\n\n // New flow: API key based authentication\n if (result.apiKey) {\n saveCredentials({\n apiKey: result.apiKey,\n apiUrl: getApiUrl(),\n })\n return {}\n }\n\n // Legacy flow: session tokens (fallback)\n saveCredentials({\n accessToken: result.accessToken!,\n refreshToken: result.refreshToken!,\n expiresAt: Date.now() + (result.expiresIn || 3600) * 1000,\n apiUrl: getApiUrl(),\n })\n\n return {}\n}\n\nexport async function ensureAuthenticated(): Promise<string> {\n const credentials = getCredentials()\n\n if (!credentials) {\n throw new Error('Not authenticated. Run `envmanager login` first.')\n }\n\n // New flow: API key based authentication\n const storedApiKey = getStoredApiKey()\n if (storedApiKey) {\n // Return cached token if still valid (with 5-minute buffer)\n if (cachedToken && Date.now() < cachedToken.expiresAt - 5 * 60 * 1000) {\n return cachedToken.accessToken\n }\n\n const tokens = await exchangeApiKeyForToken(storedApiKey)\n cachedToken = {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token,\n expiresAt: Date.now() + tokens.expires_in * 1000,\n }\n return cachedToken.accessToken\n }\n\n // Legacy flow: session token refresh\n if (shouldRefreshToken() || isTokenExpired()) {\n try {\n await refreshTokens()\n const newCreds = getCredentials()\n if (newCreds?.accessToken) {\n return newCreds.accessToken\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Session refresh failed: ${message}\\nRun \\`envmanager login\\` to re-authenticate.`)\n }\n }\n\n if (!credentials.accessToken) {\n throw new Error('Not authenticated. Run `envmanager login` first.')\n }\n\n return credentials.accessToken\n}\n\nexport async function tryRefreshToken(): Promise<boolean> {\n try {\n if (shouldRefreshToken() || isTokenExpired()) {\n await refreshTokens()\n return true\n }\n return false\n } catch {\n return false\n }\n}\n","import { existsSync, readFileSync } from 'fs'\nimport { join, dirname } from 'path'\nimport { z } from 'zod'\n\nconst ConfigSchema = z.object({\n project_id: z.string().uuid().optional(),\n project_name: z.string().optional(),\n environment: z.string().optional(),\n environment_id: z.string().uuid().optional(),\n organization_id: z.string().uuid().optional(),\n output: z.string().default('.env'),\n api_url: z.string().url().optional()\n})\n\nexport type Config = z.infer<typeof ConfigSchema>\n\nconst CONFIG_FILENAMES = ['envmanager.json', '.envmanagerrc']\n\nfunction findConfigFile(startDir: string = process.cwd()): string | null {\n let currentDir = startDir\n \n while (currentDir !== dirname(currentDir)) {\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename)\n if (existsSync(configPath)) {\n return configPath\n }\n }\n currentDir = dirname(currentDir)\n }\n \n return null\n}\n\nexport function loadConfig(): Config | null {\n const configPath = findConfigFile()\n \n if (!configPath) {\n return null\n }\n \n try {\n const content = readFileSync(configPath, 'utf-8')\n const parsed = JSON.parse(content)\n return ConfigSchema.parse(parsed)\n } catch (error) {\n if (error instanceof z.ZodError) {\n console.error('Invalid config file:', error.errors)\n }\n return null\n }\n}\n\nexport function getConfigPath(): string | null {\n return findConfigFile()\n}\n"],"mappings":"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","names":["DEFAULT_API_URL","getApiUrl","existsSync","readFileSync","join"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@envmanager-cli/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for EnvManager - secure environment variable management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@supabase/supabase-js": "^2.45.0",
|
|
56
56
|
"chalk": "^5.3.0",
|
|
57
|
-
"commander": "^
|
|
57
|
+
"commander": "^14.0.3",
|
|
58
58
|
"dotenv": "^16.4.5",
|
|
59
59
|
"js-yaml": "^4.1.0",
|
|
60
|
-
"open": "^
|
|
60
|
+
"open": "^11.0.0",
|
|
61
61
|
"ora": "^8.0.1",
|
|
62
62
|
"zod": "^3.23.8"
|
|
63
63
|
},
|
|
@@ -66,6 +66,6 @@
|
|
|
66
66
|
"@types/node": "^20.14.0",
|
|
67
67
|
"tsup": "^8.1.0",
|
|
68
68
|
"typescript": "^5.5.0",
|
|
69
|
-
"vitest": "^
|
|
69
|
+
"vitest": "^4.0.18"
|
|
70
70
|
}
|
|
71
71
|
}
|