UNPKG

@swell/cli

Version:

Swell's command line interface/utility

163 lines (162 loc) 5.5 kB
import { getCurrentAppSlugId } from '../apps/index.js'; import { classifyIdentifier, resolveInspectScope, } from '../apps/inspect-scope.js'; import { HEX24 } from '../apps/object-id.js'; import { resolveAppId } from '../apps/resolve.js'; export const WORKFLOW_STATUSES = [ 'active', 'failed', 'completed', 'terminated', ]; export const WORKFLOW_INSTANCE_ID_PATTERN = /^wf_inst_[\dA-Za-z]+$/; const REDACTED_WORKFLOW_FIELDS = new Set([ 'access_token', 'api_key', 'authorization', 'bearer_token', 'cf_api_token', 'cloudflare_token', 'installed_app_id', 'params', 'private_key', 'public_key', 'runtime_token', 'secret_key', 'token', 'token_hash', ]); const RELATIVE_TIME_FORMAT = new Intl.RelativeTimeFormat('en', { numeric: 'auto', }); export async function resolveWorkflowOperationRef(api, workflow, flags) { const kind = classifyIdentifier(workflow); if (kind.kind === 'slug') { const appId = HEX24.test(kind.appPart) ? kind.appPart : await resolveAppId(api, kind.appPart); return { appId, appSlug: kind.appPart, query: { workflow_name: kind.name }, }; } if (kind.kind === 'id') { const manifest = await api.get({ adminPath: `/data/:functions/${kind.id}`, }); if (!manifest?.app_id) { throw new Error(`Workflow manifest '${workflow}' does not have an app_id. Pass app.<app>.<workflow> or --app=<slug>.`); } const workflowName = workflowDisplayName(manifest); if (workflowName === kind.id || workflowName === '-') { throw new Error(`Workflow manifest '${workflow}' does not have a workflow name. Pass app.<app>.<workflow> or --app=<slug>.`); } return { appId: manifest.app_id, query: { workflow_id: kind.id, workflow_name: workflowName }, }; } if (kind.kind === 'name') { const scope = await resolveWorkflowScope(api, flags); if (!scope.appId) { throw new Error(`Bare workflow name '${workflow}' requires --app=<slug> or --app=. to scope. Alternatively, pass app.<app>.<workflow> or a 24-char manifest id.`); } return { appId: scope.appId, appSlug: scope.appSlug, query: { workflow_name: workflow }, }; } throw new Error(`Invalid workflow identifier '${workflow}'. Expected bare name, app.<app>.<workflow>, or 24-char manifest id.`); } export async function resolveWorkflowScope(api, flags) { return resolveInspectScope({ resolveAppId: (slug) => resolveAppId(api, slug), readCurrentAppSlug: () => getCurrentAppSlugId(), }, flags); } export function isWorkflowInstanceIdentifier(value) { return WORKFLOW_INSTANCE_ID_PATTERN.test(value); } export function workflowDisplayName(record) { return record.workflow_name || record.name || record.id || '-'; } export function workflowListMeta(record) { const parts = []; const summary = record.summary || {}; if (!record.enabled) { parts.push('disabled'); } if (summary.active_instances) { parts.push(`active ${summary.active_instances}`); } if (summary.failed_instances) { parts.push(`failed ${summary.failed_instances}`); } if (summary.completed_recent) { parts.push(`completed ${summary.completed_recent}`); } if (summary.terminated_recent) { parts.push(`terminated ${summary.terminated_recent}`); } return parts.join(' · '); } export function workflowRunDate(run) { return (run.date_failed || run.date_terminated || run.date_completed || run.date_started || run.date_created); } export function workflowRunMeta(run) { const parts = []; if (run.status) { parts.push(run.status); } const date = workflowRunDate(run); if (date) { parts.push(formatWorkflowRelativeTime(date)); } return parts.join(' · '); } export function formatWorkflowRelativeTime(value, now = Date.now()) { const timestamp = Date.parse(value); if (!Number.isFinite(timestamp)) { return value; } const diffSeconds = Math.round((timestamp - now) / 1000); const absSeconds = Math.abs(diffSeconds); if (absSeconds < 60) { return RELATIVE_TIME_FORMAT.format(diffSeconds, 'second'); } if (absSeconds < 60 * 60) { return RELATIVE_TIME_FORMAT.format(Math.round(diffSeconds / 60), 'minute'); } if (absSeconds < 24 * 60 * 60) { return RELATIVE_TIME_FORMAT.format(Math.round(diffSeconds / (60 * 60)), 'hour'); } if (absSeconds < 30 * 24 * 60 * 60) { return RELATIVE_TIME_FORMAT.format(Math.round(diffSeconds / (24 * 60 * 60)), 'day'); } return value; } export function redactWorkflowPayload(value) { if (Array.isArray(value)) { return value.map((item) => redactWorkflowPayload(item)); } if (!value || typeof value !== 'object') { if (typeof value === 'string' && value.startsWith('wf_rt_')) { return '[redacted]'; } return value; } const result = {}; for (const [key, child] of Object.entries(value)) { if (REDACTED_WORKFLOW_FIELDS.has(key.toLowerCase())) { result[key] = '[redacted]'; continue; } result[key] = redactWorkflowPayload(child); } return result; }