154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
import color from 'kleur'
|
|
import { del, get, handleError, post } from '../http'
|
|
import { resolveAppName } from '../name'
|
|
|
|
interface EnvVar {
|
|
key: string
|
|
value: string
|
|
}
|
|
|
|
function parseKeyValue(keyOrKeyValue: string, valueArg?: string): { key: string, value: string } | null {
|
|
if (valueArg !== undefined) {
|
|
const key = keyOrKeyValue.trim()
|
|
if (!key) { console.error('Key cannot be empty'); return null }
|
|
return { key, value: valueArg }
|
|
}
|
|
const eqIndex = keyOrKeyValue.indexOf('=')
|
|
if (eqIndex === -1) {
|
|
console.error('Invalid format. Use: KEY value or KEY=value')
|
|
return null
|
|
}
|
|
const key = keyOrKeyValue.slice(0, eqIndex).trim()
|
|
if (!key) { console.error('Key cannot be empty'); return null }
|
|
return { key, value: keyOrKeyValue.slice(eqIndex + 1) }
|
|
}
|
|
|
|
async function globalEnvSet(keyOrKeyValue: string, valueArg?: string) {
|
|
const parsed = parseKeyValue(keyOrKeyValue, valueArg)
|
|
if (!parsed) return
|
|
const { key, value } = parsed
|
|
|
|
try {
|
|
const result = await post<{ ok: boolean, error?: string }>('/api/env', { key, value })
|
|
if (result?.ok) {
|
|
console.log(color.green(`Set global ${color.bold(key.toUpperCase())}`))
|
|
} else {
|
|
console.error(result?.error ?? 'Failed to set variable')
|
|
}
|
|
} catch (error) {
|
|
handleError(error)
|
|
}
|
|
}
|
|
|
|
export async function envList(name: string | undefined, opts: { global?: boolean }) {
|
|
if (opts.global) {
|
|
const vars = await get<EnvVar[]>('/api/env')
|
|
console.log(color.bold().cyan('Global Environment Variables'))
|
|
console.log()
|
|
if (!vars || vars.length === 0) {
|
|
console.log(color.gray(' No global environment variables set'))
|
|
return
|
|
}
|
|
for (const v of vars) {
|
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
|
}
|
|
return
|
|
}
|
|
|
|
const appName = resolveAppName(name)
|
|
if (!appName) return
|
|
|
|
const [vars, globalVars] = await Promise.all([
|
|
get<EnvVar[]>(`/api/apps/${appName}/env`),
|
|
get<EnvVar[]>('/api/env'),
|
|
])
|
|
|
|
if (!vars) {
|
|
console.error(`App not found: ${appName}`)
|
|
return
|
|
}
|
|
|
|
console.log(color.bold().cyan(`Environment Variables for ${appName}`))
|
|
console.log()
|
|
|
|
const appKeys = new Set(vars.map(v => v.key))
|
|
|
|
if (vars.length === 0 && (!globalVars || globalVars.length === 0)) {
|
|
console.log(color.gray(' No environment variables set'))
|
|
return
|
|
}
|
|
|
|
for (const v of vars) {
|
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
|
}
|
|
|
|
if (globalVars && globalVars.length > 0) {
|
|
const inherited = globalVars.filter(v => !appKeys.has(v.key))
|
|
if (inherited.length > 0) {
|
|
if (vars.length > 0) console.log()
|
|
console.log(color.gray(' Inherited from global:'))
|
|
for (const v of inherited) {
|
|
console.log(` ${color.bold(v.key)}=${color.gray(v.value)}`)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function envSet(name: string | undefined, keyOrKeyValue: string, valueArg: string | undefined, opts: { global?: boolean }) {
|
|
// With --global, args shift: name becomes key, key becomes value
|
|
if (opts.global) {
|
|
const actualKey = name ?? keyOrKeyValue
|
|
const actualValue = name ? keyOrKeyValue : valueArg
|
|
return globalEnvSet(actualKey, actualValue)
|
|
}
|
|
|
|
const parsed = parseKeyValue(keyOrKeyValue, valueArg)
|
|
if (!parsed) return
|
|
const { key, value } = parsed
|
|
|
|
const appName = resolveAppName(name)
|
|
if (!appName) return
|
|
|
|
try {
|
|
const result = await post<{ ok: boolean, error?: string }>(`/api/apps/${appName}/env`, { key, value })
|
|
if (result?.ok) {
|
|
console.log(color.green(`Set ${color.bold(key.toUpperCase())} for ${appName}`))
|
|
console.log(color.gray('App restarted to apply changes'))
|
|
} else {
|
|
console.error(result?.error ?? 'Failed to set variable')
|
|
}
|
|
} catch (error) {
|
|
handleError(error)
|
|
}
|
|
}
|
|
|
|
export async function envRm(name: string | undefined, key: string, opts: { global?: boolean }) {
|
|
// With --global, args shift: name becomes key
|
|
if (opts.global) {
|
|
const actualKey = name ?? key
|
|
if (!actualKey) {
|
|
console.error('Key is required')
|
|
return
|
|
}
|
|
const ok = await del(`/api/env/${actualKey.toUpperCase()}`)
|
|
if (ok) {
|
|
console.log(color.green(`Removed global ${color.bold(actualKey.toUpperCase())}`))
|
|
}
|
|
return
|
|
}
|
|
|
|
if (!key) {
|
|
console.error('Key is required')
|
|
return
|
|
}
|
|
|
|
const appName = resolveAppName(name)
|
|
if (!appName) return
|
|
|
|
const ok = await del(`/api/apps/${appName}/env/${key.toUpperCase()}`)
|
|
if (ok) {
|
|
console.log(color.green(`Removed ${color.bold(key.toUpperCase())} from ${appName}`))
|
|
console.log(color.gray('App restarted to apply changes'))
|
|
}
|
|
}
|