@rawdash/cli 0.16.0 → 0.18.0
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 +4 -0
- package/dist/bin.js +44 -12
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -56,6 +56,10 @@ The CLI expects the following environment variables:
|
|
|
56
56
|
| `RAWDASH_API_KEY` | Yes (for deploy/secrets) | API key for the rawdash server |
|
|
57
57
|
| `RAWDASH_URL` | No | Server base URL (defaults to the hosted service) |
|
|
58
58
|
|
|
59
|
+
When pointing at the hosted service, `RAWDASH_URL` must include your org slug,
|
|
60
|
+
e.g. `https://api.rawdash.dev/<org-slug>`. A slug-less base URL is rejected with
|
|
61
|
+
a `403`, even with a fully-scoped key.
|
|
62
|
+
|
|
59
63
|
## Links
|
|
60
64
|
|
|
61
65
|
- [rawdash docs](https://rawdash.dev)
|
package/dist/bin.js
CHANGED
|
@@ -65,30 +65,56 @@ async function postConfig(config, dryRun) {
|
|
|
65
65
|
const diff = await res.json();
|
|
66
66
|
return { ok: true, diff };
|
|
67
67
|
}
|
|
68
|
-
return buildDeployFailure(res);
|
|
68
|
+
return buildDeployFailure(res, url, endpoint);
|
|
69
69
|
}
|
|
70
|
-
async function buildDeployFailure(res) {
|
|
70
|
+
async function buildDeployFailure(res, baseUrl, endpoint) {
|
|
71
71
|
const { body, text } = await readErrorBody(res);
|
|
72
72
|
const rawMessage = body.error ?? body.message ?? (text || res.statusText);
|
|
73
73
|
let error;
|
|
74
74
|
if (res.status === 401) {
|
|
75
75
|
error = `API key invalid or revoked. Check RAWDASH_API_KEY. (${rawMessage})`;
|
|
76
76
|
} else if (res.status === 403) {
|
|
77
|
-
error =
|
|
77
|
+
error = buildForbiddenMessage(body, rawMessage, baseUrl, endpoint);
|
|
78
78
|
} else if (res.status === 409) {
|
|
79
79
|
error = `Org is in ui source-of-truth mode. Switch to git mode in cloud settings, or push UI changes back into your config first.`;
|
|
80
80
|
} else if (res.status === 422) {
|
|
81
81
|
error = `Validation failed: ${rawMessage}`;
|
|
82
82
|
} else {
|
|
83
|
-
error = `Request failed (${res.status}): ${rawMessage}`;
|
|
83
|
+
error = `Request failed (${res.status}): ${rawMessage}${requestContext(res.status, baseUrl, endpoint)}`;
|
|
84
84
|
}
|
|
85
85
|
return { ok: false, error, status: res.status, conflicts: body.conflicts };
|
|
86
86
|
}
|
|
87
|
+
function buildForbiddenMessage(body, rawMessage, baseUrl, endpoint) {
|
|
88
|
+
if (body.code === "insufficient_scope") {
|
|
89
|
+
const scope = body.required ?? "config:write";
|
|
90
|
+
return `Key lacks the "${scope}" scope. Get a new key with broader scope. (${rawMessage})`;
|
|
91
|
+
}
|
|
92
|
+
const code = body.code ? ` [${body.code}]` : "";
|
|
93
|
+
return `Forbidden (403): ${rawMessage}${code}${requestContext(403, baseUrl, endpoint)}`;
|
|
94
|
+
}
|
|
95
|
+
function requestContext(status, baseUrl, endpoint) {
|
|
96
|
+
let context = `
|
|
97
|
+
Request URL: ${endpoint}`;
|
|
98
|
+
if ((status === 403 || status === 404) && isSluglessUrl(baseUrl)) {
|
|
99
|
+
context += `
|
|
100
|
+
RAWDASH_URL has no org slug. The hosted service expects https://api.rawdash.dev/<org-slug>; a slug-less URL is rejected with 403.`;
|
|
101
|
+
}
|
|
102
|
+
return context;
|
|
103
|
+
}
|
|
104
|
+
function isSluglessUrl(baseUrl) {
|
|
105
|
+
try {
|
|
106
|
+
const { pathname } = new URL(baseUrl);
|
|
107
|
+
return pathname === "" || pathname === "/";
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
87
112
|
async function setSecret(name, value) {
|
|
88
113
|
const { url, apiKey } = getEnv();
|
|
114
|
+
const endpoint = `${url}/secrets`;
|
|
89
115
|
let res;
|
|
90
116
|
try {
|
|
91
|
-
res = await fetch(
|
|
117
|
+
res = await fetch(endpoint, {
|
|
92
118
|
method: "POST",
|
|
93
119
|
headers: {
|
|
94
120
|
"Content-Type": "application/json",
|
|
@@ -101,14 +127,15 @@ async function setSecret(name, value) {
|
|
|
101
127
|
throw new ApiError(wrapFetchError(err), 0);
|
|
102
128
|
}
|
|
103
129
|
if (!res.ok) {
|
|
104
|
-
await throwApiError(res);
|
|
130
|
+
await throwApiError(res, url, endpoint);
|
|
105
131
|
}
|
|
106
132
|
}
|
|
107
133
|
async function listSecrets() {
|
|
108
134
|
const { url, apiKey } = getEnv();
|
|
135
|
+
const endpoint = `${url}/secrets`;
|
|
109
136
|
let res;
|
|
110
137
|
try {
|
|
111
|
-
res = await fetch(
|
|
138
|
+
res = await fetch(endpoint, {
|
|
112
139
|
headers: { Authorization: `Bearer ${apiKey ?? ""}` },
|
|
113
140
|
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
114
141
|
});
|
|
@@ -116,16 +143,17 @@ async function listSecrets() {
|
|
|
116
143
|
throw new ApiError(wrapFetchError(err), 0);
|
|
117
144
|
}
|
|
118
145
|
if (!res.ok) {
|
|
119
|
-
await throwApiError(res);
|
|
146
|
+
await throwApiError(res, url, endpoint);
|
|
120
147
|
}
|
|
121
148
|
const body = await res.json();
|
|
122
149
|
return body.secrets;
|
|
123
150
|
}
|
|
124
151
|
async function removeSecret(name) {
|
|
125
152
|
const { url, apiKey } = getEnv();
|
|
153
|
+
const endpoint = `${url}/secrets/${encodeURIComponent(name)}`;
|
|
126
154
|
let res;
|
|
127
155
|
try {
|
|
128
|
-
res = await fetch(
|
|
156
|
+
res = await fetch(endpoint, {
|
|
129
157
|
method: "DELETE",
|
|
130
158
|
headers: { Authorization: `Bearer ${apiKey ?? ""}` },
|
|
131
159
|
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS)
|
|
@@ -134,7 +162,7 @@ async function removeSecret(name) {
|
|
|
134
162
|
throw new ApiError(wrapFetchError(err), 0);
|
|
135
163
|
}
|
|
136
164
|
if (!res.ok) {
|
|
137
|
-
await throwApiError(res);
|
|
165
|
+
await throwApiError(res, url, endpoint);
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
function wrapFetchError(err) {
|
|
@@ -143,10 +171,14 @@ function wrapFetchError(err) {
|
|
|
143
171
|
}
|
|
144
172
|
return `Network error: ${err instanceof Error ? err.message : String(err)}`;
|
|
145
173
|
}
|
|
146
|
-
async function throwApiError(res) {
|
|
174
|
+
async function throwApiError(res, baseUrl, endpoint) {
|
|
147
175
|
const { body, text } = await readErrorBody(res);
|
|
148
176
|
const message = body.error ?? body.message ?? (text || res.statusText);
|
|
149
|
-
|
|
177
|
+
const code = body.code ? ` [${body.code}]` : "";
|
|
178
|
+
throw new ApiError(
|
|
179
|
+
`API error (${res.status}): ${message}${code}${requestContext(res.status, baseUrl, endpoint)}`,
|
|
180
|
+
res.status
|
|
181
|
+
);
|
|
150
182
|
}
|
|
151
183
|
async function readErrorBody(res) {
|
|
152
184
|
const text = await res.text();
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bin.ts","../src/commands/deploy.ts","../src/lib/api-client.ts","../src/lib/env.ts","../src/lib/config-loader.ts","../src/lib/output.ts","../src/commands/secrets.ts","../src/commands/validate.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { deployCommand } from './commands/deploy';\nimport { secretsCommand } from './commands/secrets';\nimport { validateCommand } from './commands/validate';\n\nconst pkg = JSON.parse(\n readFileSync(\n join(dirname(fileURLToPath(import.meta.url)), '../package.json'),\n 'utf8',\n ),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('rawdash')\n .description('Rawdash CLI — deploy and manage your dashboard config')\n .version(pkg.version);\n\nprogram.addCommand(deployCommand);\nprogram.addCommand(secretsCommand);\nprogram.addCommand(validateCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n","import { confirm, isCancel, spinner } from '@clack/prompts';\nimport { Command } from 'commander';\n\nimport { postConfig } from '../lib/api-client';\nimport { findConfigFile, loadConfig } from '../lib/config-loader';\nimport { requireApiKey } from '../lib/env';\nimport { printDiff, printError, printSuccess } from '../lib/output';\n\nexport const deployCommand = new Command('deploy')\n .description('Deploy rawdash.config.ts to the server')\n .option('--config <path>', 'path to rawdash.config.ts')\n .option('--dry-run', 'validate and diff without persisting')\n .option('--yes', 'skip confirmation prompt (useful in CI)')\n .action(\n async (opts: { config?: string; dryRun?: boolean; yes?: boolean }) => {\n requireApiKey();\n\n const configPath = await findConfigFile(opts.config).catch(\n (err: unknown) => {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n },\n );\n\n const s = spinner();\n s.start('Loading config...');\n\n const config = await loadConfig(configPath).catch((err: unknown) => {\n s.stop('Failed to load config');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n });\n s.stop('Config loaded');\n\n s.start('Fetching diff...');\n const previewResult = await postConfig(config, true);\n s.stop('');\n\n if (!previewResult.ok) {\n printError(previewResult.error);\n process.exit(exitCodeForStatus(previewResult.status));\n }\n\n printDiff(previewResult.diff);\n\n if (opts.dryRun) {\n printSuccess('Dry run complete — no changes applied');\n return;\n }\n\n if (!opts.yes) {\n const confirmed = await confirm({ message: 'Apply this diff?' });\n if (isCancel(confirmed) || !confirmed) {\n console.log('Aborted.');\n process.exit(0);\n }\n }\n\n s.start('Deploying...');\n const deployResult = await postConfig(config, false);\n s.stop('');\n\n if (!deployResult.ok) {\n printError(deployResult.error);\n process.exit(exitCodeForStatus(deployResult.status));\n }\n\n printSuccess('Deployed');\n },\n );\n\nfunction exitCodeForStatus(status: number): number {\n if (status === 401 || status === 403) {\n return 3;\n }\n if (status === 409) {\n return 4;\n }\n if (status === 422) {\n return 2;\n }\n return 1;\n}\n","import { type DashboardConfig, toWireConfig } from '@rawdash/core';\n\nimport { getEnv } from './env';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport interface Diff<T> {\n added: T[];\n removed: T[];\n modified: T[];\n}\n\nexport interface CloudConnectorRecord {\n name: string;\n connectorId: string;\n displayName?: string | null;\n config: Record<string, unknown>;\n syncIntervalSeconds?: number;\n enabled?: boolean;\n}\n\nexport interface CloudDashboardRecord {\n id: string;\n name: string;\n slug: string;\n config: Record<string, unknown>;\n}\n\nexport interface ConfigDiff {\n connectors: Diff<CloudConnectorRecord>;\n dashboards: Diff<CloudDashboardRecord>;\n}\n\nexport interface DeploySuccess {\n ok: true;\n diff: ConfigDiff;\n}\n\nexport interface DeployFailure {\n ok: false;\n error: string;\n status: number;\n conflicts?: string[];\n}\n\nexport type DeployResult = DeploySuccess | DeployFailure;\n\nexport interface CloudSecret {\n name: string;\n lastRotatedAt: string | null;\n}\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function postConfig(\n config: DashboardConfig,\n dryRun: boolean,\n): Promise<DeployResult> {\n const { url, apiKey } = getEnv();\n const endpoint = `${url}/config${dryRun ? '?dryRun=true' : ''}`;\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey ?? ''}`,\n },\n body: JSON.stringify(toWireConfig(config)),\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n const isTimeout =\n err instanceof Error &&\n (err.name === 'AbortError' || err.name === 'TimeoutError');\n return {\n ok: false,\n error: isTimeout\n ? 'Request timed out'\n : `Network error: ${err instanceof Error ? err.message : String(err)}`,\n status: 0,\n };\n }\n\n if (res.ok) {\n const diff = (await res.json()) as ConfigDiff;\n return { ok: true, diff };\n }\n\n return buildDeployFailure(res);\n}\n\nasync function buildDeployFailure(res: Response): Promise<DeployFailure> {\n const { body, text } = await readErrorBody(res);\n const rawMessage = body.error ?? body.message ?? (text || res.statusText);\n\n let error: string;\n if (res.status === 401) {\n error = `API key invalid or revoked. Check RAWDASH_API_KEY. (${rawMessage})`;\n } else if (res.status === 403) {\n error = `Key lacks config:write scope. Get a new key with broader scope. (${rawMessage})`;\n } else if (res.status === 409) {\n error = `Org is in ui source-of-truth mode. Switch to git mode in cloud settings, or push UI changes back into your config first.`;\n } else if (res.status === 422) {\n error = `Validation failed: ${rawMessage}`;\n } else {\n error = `Request failed (${res.status}): ${rawMessage}`;\n }\n\n return { ok: false, error, status: res.status, conflicts: body.conflicts };\n}\n\nexport async function setSecret(name: string, value: string): Promise<void> {\n const { url, apiKey } = getEnv();\n\n let res: Response;\n try {\n res = await fetch(`${url}/secrets`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey ?? ''}`,\n },\n body: JSON.stringify({ name, value }),\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res);\n }\n}\n\nexport async function listSecrets(): Promise<CloudSecret[]> {\n const { url, apiKey } = getEnv();\n\n let res: Response;\n try {\n res = await fetch(`${url}/secrets`, {\n headers: { Authorization: `Bearer ${apiKey ?? ''}` },\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res);\n }\n const body = (await res.json()) as { secrets: CloudSecret[] };\n return body.secrets;\n}\n\nexport async function removeSecret(name: string): Promise<void> {\n const { url, apiKey } = getEnv();\n\n let res: Response;\n try {\n res = await fetch(`${url}/secrets/${encodeURIComponent(name)}`, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${apiKey ?? ''}` },\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res);\n }\n}\n\nfunction wrapFetchError(err: unknown): string {\n if (\n err instanceof Error &&\n (err.name === 'AbortError' || err.name === 'TimeoutError')\n ) {\n return 'Request timed out';\n }\n return `Network error: ${err instanceof Error ? err.message : String(err)}`;\n}\n\nasync function throwApiError(res: Response): Promise<never> {\n const { body, text } = await readErrorBody(res);\n const message = body.error ?? body.message ?? (text || res.statusText);\n throw new ApiError(`API error (${res.status}): ${message}`, res.status);\n}\n\nasync function readErrorBody(res: Response): Promise<{\n body: { error?: string; message?: string; conflicts?: string[] };\n text: string;\n}> {\n const text = await res.text();\n const contentType = res.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n return {\n body: JSON.parse(text) as {\n error?: string;\n message?: string;\n conflicts?: string[];\n },\n text,\n };\n } catch {\n // body claimed JSON but wasn't — fall through to text\n }\n }\n return { body: {}, text };\n}\n","export function getEnv(): { url: string; apiKey: string | undefined } {\n return {\n url: process.env['RAWDASH_URL'] ?? 'https://api.rawdash.dev',\n apiKey: process.env['RAWDASH_API_KEY'],\n };\n}\n\nexport function requireApiKey(): string {\n const { apiKey } = getEnv();\n if (!apiKey) {\n console.error('RAWDASH_API_KEY is not set. Set it in your environment.');\n process.exit(3);\n }\n return apiKey;\n}\n","import { type DashboardConfig, defineConfig } from '@rawdash/core';\nimport { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { tsImport } from 'tsx/esm/api';\n\nexport async function findConfigFile(explicitPath?: string): Promise<string> {\n if (explicitPath) {\n const abs = resolve(explicitPath);\n if (!existsSync(abs)) {\n throw new Error(`Config file not found: ${abs}`);\n }\n return abs;\n }\n\n let dir = process.cwd();\n for (;;) {\n const candidate = join(dir, 'rawdash.config.ts');\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n break;\n }\n dir = parent;\n }\n\n throw new Error(\n 'Could not find rawdash.config.ts. Pass --config <path> to specify it explicitly.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<DashboardConfig> {\n const mod = await tsImport(configPath, import.meta.url);\n const config: unknown =\n (mod as { default?: unknown; config?: unknown }).default ??\n (mod as { config?: unknown }).config;\n if (!config || typeof config !== 'object') {\n throw new Error(\n `${configPath} must export a default config (result of defineConfig())`,\n );\n }\n return defineConfig(config as Parameters<typeof defineConfig>[0]);\n}\n","import pc from 'picocolors';\n\nimport type {\n CloudConnectorRecord,\n CloudDashboardRecord,\n ConfigDiff,\n Diff,\n} from './api-client';\n\nexport function printDiff(diff: ConfigDiff): void {\n printDiffSection('Connectors', diff.connectors, (c) => c.name);\n printDiffSection('Dashboards', diff.dashboards, (d) => d.slug);\n}\n\nfunction printDiffSection<\n T extends CloudConnectorRecord | CloudDashboardRecord,\n>(label: string, diff: Diff<T>, getName: (t: T) => string): void {\n if (\n diff.added.length === 0 &&\n diff.modified.length === 0 &&\n diff.removed.length === 0\n ) {\n console.log(pc.dim(` ${label}: no changes`));\n return;\n }\n console.log(pc.bold(` ${label}:`));\n for (const item of diff.added) {\n console.log(pc.green(` + ${getName(item)}`));\n }\n for (const item of diff.modified) {\n console.log(pc.yellow(` ~ ${getName(item)}`));\n }\n for (const item of diff.removed) {\n console.log(pc.red(` - ${getName(item)}`));\n }\n}\n\nexport function printError(message: string): void {\n console.error(pc.red(`✗ ${message}`));\n}\n\nexport function printSuccess(message: string): void {\n console.log(pc.green(`✓ ${message}`));\n}\n","import { spinner } from '@clack/prompts';\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\n\nimport {\n ApiError,\n listSecrets,\n removeSecret,\n setSecret,\n} from '../lib/api-client';\nimport { requireApiKey } from '../lib/env';\nimport { printError, printSuccess } from '../lib/output';\n\nexport const secretsCommand = new Command('secrets').description(\n 'Manage secrets',\n);\n\ninterface SetOptions {\n json?: string;\n fromFile?: string;\n}\n\nsecretsCommand\n .command('set <name> [value]')\n .description(\n 'Set a secret. Pass value as argument, via stdin, or as structured JSON via --json / --from-file.',\n )\n .option(\n '--json <json>',\n 'Set the secret to a JSON-encoded value (object, array, etc.). Validated before sending.',\n )\n .option(\n '--from-file <path>',\n 'Read the secret value as JSON from a file. Validated before sending.',\n )\n .action(async (name: string, value: string | undefined, opts: SetOptions) => {\n requireApiKey();\n\n const usingJson = opts.json !== undefined;\n const usingFile = opts.fromFile !== undefined;\n\n if (usingJson && usingFile) {\n printError('Cannot use --json and --from-file together.');\n process.exit(1);\n }\n if ((usingJson || usingFile) && value !== undefined) {\n printError(\n 'Cannot combine a positional value with --json or --from-file.',\n );\n process.exit(1);\n }\n\n let secretValue: string;\n if (usingJson) {\n const raw = opts.json!;\n try {\n JSON.parse(raw);\n } catch (err) {\n printError(\n `Invalid JSON passed to --json: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n secretValue = raw;\n } else if (usingFile) {\n let raw: string;\n try {\n raw = await readFile(opts.fromFile!, 'utf8');\n } catch (err) {\n printError(\n `Failed to read file \"${opts.fromFile}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n try {\n JSON.parse(raw);\n } catch (err) {\n printError(\n `File \"${opts.fromFile}\" does not contain valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n secretValue = raw;\n } else if (value !== undefined) {\n secretValue = value;\n } else {\n const stdin = await readStdin();\n if (!stdin) {\n printError('No value provided. Pass as argument or via stdin.');\n process.exit(1);\n }\n secretValue = stdin;\n }\n\n const s = spinner();\n s.start(`Setting secret ${name}...`);\n try {\n await setSecret(name, secretValue);\n s.stop('');\n printSuccess(`Secret ${name} set`);\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nsecretsCommand\n .command('list')\n .description('List all secrets (names and last-rotated timestamps)')\n .action(async () => {\n requireApiKey();\n\n const s = spinner();\n s.start('Fetching secrets...');\n try {\n const secrets = await listSecrets();\n s.stop('');\n if (secrets.length === 0) {\n console.log('No secrets configured.');\n return;\n }\n for (const { name, lastRotatedAt } of secrets) {\n const ts = lastRotatedAt\n ? new Date(lastRotatedAt).toLocaleString()\n : 'never';\n console.log(` ${name} (last rotated: ${ts})`);\n }\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nsecretsCommand\n .command('remove <name>')\n .description('Remove a secret')\n .action(async (name: string) => {\n requireApiKey();\n\n const s = spinner();\n s.start(`Removing secret ${name}...`);\n try {\n await removeSecret(name);\n s.stop('');\n printSuccess(`Secret ${name} removed`);\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n process.stdin.on('data', (chunk: Buffer) => chunks.push(chunk));\n process.stdin.on('end', () =>\n resolve(Buffer.concat(chunks).toString('utf8')),\n );\n process.stdin.on('error', reject);\n });\n}\n\nfunction authExitCode(err: unknown): number {\n if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {\n return 3;\n }\n return 1;\n}\n","import { Command } from 'commander';\n\nimport { findConfigFile, loadConfig } from '../lib/config-loader';\nimport { printError, printSuccess } from '../lib/output';\n\nexport const validateCommand = new Command('validate')\n .description('Validate rawdash.config.ts locally without network access')\n .option('--config <path>', 'path to rawdash.config.ts')\n .action(async (opts: { config?: string }) => {\n const configPath = await findConfigFile(opts.config).catch(\n (err: unknown) => {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n },\n );\n\n try {\n const config = await loadConfig(configPath);\n console.log(JSON.stringify(config, null, 2));\n printSuccess('Config is valid');\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n }\n });\n"],"mappings":"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","names":["Command","dirname","join","spinner","Command","Command","spinner","resolve","Command","Command","join","dirname","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts","../src/commands/deploy.ts","../src/lib/api-client.ts","../src/lib/env.ts","../src/lib/config-loader.ts","../src/lib/output.ts","../src/commands/secrets.ts","../src/commands/validate.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { deployCommand } from './commands/deploy';\nimport { secretsCommand } from './commands/secrets';\nimport { validateCommand } from './commands/validate';\n\nconst pkg = JSON.parse(\n readFileSync(\n join(dirname(fileURLToPath(import.meta.url)), '../package.json'),\n 'utf8',\n ),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('rawdash')\n .description('Rawdash CLI — deploy and manage your dashboard config')\n .version(pkg.version);\n\nprogram.addCommand(deployCommand);\nprogram.addCommand(secretsCommand);\nprogram.addCommand(validateCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n","import { confirm, isCancel, spinner } from '@clack/prompts';\nimport { Command } from 'commander';\n\nimport { postConfig } from '../lib/api-client';\nimport { findConfigFile, loadConfig } from '../lib/config-loader';\nimport { requireApiKey } from '../lib/env';\nimport { printDiff, printError, printSuccess } from '../lib/output';\n\nexport const deployCommand = new Command('deploy')\n .description('Deploy rawdash.config.ts to the server')\n .option('--config <path>', 'path to rawdash.config.ts')\n .option('--dry-run', 'validate and diff without persisting')\n .option('--yes', 'skip confirmation prompt (useful in CI)')\n .action(\n async (opts: { config?: string; dryRun?: boolean; yes?: boolean }) => {\n requireApiKey();\n\n const configPath = await findConfigFile(opts.config).catch(\n (err: unknown) => {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n },\n );\n\n const s = spinner();\n s.start('Loading config...');\n\n const config = await loadConfig(configPath).catch((err: unknown) => {\n s.stop('Failed to load config');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n });\n s.stop('Config loaded');\n\n s.start('Fetching diff...');\n const previewResult = await postConfig(config, true);\n s.stop('');\n\n if (!previewResult.ok) {\n printError(previewResult.error);\n process.exit(exitCodeForStatus(previewResult.status));\n }\n\n printDiff(previewResult.diff);\n\n if (opts.dryRun) {\n printSuccess('Dry run complete — no changes applied');\n return;\n }\n\n if (!opts.yes) {\n const confirmed = await confirm({ message: 'Apply this diff?' });\n if (isCancel(confirmed) || !confirmed) {\n console.log('Aborted.');\n process.exit(0);\n }\n }\n\n s.start('Deploying...');\n const deployResult = await postConfig(config, false);\n s.stop('');\n\n if (!deployResult.ok) {\n printError(deployResult.error);\n process.exit(exitCodeForStatus(deployResult.status));\n }\n\n printSuccess('Deployed');\n },\n );\n\nfunction exitCodeForStatus(status: number): number {\n if (status === 401 || status === 403) {\n return 3;\n }\n if (status === 409) {\n return 4;\n }\n if (status === 422) {\n return 2;\n }\n return 1;\n}\n","import { type DashboardConfig, toWireConfig } from '@rawdash/core';\n\nimport { getEnv } from './env';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nexport interface Diff<T> {\n added: T[];\n removed: T[];\n modified: T[];\n}\n\nexport interface CloudConnectorRecord {\n name: string;\n connectorId: string;\n displayName?: string | null;\n config: Record<string, unknown>;\n syncIntervalSeconds?: number;\n enabled?: boolean;\n}\n\nexport interface CloudDashboardRecord {\n id: string;\n name: string;\n slug: string;\n config: Record<string, unknown>;\n}\n\nexport interface ConfigDiff {\n connectors: Diff<CloudConnectorRecord>;\n dashboards: Diff<CloudDashboardRecord>;\n}\n\nexport interface DeploySuccess {\n ok: true;\n diff: ConfigDiff;\n}\n\nexport interface DeployFailure {\n ok: false;\n error: string;\n status: number;\n conflicts?: string[];\n}\n\nexport type DeployResult = DeploySuccess | DeployFailure;\n\nexport interface CloudSecret {\n name: string;\n lastRotatedAt: string | null;\n}\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\ninterface ErrorBody {\n error?: string;\n message?: string;\n code?: string;\n required?: string;\n conflicts?: string[];\n}\n\nexport async function postConfig(\n config: DashboardConfig,\n dryRun: boolean,\n): Promise<DeployResult> {\n const { url, apiKey } = getEnv();\n const endpoint = `${url}/config${dryRun ? '?dryRun=true' : ''}`;\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey ?? ''}`,\n },\n body: JSON.stringify(toWireConfig(config)),\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n const isTimeout =\n err instanceof Error &&\n (err.name === 'AbortError' || err.name === 'TimeoutError');\n return {\n ok: false,\n error: isTimeout\n ? 'Request timed out'\n : `Network error: ${err instanceof Error ? err.message : String(err)}`,\n status: 0,\n };\n }\n\n if (res.ok) {\n const diff = (await res.json()) as ConfigDiff;\n return { ok: true, diff };\n }\n\n return buildDeployFailure(res, url, endpoint);\n}\n\nasync function buildDeployFailure(\n res: Response,\n baseUrl: string,\n endpoint: string,\n): Promise<DeployFailure> {\n const { body, text } = await readErrorBody(res);\n const rawMessage = body.error ?? body.message ?? (text || res.statusText);\n\n let error: string;\n if (res.status === 401) {\n error = `API key invalid or revoked. Check RAWDASH_API_KEY. (${rawMessage})`;\n } else if (res.status === 403) {\n error = buildForbiddenMessage(body, rawMessage, baseUrl, endpoint);\n } else if (res.status === 409) {\n error = `Org is in ui source-of-truth mode. Switch to git mode in cloud settings, or push UI changes back into your config first.`;\n } else if (res.status === 422) {\n error = `Validation failed: ${rawMessage}`;\n } else {\n error = `Request failed (${res.status}): ${rawMessage}${requestContext(res.status, baseUrl, endpoint)}`;\n }\n\n return { ok: false, error, status: res.status, conflicts: body.conflicts };\n}\n\nfunction buildForbiddenMessage(\n body: ErrorBody,\n rawMessage: string,\n baseUrl: string,\n endpoint: string,\n): string {\n if (body.code === 'insufficient_scope') {\n const scope = body.required ?? 'config:write';\n return `Key lacks the \"${scope}\" scope. Get a new key with broader scope. (${rawMessage})`;\n }\n const code = body.code ? ` [${body.code}]` : '';\n return `Forbidden (403): ${rawMessage}${code}${requestContext(403, baseUrl, endpoint)}`;\n}\n\nfunction requestContext(\n status: number,\n baseUrl: string,\n endpoint: string,\n): string {\n let context = `\\n Request URL: ${endpoint}`;\n if ((status === 403 || status === 404) && isSluglessUrl(baseUrl)) {\n context +=\n `\\n RAWDASH_URL has no org slug. The hosted service expects ` +\n `https://api.rawdash.dev/<org-slug>; a slug-less URL is rejected with 403.`;\n }\n return context;\n}\n\nfunction isSluglessUrl(baseUrl: string): boolean {\n try {\n const { pathname } = new URL(baseUrl);\n return pathname === '' || pathname === '/';\n } catch {\n return false;\n }\n}\n\nexport async function setSecret(name: string, value: string): Promise<void> {\n const { url, apiKey } = getEnv();\n const endpoint = `${url}/secrets`;\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey ?? ''}`,\n },\n body: JSON.stringify({ name, value }),\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res, url, endpoint);\n }\n}\n\nexport async function listSecrets(): Promise<CloudSecret[]> {\n const { url, apiKey } = getEnv();\n const endpoint = `${url}/secrets`;\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n headers: { Authorization: `Bearer ${apiKey ?? ''}` },\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res, url, endpoint);\n }\n const body = (await res.json()) as { secrets: CloudSecret[] };\n return body.secrets;\n}\n\nexport async function removeSecret(name: string): Promise<void> {\n const { url, apiKey } = getEnv();\n const endpoint = `${url}/secrets/${encodeURIComponent(name)}`;\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: 'DELETE',\n headers: { Authorization: `Bearer ${apiKey ?? ''}` },\n signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),\n });\n } catch (err) {\n throw new ApiError(wrapFetchError(err), 0);\n }\n\n if (!res.ok) {\n await throwApiError(res, url, endpoint);\n }\n}\n\nfunction wrapFetchError(err: unknown): string {\n if (\n err instanceof Error &&\n (err.name === 'AbortError' || err.name === 'TimeoutError')\n ) {\n return 'Request timed out';\n }\n return `Network error: ${err instanceof Error ? err.message : String(err)}`;\n}\n\nasync function throwApiError(\n res: Response,\n baseUrl: string,\n endpoint: string,\n): Promise<never> {\n const { body, text } = await readErrorBody(res);\n const message = body.error ?? body.message ?? (text || res.statusText);\n const code = body.code ? ` [${body.code}]` : '';\n throw new ApiError(\n `API error (${res.status}): ${message}${code}${requestContext(res.status, baseUrl, endpoint)}`,\n res.status,\n );\n}\n\nasync function readErrorBody(res: Response): Promise<{\n body: ErrorBody;\n text: string;\n}> {\n const text = await res.text();\n const contentType = res.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n return {\n body: JSON.parse(text) as ErrorBody,\n text,\n };\n } catch {\n // body claimed JSON but wasn't — fall through to text\n }\n }\n return { body: {}, text };\n}\n","export function getEnv(): { url: string; apiKey: string | undefined } {\n return {\n url: process.env['RAWDASH_URL'] ?? 'https://api.rawdash.dev',\n apiKey: process.env['RAWDASH_API_KEY'],\n };\n}\n\nexport function requireApiKey(): string {\n const { apiKey } = getEnv();\n if (!apiKey) {\n console.error('RAWDASH_API_KEY is not set. Set it in your environment.');\n process.exit(3);\n }\n return apiKey;\n}\n","import { type DashboardConfig, defineConfig } from '@rawdash/core';\nimport { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { tsImport } from 'tsx/esm/api';\n\nexport async function findConfigFile(explicitPath?: string): Promise<string> {\n if (explicitPath) {\n const abs = resolve(explicitPath);\n if (!existsSync(abs)) {\n throw new Error(`Config file not found: ${abs}`);\n }\n return abs;\n }\n\n let dir = process.cwd();\n for (;;) {\n const candidate = join(dir, 'rawdash.config.ts');\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n break;\n }\n dir = parent;\n }\n\n throw new Error(\n 'Could not find rawdash.config.ts. Pass --config <path> to specify it explicitly.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<DashboardConfig> {\n const mod = await tsImport(configPath, import.meta.url);\n const config: unknown =\n (mod as { default?: unknown; config?: unknown }).default ??\n (mod as { config?: unknown }).config;\n if (!config || typeof config !== 'object') {\n throw new Error(\n `${configPath} must export a default config (result of defineConfig())`,\n );\n }\n return defineConfig(config as Parameters<typeof defineConfig>[0]);\n}\n","import pc from 'picocolors';\n\nimport type {\n CloudConnectorRecord,\n CloudDashboardRecord,\n ConfigDiff,\n Diff,\n} from './api-client';\n\nexport function printDiff(diff: ConfigDiff): void {\n printDiffSection('Connectors', diff.connectors, (c) => c.name);\n printDiffSection('Dashboards', diff.dashboards, (d) => d.slug);\n}\n\nfunction printDiffSection<\n T extends CloudConnectorRecord | CloudDashboardRecord,\n>(label: string, diff: Diff<T>, getName: (t: T) => string): void {\n if (\n diff.added.length === 0 &&\n diff.modified.length === 0 &&\n diff.removed.length === 0\n ) {\n console.log(pc.dim(` ${label}: no changes`));\n return;\n }\n console.log(pc.bold(` ${label}:`));\n for (const item of diff.added) {\n console.log(pc.green(` + ${getName(item)}`));\n }\n for (const item of diff.modified) {\n console.log(pc.yellow(` ~ ${getName(item)}`));\n }\n for (const item of diff.removed) {\n console.log(pc.red(` - ${getName(item)}`));\n }\n}\n\nexport function printError(message: string): void {\n console.error(pc.red(`✗ ${message}`));\n}\n\nexport function printSuccess(message: string): void {\n console.log(pc.green(`✓ ${message}`));\n}\n","import { spinner } from '@clack/prompts';\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\n\nimport {\n ApiError,\n listSecrets,\n removeSecret,\n setSecret,\n} from '../lib/api-client';\nimport { requireApiKey } from '../lib/env';\nimport { printError, printSuccess } from '../lib/output';\n\nexport const secretsCommand = new Command('secrets').description(\n 'Manage secrets',\n);\n\ninterface SetOptions {\n json?: string;\n fromFile?: string;\n}\n\nsecretsCommand\n .command('set <name> [value]')\n .description(\n 'Set a secret. Pass value as argument, via stdin, or as structured JSON via --json / --from-file.',\n )\n .option(\n '--json <json>',\n 'Set the secret to a JSON-encoded value (object, array, etc.). Validated before sending.',\n )\n .option(\n '--from-file <path>',\n 'Read the secret value as JSON from a file. Validated before sending.',\n )\n .action(async (name: string, value: string | undefined, opts: SetOptions) => {\n requireApiKey();\n\n const usingJson = opts.json !== undefined;\n const usingFile = opts.fromFile !== undefined;\n\n if (usingJson && usingFile) {\n printError('Cannot use --json and --from-file together.');\n process.exit(1);\n }\n if ((usingJson || usingFile) && value !== undefined) {\n printError(\n 'Cannot combine a positional value with --json or --from-file.',\n );\n process.exit(1);\n }\n\n let secretValue: string;\n if (usingJson) {\n const raw = opts.json!;\n try {\n JSON.parse(raw);\n } catch (err) {\n printError(\n `Invalid JSON passed to --json: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n secretValue = raw;\n } else if (usingFile) {\n let raw: string;\n try {\n raw = await readFile(opts.fromFile!, 'utf8');\n } catch (err) {\n printError(\n `Failed to read file \"${opts.fromFile}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n try {\n JSON.parse(raw);\n } catch (err) {\n printError(\n `File \"${opts.fromFile}\" does not contain valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n secretValue = raw;\n } else if (value !== undefined) {\n secretValue = value;\n } else {\n const stdin = await readStdin();\n if (!stdin) {\n printError('No value provided. Pass as argument or via stdin.');\n process.exit(1);\n }\n secretValue = stdin;\n }\n\n const s = spinner();\n s.start(`Setting secret ${name}...`);\n try {\n await setSecret(name, secretValue);\n s.stop('');\n printSuccess(`Secret ${name} set`);\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nsecretsCommand\n .command('list')\n .description('List all secrets (names and last-rotated timestamps)')\n .action(async () => {\n requireApiKey();\n\n const s = spinner();\n s.start('Fetching secrets...');\n try {\n const secrets = await listSecrets();\n s.stop('');\n if (secrets.length === 0) {\n console.log('No secrets configured.');\n return;\n }\n for (const { name, lastRotatedAt } of secrets) {\n const ts = lastRotatedAt\n ? new Date(lastRotatedAt).toLocaleString()\n : 'never';\n console.log(` ${name} (last rotated: ${ts})`);\n }\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nsecretsCommand\n .command('remove <name>')\n .description('Remove a secret')\n .action(async (name: string) => {\n requireApiKey();\n\n const s = spinner();\n s.start(`Removing secret ${name}...`);\n try {\n await removeSecret(name);\n s.stop('');\n printSuccess(`Secret ${name} removed`);\n } catch (err) {\n s.stop('');\n printError(err instanceof Error ? err.message : String(err));\n process.exit(authExitCode(err));\n }\n });\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n process.stdin.on('data', (chunk: Buffer) => chunks.push(chunk));\n process.stdin.on('end', () =>\n resolve(Buffer.concat(chunks).toString('utf8')),\n );\n process.stdin.on('error', reject);\n });\n}\n\nfunction authExitCode(err: unknown): number {\n if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {\n return 3;\n }\n return 1;\n}\n","import { Command } from 'commander';\n\nimport { findConfigFile, loadConfig } from '../lib/config-loader';\nimport { printError, printSuccess } from '../lib/output';\n\nexport const validateCommand = new Command('validate')\n .description('Validate rawdash.config.ts locally without network access')\n .option('--config <path>', 'path to rawdash.config.ts')\n .action(async (opts: { config?: string }) => {\n const configPath = await findConfigFile(opts.config).catch(\n (err: unknown) => {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n },\n );\n\n try {\n const config = await loadConfig(configPath);\n console.log(JSON.stringify(config, null, 2));\n printSuccess('Config is valid');\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n process.exit(2);\n }\n });\n"],"mappings":"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","names":["Command","dirname","join","spinner","Command","Command","spinner","resolve","Command","Command","join","dirname","Command"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawdash/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Rawdash CLI — deploy and manage your dashboard config",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"commander": "^13.0.0",
|
|
29
29
|
"picocolors": "^1.1.0",
|
|
30
30
|
"tsx": "^4.19.4",
|
|
31
|
-
"@rawdash/core": "0.
|
|
31
|
+
"@rawdash/core": "0.18.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^22.0.0",
|