@framedash/cli 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/commands/alerts.d.ts +2 -0
  4. package/dist/commands/alerts.d.ts.map +1 -0
  5. package/dist/commands/alerts.js +171 -0
  6. package/dist/commands/alerts.js.map +1 -0
  7. package/dist/commands/auth.d.ts +2 -0
  8. package/dist/commands/auth.d.ts.map +1 -0
  9. package/dist/commands/auth.js +20 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/content.d.ts +2 -0
  12. package/dist/commands/content.d.ts.map +1 -0
  13. package/dist/commands/content.js +104 -0
  14. package/dist/commands/content.js.map +1 -0
  15. package/dist/commands/dashboard.d.ts +2 -0
  16. package/dist/commands/dashboard.d.ts.map +1 -0
  17. package/dist/commands/dashboard.js +22 -0
  18. package/dist/commands/dashboard.js.map +1 -0
  19. package/dist/commands/funnel.d.ts +2 -0
  20. package/dist/commands/funnel.d.ts.map +1 -0
  21. package/dist/commands/funnel.js +43 -0
  22. package/dist/commands/funnel.js.map +1 -0
  23. package/dist/commands/map-capture.d.ts +17 -0
  24. package/dist/commands/map-capture.d.ts.map +1 -0
  25. package/dist/commands/map-capture.js +200 -0
  26. package/dist/commands/map-capture.js.map +1 -0
  27. package/dist/commands/maps.d.ts +2 -0
  28. package/dist/commands/maps.d.ts.map +1 -0
  29. package/dist/commands/maps.js +38 -0
  30. package/dist/commands/maps.js.map +1 -0
  31. package/dist/commands/query.d.ts +2 -0
  32. package/dist/commands/query.d.ts.map +1 -0
  33. package/dist/commands/query.js +70 -0
  34. package/dist/commands/query.js.map +1 -0
  35. package/dist/commands/retention.d.ts +2 -0
  36. package/dist/commands/retention.d.ts.map +1 -0
  37. package/dist/commands/retention.js +22 -0
  38. package/dist/commands/retention.js.map +1 -0
  39. package/dist/commands/status.d.ts +2 -0
  40. package/dist/commands/status.d.ts.map +1 -0
  41. package/dist/commands/status.js +20 -0
  42. package/dist/commands/status.js.map +1 -0
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +73 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/lib/config.d.ts +47 -0
  48. package/dist/lib/config.d.ts.map +1 -0
  49. package/dist/lib/config.js +114 -0
  50. package/dist/lib/config.js.map +1 -0
  51. package/dist/lib/create-client.d.ts +3 -0
  52. package/dist/lib/create-client.d.ts.map +1 -0
  53. package/dist/lib/create-client.js +30 -0
  54. package/dist/lib/create-client.js.map +1 -0
  55. package/dist/lib/formatters.d.ts +4 -0
  56. package/dist/lib/formatters.d.ts.map +1 -0
  57. package/dist/lib/formatters.js +71 -0
  58. package/dist/lib/formatters.js.map +1 -0
  59. package/dist/lib/logger.d.ts +9 -0
  60. package/dist/lib/logger.d.ts.map +1 -0
  61. package/dist/lib/logger.js +15 -0
  62. package/dist/lib/logger.js.map +1 -0
  63. package/dist/lib/metadata.d.ts +36 -0
  64. package/dist/lib/metadata.d.ts.map +1 -0
  65. package/dist/lib/metadata.js +40 -0
  66. package/dist/lib/metadata.js.map +1 -0
  67. package/dist/lib/run-command.d.ts +28 -0
  68. package/dist/lib/run-command.d.ts.map +1 -0
  69. package/dist/lib/run-command.js +53 -0
  70. package/dist/lib/run-command.js.map +1 -0
  71. package/dist/lib/uploader.d.ts +19 -0
  72. package/dist/lib/uploader.d.ts.map +1 -0
  73. package/dist/lib/uploader.js +61 -0
  74. package/dist/lib/uploader.js.map +1 -0
  75. package/package.json +43 -0
@@ -0,0 +1,200 @@
1
+ import { readdir, readFile, realpath, stat } from "node:fs/promises";
2
+ import { extname, isAbsolute, join, relative, resolve } from "node:path";
3
+ import { parseArgs } from "node:util";
4
+ import { resolveApiKey } from "../lib/config.js";
5
+ import { error, log, success } from "../lib/logger.js";
6
+ import { mapCaptureMetadataSchema } from "../lib/metadata.js";
7
+ import { uploadMapCapture } from "../lib/uploader.js";
8
+ const ALLOWED_IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".webp"]);
9
+ const MAP_CAPTURE_HELP = `Usage: framedash map-capture [options]
10
+
11
+ Upload captured map images and metadata to Framedash SaaS.
12
+
13
+ Reads JSON sidecar metadata files from --input-dir, validates them,
14
+ and optionally uploads the associated images to the Framedash API.
15
+
16
+ Required:
17
+ --input-dir <path> Directory containing JSON metadata files and images
18
+
19
+ Upload options (all required together):
20
+ --upload Enable upload to Framedash API
21
+ --api-key <key> Admin API key. Prefer FRAMEDASH_API_KEY env or
22
+ --api-key-file: a key passed as --api-key is visible
23
+ in the process list and shell history.
24
+ --api-key-file <path> Read the admin API key from a file ('-' for stdin)
25
+ --project-id <uuid> Target project ID, or set FRAMEDASH_PROJECT_ID env
26
+
27
+ Optional:
28
+ --base-url <url> API base URL (default: https://app.framedash.dev)
29
+ --dry-run Validate files without uploading
30
+
31
+ Examples:
32
+ # Validate metadata files only
33
+ framedash map-capture --input-dir ./captures --dry-run
34
+
35
+ # Upload to Framedash (key from env, not the command line)
36
+ FRAMEDASH_API_KEY=... FRAMEDASH_PROJECT_ID=... \\
37
+ framedash map-capture --input-dir ./captures --upload`;
38
+ /** CLI entry point for map-capture — parses args then delegates to mapCapture(). */
39
+ export async function mapCaptureCommand(args) {
40
+ const { values } = parseArgs({
41
+ args,
42
+ options: {
43
+ "input-dir": { type: "string" },
44
+ "api-key": { type: "string" },
45
+ "api-key-file": { type: "string" },
46
+ "project-id": { type: "string" },
47
+ "base-url": { type: "string", default: "https://app.framedash.dev" },
48
+ upload: { type: "boolean", default: false },
49
+ "dry-run": { type: "boolean", default: false },
50
+ help: { type: "boolean", short: "h", default: false },
51
+ },
52
+ allowPositionals: false,
53
+ });
54
+ if (values.help) {
55
+ log(MAP_CAPTURE_HELP);
56
+ return;
57
+ }
58
+ // Resolve the API key only when an upload will actually run, so a validation
59
+ // dry run with --api-key-file - does not block on stdin (or fail on a missing
60
+ // file) for a key it never uses.
61
+ const willUpload = Boolean(values.upload) && !values["dry-run"];
62
+ const result = await mapCapture({
63
+ inputDir: values["input-dir"],
64
+ upload: values.upload,
65
+ dryRun: values["dry-run"],
66
+ apiKey: willUpload ? resolveApiKey(values) : undefined,
67
+ projectId: values["project-id"] ?? process.env.FRAMEDASH_PROJECT_ID,
68
+ baseUrl: values["base-url"] ?? "https://app.framedash.dev",
69
+ });
70
+ if (!result.ok) {
71
+ process.exit(1);
72
+ }
73
+ }
74
+ export async function mapCapture(opts) {
75
+ const fail = { ok: false, successCount: 0, errorCount: 0 };
76
+ if (!opts.inputDir) {
77
+ error("--input-dir is required");
78
+ return fail;
79
+ }
80
+ const upload = Boolean(opts.upload);
81
+ const dryRun = Boolean(opts.dryRun);
82
+ if (upload && !dryRun) {
83
+ if (!opts.apiKey) {
84
+ error("--api-key (or FRAMEDASH_API_KEY env) is required with --upload");
85
+ return fail;
86
+ }
87
+ if (!opts.projectId) {
88
+ error("--project-id (or FRAMEDASH_PROJECT_ID env) is required with --upload");
89
+ return fail;
90
+ }
91
+ }
92
+ const resolvedDir = resolve(opts.inputDir);
93
+ let dirStat;
94
+ try {
95
+ dirStat = await stat(resolvedDir);
96
+ }
97
+ catch {
98
+ error(`Input directory not found: ${resolvedDir}`);
99
+ return fail;
100
+ }
101
+ if (!dirStat.isDirectory()) {
102
+ error(`Not a directory: ${resolvedDir}`);
103
+ return fail;
104
+ }
105
+ const files = await readdir(resolvedDir);
106
+ const jsonFiles = files.filter((f) => f.endsWith(".json"));
107
+ if (jsonFiles.length === 0) {
108
+ error(`No JSON metadata files found in ${resolvedDir}`);
109
+ return fail;
110
+ }
111
+ log(`Found ${jsonFiles.length} metadata file(s) in ${resolvedDir}`);
112
+ const realInputDir = await realpath(resolvedDir);
113
+ let successCount = 0;
114
+ let errorCount = 0;
115
+ for (const jsonFile of jsonFiles) {
116
+ const jsonPath = join(resolvedDir, jsonFile);
117
+ try {
118
+ const raw = await readFile(jsonPath, "utf-8");
119
+ let parsed;
120
+ try {
121
+ parsed = JSON.parse(raw);
122
+ }
123
+ catch {
124
+ error(`${jsonFile}: Invalid JSON`);
125
+ errorCount++;
126
+ continue;
127
+ }
128
+ const result = mapCaptureMetadataSchema.safeParse(parsed);
129
+ if (!result.success) {
130
+ const issues = result.error.issues.map((i) => i.message).join("; ");
131
+ error(`${jsonFile}: Invalid metadata \u2014 ${issues}`);
132
+ errorCount++;
133
+ continue;
134
+ }
135
+ const metadata = result.data;
136
+ // Verify image file exists and is within input directory
137
+ if (isAbsolute(metadata.image_path)) {
138
+ error(`${jsonFile}: Absolute image paths are not allowed: ${metadata.image_path}`);
139
+ errorCount++;
140
+ continue;
141
+ }
142
+ const imagePath = await realpath(resolve(resolvedDir, metadata.image_path)).catch(() => null);
143
+ if (!imagePath) {
144
+ error(`${jsonFile}: Image not found: ${metadata.image_path}`);
145
+ errorCount++;
146
+ continue;
147
+ }
148
+ const rel = relative(realInputDir, imagePath);
149
+ if (rel.startsWith("..") || isAbsolute(rel)) {
150
+ error(`${jsonFile}: Image path escapes input directory: ${metadata.image_path}`);
151
+ errorCount++;
152
+ continue;
153
+ }
154
+ const imgStat = await stat(imagePath);
155
+ if (!imgStat.isFile()) {
156
+ error(`${jsonFile}: Image path is not a file: ${metadata.image_path}`);
157
+ errorCount++;
158
+ continue;
159
+ }
160
+ const imgExt = extname(imagePath).toLowerCase();
161
+ if (!ALLOWED_IMAGE_EXTS.has(imgExt)) {
162
+ error(`${jsonFile}: Unsupported image format: ${imgExt}`);
163
+ errorCount++;
164
+ continue;
165
+ }
166
+ if (dryRun) {
167
+ success(`${jsonFile}: map_id=${metadata.map_id}, ` +
168
+ `image=${metadata.image_path}, ` +
169
+ `bounds=[${metadata.world_bounds.min.x},${metadata.world_bounds.min.y}]` +
170
+ `→[${metadata.world_bounds.max.x},${metadata.world_bounds.max.y}], ` +
171
+ `size=${metadata.image_dimensions.width}x${metadata.image_dimensions.height}`);
172
+ successCount++;
173
+ continue;
174
+ }
175
+ if (upload) {
176
+ const uploadResult = await uploadMapCapture({
177
+ metadata,
178
+ imagePath,
179
+ apiKey: opts.apiKey,
180
+ projectId: opts.projectId,
181
+ baseUrl: opts.baseUrl ?? "https://app.framedash.dev",
182
+ });
183
+ success(`${metadata.map_id}: ${uploadResult.action} ` +
184
+ `(${metadata.image_dimensions.width}x${metadata.image_dimensions.height})`);
185
+ }
186
+ else {
187
+ success(`${jsonFile}: Valid (map_id=${metadata.map_id})`);
188
+ }
189
+ successCount++;
190
+ }
191
+ catch (err) {
192
+ error(`${jsonFile}: ${err instanceof Error ? err.message : String(err)}`);
193
+ errorCount++;
194
+ }
195
+ }
196
+ log("");
197
+ log(`Done: ${successCount} succeeded, ${errorCount} failed`);
198
+ return { ok: errorCount === 0, successCount, errorCount };
199
+ }
200
+ //# sourceMappingURL=map-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-capture.js","sourceRoot":"","sources":["../../src/commands/map-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const maps: (args: string[]) => Promise<void>;
2
+ //# sourceMappingURL=maps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../../src/commands/maps.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,IAAI,mCAGf,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { formatOutput } from "../lib/formatters.js";
2
+ import { error, log, success } from "../lib/logger.js";
3
+ import { runCommand, withSubcommands } from "../lib/run-command.js";
4
+ const HELP = `Usage: framedash maps <subcommand> [options]
5
+
6
+ Manage maps.
7
+
8
+ Subcommands:
9
+ list List maps
10
+ delete <map-id> Delete a map
11
+
12
+ Run 'framedash maps <subcommand> --help' for more info.`;
13
+ export const maps = withSubcommands("maps", HELP, {
14
+ list: mapsList,
15
+ delete: mapsDelete,
16
+ });
17
+ async function mapsList(args) {
18
+ await runCommand({ args, help: "Usage: framedash maps list [--format json|table|csv] [global options]" }, async ({ client, config }) => {
19
+ const data = await client.get(client.projectPath("maps"));
20
+ log(formatOutput(data, config.format));
21
+ });
22
+ }
23
+ async function mapsDelete(args) {
24
+ await runCommand({
25
+ args,
26
+ help: "Usage: framedash maps delete <map-id> [global options]",
27
+ allowPositionals: true,
28
+ }, async ({ client, positionals }) => {
29
+ const mapId = positionals[0];
30
+ if (!mapId) {
31
+ error("Map ID is required: framedash maps delete <map-id>");
32
+ process.exit(1);
33
+ }
34
+ await client.delete(client.projectPath(`maps/${encodeURIComponent(mapId)}`));
35
+ success(`Map ${mapId} deleted`);
36
+ });
37
+ }
38
+ //# sourceMappingURL=maps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maps.js","sourceRoot":"","sources":["../../src/commands/maps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEpE,MAAM,IAAI,GAAG;;;;;;;;wDAQ2C,CAAC;AAEzD,MAAM,CAAC,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE;IACjD,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE,UAAU;CAClB,CAAC,CAAC;AAEH,KAAK,UAAU,QAAQ,CAAC,IAAc;IACrC,MAAM,UAAU,CACf,EAAE,IAAI,EAAE,IAAI,EAAE,uEAAuE,EAAE,EACvF,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC,CACD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,UAAU,CACf;QACC,IAAI;QACJ,IAAI,EAAE,wDAAwD;QAC9D,gBAAgB,EAAE,IAAI;KACtB,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,CAAC,oDAAoD,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7E,OAAO,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC;IACjC,CAAC,CACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function query(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAMA,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CzD"}
@@ -0,0 +1,70 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { parsePositiveInt } from "../lib/config.js";
3
+ import { formatOutput } from "../lib/formatters.js";
4
+ import { error, log } from "../lib/logger.js";
5
+ import { runCommand } from "../lib/run-command.js";
6
+ export async function query(args) {
7
+ await runCommand({
8
+ args,
9
+ help: HELP,
10
+ options: {
11
+ limit: { type: "string" },
12
+ file: { type: "string", short: "f" },
13
+ },
14
+ allowPositionals: true,
15
+ }, async ({ client, config, values, positionals }) => {
16
+ if (values.file && positionals.length > 0) {
17
+ error("Cannot use both --file and a positional SQL argument. Provide one or the other.");
18
+ process.exit(1);
19
+ }
20
+ let sql;
21
+ if (values.file) {
22
+ try {
23
+ sql = await readFile(values.file, "utf-8");
24
+ }
25
+ catch (err) {
26
+ const msg = err instanceof Error ? err.message : "unknown error";
27
+ error(`Failed to read SQL file: ${values.file} (${msg})`);
28
+ process.exit(1);
29
+ }
30
+ }
31
+ else if (positionals.length > 0) {
32
+ sql = positionals.join(" ");
33
+ }
34
+ else {
35
+ error("SQL query is required. Provide as argument or use --file.");
36
+ process.exit(1);
37
+ }
38
+ const body = {
39
+ sql,
40
+ project_id: config.projectId,
41
+ };
42
+ if (values.limit) {
43
+ body.limit = parsePositiveInt(values.limit, "limit");
44
+ }
45
+ const data = await client.post("/api/v1/query", body);
46
+ log(formatOutput(data, config.format));
47
+ });
48
+ }
49
+ const HELP = `Usage: framedash query <sql> [options]
50
+ framedash query --file query.sql [options]
51
+
52
+ Execute a read-only ClickHouse query.
53
+
54
+ Arguments:
55
+ <sql> SQL query string
56
+
57
+ Options:
58
+ -f, --file <path> Read SQL from file
59
+ --limit <n> Max rows (default: 1000)
60
+ --api-key <key> API key (or FRAMEDASH_API_KEY env)
61
+ --project-id <uuid> Project ID (or FRAMEDASH_PROJECT_ID env)
62
+ --base-url <url> API base URL (default: https://app.framedash.dev)
63
+ --format <fmt> Output format: json, table, csv (default: json)
64
+ -h, --help Show help
65
+
66
+ Examples:
67
+ framedash query "SELECT count() FROM events"
68
+ framedash query "SELECT event_name, count() FROM events GROUP BY event_name" --format table
69
+ framedash query --file complex-query.sql --limit 100`;
70
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAc;IACzC,MAAM,UAAU,CACf;QACC,IAAI;QACJ,IAAI,EAAE,IAAI;QACV,OAAO,EAAE;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;SACpC;QACD,gBAAgB,EAAE,IAAI;KACtB,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE;QACjD,IAAI,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,iFAAiF,CAAC,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QAED,IAAI,GAAW,CAAC;QAChB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC;gBACJ,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAc,EAAE,OAAO,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;gBACjE,KAAK,CAAC,4BAA4B,MAAM,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC;gBAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACF,CAAC;aAAM,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,2DAA2D,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,IAAI,GAA4B;YACrC,GAAG;YACH,UAAU,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC;QACF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAe,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACtD,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC,CACD,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;uDAoB0C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function retention(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=retention.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.d.ts","sourceRoot":"","sources":["../../src/commands/retention.ts"],"names":[],"mappings":"AAIA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7D"}
@@ -0,0 +1,22 @@
1
+ import { formatOutput } from "../lib/formatters.js";
2
+ import { log } from "../lib/logger.js";
3
+ import { runCommand } from "../lib/run-command.js";
4
+ export async function retention(args) {
5
+ await runCommand({ args, help: HELP, options: { days: { type: "string" } } }, async ({ client, config, values }) => {
6
+ const params = new URLSearchParams({ days: values.days ?? "30" });
7
+ const data = await client.get(client.projectPath(`retention?${params}`));
8
+ log(formatOutput(data, config.format));
9
+ });
10
+ }
11
+ const HELP = `Usage: framedash retention [options]
12
+
13
+ Show player retention cohorts.
14
+
15
+ Options:
16
+ --days <n> Time period in days: 1, 7, 14, 30 (default: 30)
17
+ --api-key <key> API key (or FRAMEDASH_API_KEY env)
18
+ --project-id <uuid> Project ID (or FRAMEDASH_PROJECT_ID env)
19
+ --base-url <url> API base URL (default: https://app.framedash.dev)
20
+ --format <fmt> Output format: json, table, csv (default: json)
21
+ -h, --help Show help`;
22
+ //# sourceMappingURL=retention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/commands/retention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc;IAC7C,MAAM,UAAU,CACf,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAC3D,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,IAAI,EAAG,MAAM,CAAC,IAAe,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC,CAAC;QACzE,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC,CACD,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;;mCAUsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function status(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAIA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1D"}
@@ -0,0 +1,20 @@
1
+ import { formatOutput } from "../lib/formatters.js";
2
+ import { log } from "../lib/logger.js";
3
+ import { runCommand } from "../lib/run-command.js";
4
+ export async function status(args) {
5
+ await runCommand({ args, help: HELP }, async ({ client, config }) => {
6
+ const data = await client.get(client.projectPath("status"));
7
+ log(formatOutput(data, config.format));
8
+ });
9
+ }
10
+ const HELP = `Usage: framedash status [options]
11
+
12
+ Show project status and key metrics.
13
+
14
+ Options:
15
+ --api-key <key> API key (or FRAMEDASH_API_KEY env)
16
+ --project-id <uuid> Project ID (or FRAMEDASH_PROJECT_ID env)
17
+ --base-url <url> API base URL (default: https://app.framedash.dev)
18
+ --format <fmt> Output format: json, table, csv (default: json)
19
+ -h, --help Show help`;
20
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAc;IAC1C,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QACnE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5D,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;mCASsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { error, log } from "./lib/logger.js";
4
+ const VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"))
5
+ .version;
6
+ const HELP = `Usage: framedash <command> [options]
7
+
8
+ Commands:
9
+ auth Verify API key and list projects
10
+ status Show project status and key metrics
11
+ dashboard Show dashboard metrics
12
+ retention Show player retention cohorts
13
+ funnel Analyze event funnels
14
+ query Execute a read-only ClickHouse query
15
+ alerts Manage alert rules (list, create, update, delete)
16
+ maps Manage maps (list, delete)
17
+ content Manage content registry (list, import, delete)
18
+ map-capture Upload captured map images
19
+
20
+ Global Options:
21
+ --api-key <key> API key. Prefer FRAMEDASH_API_KEY env or --api-key-file:
22
+ a key passed as --api-key is visible in the process
23
+ list and shell history.
24
+ --api-key-file <path> Read the API key from a file ('-' for stdin)
25
+ --project-id <uuid> Project ID (or FRAMEDASH_PROJECT_ID env)
26
+ --base-url <url> API base URL (default: https://app.framedash.dev)
27
+ --format <fmt> Output format: json, table, csv (default: json)
28
+ -h, --help Show help
29
+ -v, --version Show version
30
+
31
+ Run 'framedash <command> --help' for command-specific options.`;
32
+ /** Type-safe command registry — typos in export names become build-time errors. */
33
+ const COMMANDS = {
34
+ auth: () => import("./commands/auth.js").then((m) => m.auth),
35
+ status: () => import("./commands/status.js").then((m) => m.status),
36
+ dashboard: () => import("./commands/dashboard.js").then((m) => m.dashboard),
37
+ retention: () => import("./commands/retention.js").then((m) => m.retention),
38
+ funnel: () => import("./commands/funnel.js").then((m) => m.funnel),
39
+ query: () => import("./commands/query.js").then((m) => m.query),
40
+ alerts: () => import("./commands/alerts.js").then((m) => m.alerts),
41
+ maps: () => import("./commands/maps.js").then((m) => m.maps),
42
+ content: () => import("./commands/content.js").then((m) => m.content),
43
+ "map-capture": () => import("./commands/map-capture.js").then((m) => m.mapCaptureCommand),
44
+ };
45
+ const command = process.argv[2];
46
+ const commandArgs = process.argv.slice(3);
47
+ if (command === "-v" || command === "--version") {
48
+ log(`framedash v${VERSION}`);
49
+ process.exit(0);
50
+ }
51
+ if (!command || command === "-h" || command === "--help") {
52
+ log(HELP);
53
+ process.exit(0);
54
+ }
55
+ try {
56
+ if (!Object.hasOwn(COMMANDS, command)) {
57
+ error(`Unknown command: ${command}`);
58
+ log(HELP);
59
+ process.exit(1);
60
+ }
61
+ // biome-ignore lint/style/noNonNullAssertion: validated by Object.hasOwn above
62
+ const fn = await COMMANDS[command]();
63
+ await fn(commandArgs);
64
+ }
65
+ catch (err) {
66
+ if (err instanceof Error && "code" in err && err.code === "ERR_PARSE_ARGS_UNKNOWN_OPTION") {
67
+ error(err.message);
68
+ process.exit(1);
69
+ }
70
+ error(err instanceof Error ? err.message : String(err));
71
+ process.exit(1);
72
+ }
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ export type OutputFormat = "json" | "table" | "csv";
2
+ export type CliConfig = {
3
+ apiKey: string;
4
+ projectId: string;
5
+ baseUrl: string;
6
+ format: OutputFormat;
7
+ };
8
+ /**
9
+ * Resolve the API key, preferring sources that keep it out of the process
10
+ * argument list: --api-key flag, then --api-key-file (a path, or "-" for stdin),
11
+ * then the FRAMEDASH_API_KEY env var. Returns undefined if none is set.
12
+ */
13
+ export declare function resolveApiKey(values: Record<string, unknown>): string | undefined;
14
+ /** Resolve global CLI config from parsed flags and environment variables. */
15
+ export declare function resolveConfig(values: Record<string, unknown>): CliConfig;
16
+ /** Resolve config for commands that don't require --project-id (e.g. auth). */
17
+ export declare function resolveConfigWithoutProject(values: Record<string, unknown>): Omit<CliConfig, "projectId">;
18
+ /** Parse a string flag as a positive integer with a descriptive error. */
19
+ export declare function parsePositiveInt(value: string, flagName: string): number;
20
+ /** Parse a string flag as a non-negative number with a descriptive error. */
21
+ export declare function parseNumber(value: string, flagName: string): number;
22
+ /**
23
+ * Global parseArgs option definitions shared by all commands.
24
+ * Spread into each command's parseArgs call.
25
+ */
26
+ export declare const GLOBAL_OPTIONS: {
27
+ "api-key": {
28
+ type: "string";
29
+ };
30
+ "api-key-file": {
31
+ type: "string";
32
+ };
33
+ "project-id": {
34
+ type: "string";
35
+ };
36
+ "base-url": {
37
+ type: "string";
38
+ };
39
+ format: {
40
+ type: "string";
41
+ };
42
+ help: {
43
+ type: "boolean";
44
+ short: "h";
45
+ };
46
+ };
47
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAEpD,MAAM,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;CACrB,CAAC;AA6BF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CA+BjF;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgBxE;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAS9B;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOxE;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;CAO1B,CAAC"}