blokctl 0.2.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/dist/commands/build/index.d.ts +2 -0
- package/dist/commands/build/index.js +210 -0
- package/dist/commands/config/index.d.ts +1 -0
- package/dist/commands/config/index.js +46 -0
- package/dist/commands/cost/index.d.ts +1 -0
- package/dist/commands/cost/index.js +74 -0
- package/dist/commands/create/node.d.ts +2 -0
- package/dist/commands/create/node.js +541 -0
- package/dist/commands/create/project.d.ts +2 -0
- package/dist/commands/create/project.js +941 -0
- package/dist/commands/create/utils/Examples.d.ts +39 -0
- package/dist/commands/create/utils/Examples.js +983 -0
- package/dist/commands/create/workflow.d.ts +2 -0
- package/dist/commands/create/workflow.js +109 -0
- package/dist/commands/deploy/index.d.ts +2 -0
- package/dist/commands/deploy/index.js +176 -0
- package/dist/commands/dev/index.d.ts +2 -0
- package/dist/commands/dev/index.js +190 -0
- package/dist/commands/generate/GenerationAnalytics.d.ts +61 -0
- package/dist/commands/generate/GenerationAnalytics.js +162 -0
- package/dist/commands/generate/GenerationAnalytics.test.d.ts +1 -0
- package/dist/commands/generate/GenerationAnalytics.test.js +407 -0
- package/dist/commands/generate/NodeFileWriter.d.ts +5 -0
- package/dist/commands/generate/NodeFileWriter.js +240 -0
- package/dist/commands/generate/NodeGenerator.d.ts +20 -0
- package/dist/commands/generate/NodeGenerator.js +181 -0
- package/dist/commands/generate/NodeGenerator.test.d.ts +1 -0
- package/dist/commands/generate/NodeGenerator.test.js +101 -0
- package/dist/commands/generate/PromptVersioning.d.ts +25 -0
- package/dist/commands/generate/PromptVersioning.js +71 -0
- package/dist/commands/generate/PromptVersioning.test.d.ts +1 -0
- package/dist/commands/generate/PromptVersioning.test.js +120 -0
- package/dist/commands/generate/RegisterNode.d.ts +3 -0
- package/dist/commands/generate/RegisterNode.js +37 -0
- package/dist/commands/generate/RuntimeGenerator.d.ts +40 -0
- package/dist/commands/generate/RuntimeGenerator.js +369 -0
- package/dist/commands/generate/RuntimeGenerator.test.d.ts +1 -0
- package/dist/commands/generate/RuntimeGenerator.test.js +553 -0
- package/dist/commands/generate/TriggerGenerator.d.ts +22 -0
- package/dist/commands/generate/TriggerGenerator.js +220 -0
- package/dist/commands/generate/TriggerGenerator.test.d.ts +1 -0
- package/dist/commands/generate/TriggerGenerator.test.js +209 -0
- package/dist/commands/generate/WorkflowGenerator.d.ts +20 -0
- package/dist/commands/generate/WorkflowGenerator.js +131 -0
- package/dist/commands/generate/WorkflowGenerator.test.d.ts +1 -0
- package/dist/commands/generate/WorkflowGenerator.test.js +77 -0
- package/dist/commands/generate/e2e/NodeGenerator.e2e.test.d.ts +1 -0
- package/dist/commands/generate/e2e/NodeGenerator.e2e.test.js +216 -0
- package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.d.ts +1 -0
- package/dist/commands/generate/e2e/RuntimeGenerator.e2e.test.js +759 -0
- package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.d.ts +1 -0
- package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.js +295 -0
- package/dist/commands/generate/e2e/WorkflowGenerator.e2e.test.d.ts +1 -0
- package/dist/commands/generate/e2e/WorkflowGenerator.e2e.test.js +353 -0
- package/dist/commands/generate/index.d.ts +1 -0
- package/dist/commands/generate/index.js +418 -0
- package/dist/commands/generate/prompts/create-fn-node.system.d.ts +5 -0
- package/dist/commands/generate/prompts/create-fn-node.system.js +256 -0
- package/dist/commands/generate/prompts/create-node-manifest.system.d.ts +4 -0
- package/dist/commands/generate/prompts/create-node-manifest.system.js +41 -0
- package/dist/commands/generate/prompts/create-node.system.d.ts +5 -0
- package/dist/commands/generate/prompts/create-node.system.js +114 -0
- package/dist/commands/generate/prompts/create-readme.system.d.ts +4 -0
- package/dist/commands/generate/prompts/create-readme.system.js +83 -0
- package/dist/commands/generate/prompts/create-runtime.system.d.ts +5 -0
- package/dist/commands/generate/prompts/create-runtime.system.js +284 -0
- package/dist/commands/generate/prompts/create-trigger.system.d.ts +5 -0
- package/dist/commands/generate/prompts/create-trigger.system.js +293 -0
- package/dist/commands/generate/prompts/create-workflow.system.d.ts +5 -0
- package/dist/commands/generate/prompts/create-workflow.system.js +476 -0
- package/dist/commands/generate/prompts/register-node.system.d.ts +4 -0
- package/dist/commands/generate/prompts/register-node.system.js +26 -0
- package/dist/commands/generate/validators/CompilationValidator.d.ts +9 -0
- package/dist/commands/generate/validators/CompilationValidator.js +86 -0
- package/dist/commands/generate/validators/CompilationValidator.test.d.ts +1 -0
- package/dist/commands/generate/validators/CompilationValidator.test.js +161 -0
- package/dist/commands/generate/validators/NodeValidator.d.ts +18 -0
- package/dist/commands/generate/validators/NodeValidator.js +217 -0
- package/dist/commands/generate/validators/NodeValidator.test.d.ts +1 -0
- package/dist/commands/generate/validators/NodeValidator.test.js +281 -0
- package/dist/commands/generate/validators/WorkflowValidator.d.ts +6 -0
- package/dist/commands/generate/validators/WorkflowValidator.js +301 -0
- package/dist/commands/generate/validators/WorkflowValidator.test.d.ts +1 -0
- package/dist/commands/generate/validators/WorkflowValidator.test.js +647 -0
- package/dist/commands/generate/validators/index.d.ts +4 -0
- package/dist/commands/generate/validators/index.js +2 -0
- package/dist/commands/graph/index.d.ts +1 -0
- package/dist/commands/graph/index.js +69 -0
- package/dist/commands/install/index.d.ts +1 -0
- package/dist/commands/install/index.js +4 -0
- package/dist/commands/install/node.d.ts +4 -0
- package/dist/commands/install/node.js +136 -0
- package/dist/commands/install/workflow.d.ts +4 -0
- package/dist/commands/install/workflow.js +62 -0
- package/dist/commands/login/index.d.ts +2 -0
- package/dist/commands/login/index.js +77 -0
- package/dist/commands/logout/index.d.ts +2 -0
- package/dist/commands/logout/index.js +20 -0
- package/dist/commands/marketplace/runtime.d.ts +54 -0
- package/dist/commands/marketplace/runtime.js +350 -0
- package/dist/commands/migrate/index.d.ts +1 -0
- package/dist/commands/migrate/index.js +14 -0
- package/dist/commands/migrate/node.d.ts +2 -0
- package/dist/commands/migrate/node.js +110 -0
- package/dist/commands/monitor/index.d.ts +1 -0
- package/dist/commands/monitor/index.js +28 -0
- package/dist/commands/monitor/monitor-component.d.ts +1 -0
- package/dist/commands/monitor/monitor-component.js +271 -0
- package/dist/commands/monitor/static/index.html +2124 -0
- package/dist/commands/monitor/static-web-server.d.ts +1 -0
- package/dist/commands/monitor/static-web-server.js +89 -0
- package/dist/commands/profile/index.d.ts +1 -0
- package/dist/commands/profile/index.js +112 -0
- package/dist/commands/publish/index.d.ts +1 -0
- package/dist/commands/publish/index.js +4 -0
- package/dist/commands/publish/node.d.ts +4 -0
- package/dist/commands/publish/node.js +231 -0
- package/dist/commands/publish/workflow.d.ts +4 -0
- package/dist/commands/publish/workflow.js +165 -0
- package/dist/commands/search/docs.d.ts +17 -0
- package/dist/commands/search/docs.js +179 -0
- package/dist/commands/search/index.d.ts +1 -0
- package/dist/commands/search/index.js +5 -0
- package/dist/commands/search/indexer.d.ts +10 -0
- package/dist/commands/search/indexer.js +265 -0
- package/dist/commands/search/nodes.d.ts +4 -0
- package/dist/commands/search/nodes.js +101 -0
- package/dist/commands/search/workflow.d.ts +4 -0
- package/dist/commands/search/workflow.js +100 -0
- package/dist/commands/trace/index.d.ts +1 -0
- package/dist/commands/trace/index.js +26 -0
- package/dist/commands/trace/startStudio.d.ts +8 -0
- package/dist/commands/trace/startStudio.js +116 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +186 -0
- package/dist/services/commander.d.ts +9 -0
- package/dist/services/commander.js +20 -0
- package/dist/services/constants.d.ts +1 -0
- package/dist/services/constants.js +3 -0
- package/dist/services/local-token-manager.d.ts +14 -0
- package/dist/services/local-token-manager.js +99 -0
- package/dist/services/non-interactive.d.ts +5 -0
- package/dist/services/non-interactive.js +30 -0
- package/dist/services/package-manager.d.ts +35 -0
- package/dist/services/package-manager.js +111 -0
- package/dist/services/posthog.d.ts +31 -0
- package/dist/services/posthog.js +159 -0
- package/dist/services/registry-manager.d.ts +9 -0
- package/dist/services/registry-manager.js +26 -0
- package/dist/services/runtime-detector.d.ts +23 -0
- package/dist/services/runtime-detector.js +181 -0
- package/dist/services/runtime-setup.d.ts +36 -0
- package/dist/services/runtime-setup.js +250 -0
- package/dist/services/utils.d.ts +2 -0
- package/dist/services/utils.js +29 -0
- package/dist/services/workflow-loader.d.ts +30 -0
- package/dist/services/workflow-loader.js +46 -0
- package/dist/studio-dist/assets/charts-Dso0hPUR.js +68 -0
- package/dist/studio-dist/assets/graph-CsV2nWGn.js +23 -0
- package/dist/studio-dist/assets/icons-zP8LLgPh.js +311 -0
- package/dist/studio-dist/assets/index-CLyEkXMx.css +1 -0
- package/dist/studio-dist/assets/index-CNXFX_ar.js +27 -0
- package/dist/studio-dist/assets/react-vendor--Eh9ivFN.js +17 -0
- package/dist/studio-dist/assets/tanstack-query-CiM1U6F5.js +1 -0
- package/dist/studio-dist/assets/tanstack-router-Btjy0MKq.js +25 -0
- package/dist/studio-dist/assets/tanstack-table-DhwRvuH2.js +22 -0
- package/dist/studio-dist/favicon.svg +5 -0
- package/dist/studio-dist/index.html +21 -0
- package/package.json +75 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { program, trackCommandExecution } from "../../services/commander.js";
|
|
2
|
+
import { startStudio } from "./startStudio.js";
|
|
3
|
+
program
|
|
4
|
+
.command("trace")
|
|
5
|
+
.alias("studio")
|
|
6
|
+
.description("Open Blok Studio — real-time workflow trace UI")
|
|
7
|
+
.option("-p, --port <port>", "Studio UI port", "5555")
|
|
8
|
+
.option("-u, --url <url>", "Blok backend URL", "http://localhost:4000")
|
|
9
|
+
.option("--workflow <name>", "Open specific workflow")
|
|
10
|
+
.option("--run <id>", "Open specific run")
|
|
11
|
+
.option("--no-open", "Don't auto-open browser")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
await trackCommandExecution({
|
|
14
|
+
command: "trace",
|
|
15
|
+
args: options,
|
|
16
|
+
execution: async () => {
|
|
17
|
+
await startStudio({
|
|
18
|
+
port: Number.parseInt(options.port, 10),
|
|
19
|
+
url: options.url,
|
|
20
|
+
workflow: options.workflow,
|
|
21
|
+
run: options.run,
|
|
22
|
+
open: options.open,
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import https from "node:https";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
7
|
+
import open from "open";
|
|
8
|
+
import color from "picocolors";
|
|
9
|
+
import serveHandler from "serve-handler";
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
function resolveStaticPath() {
|
|
13
|
+
const bundled = path.resolve(__dirname, "../../studio-dist");
|
|
14
|
+
if (fs.existsSync(path.join(bundled, "index.html")))
|
|
15
|
+
return bundled;
|
|
16
|
+
const workspace = path.resolve(__dirname, "../../../../apps/studio/dist");
|
|
17
|
+
if (fs.existsSync(path.join(workspace, "index.html")))
|
|
18
|
+
return workspace;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
async function checkBackendHealth(backendUrl) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
const url = new URL("/__blok/health", backendUrl);
|
|
24
|
+
const client = url.protocol === "https:" ? https : http;
|
|
25
|
+
const req = client.get(url, { timeout: 3000 }, (res) => {
|
|
26
|
+
resolve(res.statusCode === 200);
|
|
27
|
+
});
|
|
28
|
+
req.on("error", () => resolve(false));
|
|
29
|
+
req.on("timeout", () => {
|
|
30
|
+
req.destroy();
|
|
31
|
+
resolve(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function proxyRequest(req, res, backendUrl) {
|
|
36
|
+
const targetUrl = new URL(req.url, backendUrl);
|
|
37
|
+
const client = targetUrl.protocol === "https:" ? https : http;
|
|
38
|
+
const proxyReq = client.request(targetUrl, {
|
|
39
|
+
method: req.method,
|
|
40
|
+
headers: {
|
|
41
|
+
...req.headers,
|
|
42
|
+
host: targetUrl.host,
|
|
43
|
+
},
|
|
44
|
+
}, (proxyRes) => {
|
|
45
|
+
res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
|
|
46
|
+
proxyRes.pipe(res, { end: true });
|
|
47
|
+
});
|
|
48
|
+
proxyReq.on("error", () => {
|
|
49
|
+
if (!res.headersSent) {
|
|
50
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
51
|
+
res.end(JSON.stringify({ error: "Backend unavailable" }));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
req.on("close", () => {
|
|
55
|
+
proxyReq.destroy();
|
|
56
|
+
});
|
|
57
|
+
req.pipe(proxyReq, { end: true });
|
|
58
|
+
}
|
|
59
|
+
export async function startStudio(options) {
|
|
60
|
+
const { port, url: backendUrl, open: shouldOpen } = options;
|
|
61
|
+
p.intro(color.bgCyan(color.black(" Blok Studio ")));
|
|
62
|
+
const staticPath = resolveStaticPath();
|
|
63
|
+
if (!staticPath) {
|
|
64
|
+
p.log.error(`Studio assets not found.\n` + ` Build them first: ${color.cyan("pnpm --filter @blok/studio build")}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const s = p.spinner();
|
|
68
|
+
s.start("Checking backend health...");
|
|
69
|
+
const healthy = await checkBackendHealth(backendUrl);
|
|
70
|
+
if (!healthy) {
|
|
71
|
+
s.stop(color.yellow("Backend not reachable"));
|
|
72
|
+
p.log.warn(`Blok backend not found at ${color.cyan(backendUrl)}\n` + ` Start it first: ${color.cyan("blokctl dev")}`);
|
|
73
|
+
p.log.info("Starting Studio anyway — it will connect when the backend is up.");
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
s.stop(color.green("Backend healthy"));
|
|
77
|
+
}
|
|
78
|
+
const server = http.createServer((req, res) => {
|
|
79
|
+
const url = req.url || "/";
|
|
80
|
+
if (url.startsWith("/__blok")) {
|
|
81
|
+
return proxyRequest(req, res, backendUrl);
|
|
82
|
+
}
|
|
83
|
+
serveHandler(req, res, {
|
|
84
|
+
public: staticPath,
|
|
85
|
+
rewrites: [{ source: "**", destination: "/index.html" }],
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return new Promise(() => {
|
|
89
|
+
server.listen(port, async () => {
|
|
90
|
+
let studioUrl = `http://localhost:${port}`;
|
|
91
|
+
if (options.workflow) {
|
|
92
|
+
studioUrl += `/workflows/${encodeURIComponent(options.workflow)}`;
|
|
93
|
+
}
|
|
94
|
+
else if (options.run) {
|
|
95
|
+
studioUrl += `/runs/${encodeURIComponent(options.run)}`;
|
|
96
|
+
}
|
|
97
|
+
p.log.success(`Studio running at ${color.cyan(studioUrl)}`);
|
|
98
|
+
p.log.info(`Connected to backend at ${color.dim(backendUrl)}`);
|
|
99
|
+
console.log(color.dim(" Press Ctrl+C to stop\n"));
|
|
100
|
+
if (shouldOpen) {
|
|
101
|
+
await open(studioUrl);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const stop = () => {
|
|
105
|
+
console.log();
|
|
106
|
+
server.close(() => {
|
|
107
|
+
p.outro(color.dim("Blok Studio stopped."));
|
|
108
|
+
process.exit(0);
|
|
109
|
+
});
|
|
110
|
+
setTimeout(() => process.exit(0), 3000);
|
|
111
|
+
};
|
|
112
|
+
process.once("SIGINT", stop);
|
|
113
|
+
process.once("SIGTERM", stop);
|
|
114
|
+
process.once("SIGQUIT", stop);
|
|
115
|
+
});
|
|
116
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#! /usr/bin/env bun
|
|
2
|
+
import "./commands/login/index.js";
|
|
3
|
+
import "./commands/logout/index.js";
|
|
4
|
+
import "./commands/build/index.js";
|
|
5
|
+
import "./commands/deploy/index.js";
|
|
6
|
+
import "./commands/monitor/index.js";
|
|
7
|
+
import "./commands/publish/index.js";
|
|
8
|
+
import "./commands/install/index.js";
|
|
9
|
+
import "./commands/search/index.js";
|
|
10
|
+
import "./commands/generate/index.js";
|
|
11
|
+
import "./commands/config/index.js";
|
|
12
|
+
import "./commands/migrate/index.js";
|
|
13
|
+
import "./commands/graph/index.js";
|
|
14
|
+
import "./commands/profile/index.js";
|
|
15
|
+
import "./commands/cost/index.js";
|
|
16
|
+
import "./commands/trace/index.js";
|
|
17
|
+
export declare const CLI_NAME = "blokctl";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#! /usr/bin/env bun
|
|
2
|
+
import child_process from "node:child_process";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import util from "node:util";
|
|
5
|
+
import * as p from "@clack/prompts";
|
|
6
|
+
import fsExtra from "fs-extra";
|
|
7
|
+
import color from "picocolors";
|
|
8
|
+
import { createNode } from "./commands/create/node.js";
|
|
9
|
+
import { createProject } from "./commands/create/project.js";
|
|
10
|
+
import { createWorkflow } from "./commands/create/workflow.js";
|
|
11
|
+
import { devProject } from "./commands/dev/index.js";
|
|
12
|
+
import { program } from "./services/commander.js";
|
|
13
|
+
import { setNonInteractive } from "./services/non-interactive.js";
|
|
14
|
+
import { PosthogAnalytics } from "./services/posthog.js";
|
|
15
|
+
import { getPackageVersion } from "./services/utils.js";
|
|
16
|
+
import "./commands/login/index.js";
|
|
17
|
+
import "./commands/logout/index.js";
|
|
18
|
+
import "./commands/build/index.js";
|
|
19
|
+
import "./commands/deploy/index.js";
|
|
20
|
+
import "./commands/monitor/index.js";
|
|
21
|
+
import "./commands/publish/index.js";
|
|
22
|
+
import "./commands/install/index.js";
|
|
23
|
+
import "./commands/search/index.js";
|
|
24
|
+
import "./commands/generate/index.js";
|
|
25
|
+
import "./commands/config/index.js";
|
|
26
|
+
import "./commands/migrate/index.js";
|
|
27
|
+
import "./commands/graph/index.js";
|
|
28
|
+
import "./commands/profile/index.js";
|
|
29
|
+
import "./commands/cost/index.js";
|
|
30
|
+
import "./commands/trace/index.js";
|
|
31
|
+
import { Command } from "commander";
|
|
32
|
+
const version = await getPackageVersion();
|
|
33
|
+
const exec = util.promisify(child_process.exec);
|
|
34
|
+
export const CLI_NAME = "blokctl";
|
|
35
|
+
const validateVersion = async (currentVersion) => {
|
|
36
|
+
let latestVersion;
|
|
37
|
+
try {
|
|
38
|
+
const execResponse = await exec(`npm view ${CLI_NAME} version`);
|
|
39
|
+
latestVersion = execResponse.stdout.trim();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return { currentVersion, latestVersion: currentVersion, isLatest: true };
|
|
43
|
+
}
|
|
44
|
+
const [latestMajor, latestMinor, latestPatch] = latestVersion.split(".").map(Number);
|
|
45
|
+
const [currentMajor, currentMinor, currentPatch] = currentVersion.split(".").map(Number);
|
|
46
|
+
let isLatest = true;
|
|
47
|
+
if (latestMajor > currentMajor ||
|
|
48
|
+
(latestMajor === currentMajor && latestMinor > currentMinor) ||
|
|
49
|
+
(latestMajor === currentMajor && latestMinor === currentMinor && latestPatch > currentPatch)) {
|
|
50
|
+
p.log.warn(`A new version of ${CLI_NAME} CLI is available.\nPlease update to the latest version.\nVersion:\t${color.red(currentVersion)} > ${color.green(latestVersion)}`);
|
|
51
|
+
isLatest = false;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
currentVersion,
|
|
55
|
+
latestVersion,
|
|
56
|
+
isLatest,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
async function main() {
|
|
60
|
+
try {
|
|
61
|
+
const HOME_DIR = `${os.homedir()}/.blok`;
|
|
62
|
+
const cliConfigPath = `${HOME_DIR}/blokctl.json`;
|
|
63
|
+
fsExtra.ensureDirSync(HOME_DIR);
|
|
64
|
+
const analytics = new PosthogAnalytics({
|
|
65
|
+
version: version,
|
|
66
|
+
cliConfigPath: cliConfigPath,
|
|
67
|
+
});
|
|
68
|
+
program.version(`${version}`, "-v, --version").description(`Blok CLI ${version}`);
|
|
69
|
+
program.option("--non-interactive", "Disable interactive prompts (fail if required flags are missing)");
|
|
70
|
+
program.hook("preAction", (thisCommand) => {
|
|
71
|
+
const opts = thisCommand.opts();
|
|
72
|
+
if (opts.nonInteractive) {
|
|
73
|
+
setNonInteractive(true);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
await validateVersion(version);
|
|
77
|
+
const create = new Command("create").description("Create a new blok component");
|
|
78
|
+
const project = new Command("project")
|
|
79
|
+
.description("Create a new Project")
|
|
80
|
+
.option("-n, --name <value>", "Create a default Project")
|
|
81
|
+
.option("-l, --local <path>", "Use a local repo path instead of cloning from remote")
|
|
82
|
+
.option("-t, --trigger <value>", "Single trigger type (backwards compat, default: http)")
|
|
83
|
+
.option("-T, --triggers <value>", "Comma-separated trigger list: http,sse,pubsub,queue (default: http)")
|
|
84
|
+
.option("-r, --runtimes <value>", "Comma-separated runtime list (default: node)")
|
|
85
|
+
.option("-m, --package-manager <value>", "Package manager: npm, yarn, pnpm, bun")
|
|
86
|
+
.option("--pubsub-provider <value>", "Pub/Sub provider: gcp, aws, azure (default: gcp)")
|
|
87
|
+
.option("--queue-provider <value>", "Queue provider: kafka, rabbitmq, sqs, redis (default: kafka)")
|
|
88
|
+
.option("--examples", "Install example workflows and nodes")
|
|
89
|
+
.action(async (options) => {
|
|
90
|
+
await analytics.trackCommandExecution({
|
|
91
|
+
command: "create project",
|
|
92
|
+
args: options,
|
|
93
|
+
execution: async () => {
|
|
94
|
+
createProject(options, version, false, options.local);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
project
|
|
99
|
+
.command(".")
|
|
100
|
+
.description("Create a new Project")
|
|
101
|
+
.action(async (options) => {
|
|
102
|
+
await analytics.trackCommandExecution({
|
|
103
|
+
command: "create project .",
|
|
104
|
+
args: options,
|
|
105
|
+
execution: async () => {
|
|
106
|
+
createProject(options, version, true, project.opts().local);
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
const node = new Command("node")
|
|
111
|
+
.description("Create a new Node")
|
|
112
|
+
.option("-n, --name <value>", "Create a default Node")
|
|
113
|
+
.option("-s, --style <value>", "Node style: 'function' (recommended) or 'class'")
|
|
114
|
+
.option("-r, --runtime <value>", "Runtime: typescript, python3, go, java, rust, csharp, php, ruby")
|
|
115
|
+
.option("-m, --package-manager <value>", "Package manager: npm, yarn, pnpm, bun")
|
|
116
|
+
.option("--node-type <value>", "Node type: module, class (TypeScript only)")
|
|
117
|
+
.option("--template <value>", "Template: standard, ui (TypeScript only)")
|
|
118
|
+
.action(async (options) => {
|
|
119
|
+
await analytics.trackCommandExecution({
|
|
120
|
+
command: "create node",
|
|
121
|
+
args: options,
|
|
122
|
+
execution: async () => {
|
|
123
|
+
createNode(options, false);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
node
|
|
128
|
+
.command(".")
|
|
129
|
+
.description("Create a new Node")
|
|
130
|
+
.option("-s, --style <value>", "Node style: 'function' (recommended) or 'class'")
|
|
131
|
+
.action(async (options) => {
|
|
132
|
+
await analytics.trackCommandExecution({
|
|
133
|
+
command: "create node",
|
|
134
|
+
args: options,
|
|
135
|
+
execution: async () => {
|
|
136
|
+
createNode(options, true);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
const workflow = new Command("workflow")
|
|
141
|
+
.description("Create a new Workflow")
|
|
142
|
+
.option("-n, --name <value>", "Create a default Workflow")
|
|
143
|
+
.action(async (options) => {
|
|
144
|
+
await analytics.trackCommandExecution({
|
|
145
|
+
command: "create workflow",
|
|
146
|
+
args: options,
|
|
147
|
+
execution: async () => {
|
|
148
|
+
createWorkflow(options, false);
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
workflow
|
|
153
|
+
.command(".")
|
|
154
|
+
.description("Create a new Workflow")
|
|
155
|
+
.action(async (options) => {
|
|
156
|
+
await analytics.trackCommandExecution({
|
|
157
|
+
command: "create workflow",
|
|
158
|
+
args: options,
|
|
159
|
+
execution: async () => {
|
|
160
|
+
createWorkflow(options, true);
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
create.addCommand(project);
|
|
165
|
+
create.addCommand(node);
|
|
166
|
+
create.addCommand(workflow);
|
|
167
|
+
program.addCommand(create);
|
|
168
|
+
program
|
|
169
|
+
.command("dev")
|
|
170
|
+
.description("Start the development server")
|
|
171
|
+
.action(async (options) => {
|
|
172
|
+
await analytics.trackCommandExecution({
|
|
173
|
+
command: "dev",
|
|
174
|
+
args: options,
|
|
175
|
+
execution: async () => {
|
|
176
|
+
devProject(options);
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
program.parse(process.argv);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
console.log(err.message);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
main();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command, type OptionValues } from "commander";
|
|
2
|
+
declare const program: Command;
|
|
3
|
+
type TrackCommandExecutionParams = {
|
|
4
|
+
command: string;
|
|
5
|
+
args: OptionValues;
|
|
6
|
+
execution: () => Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
declare const trackCommandExecution: ({ command, args, execution }: TrackCommandExecutionParams) => Promise<void>;
|
|
9
|
+
export { program, trackCommandExecution, Command, type OptionValues, type TrackCommandExecutionParams };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { PosthogAnalytics } from "./posthog.js";
|
|
4
|
+
import { getPackageVersion } from "./utils.js";
|
|
5
|
+
const version = await getPackageVersion();
|
|
6
|
+
const program = new Command();
|
|
7
|
+
const HOME_DIR = `${os.homedir()}/.blok`;
|
|
8
|
+
const cliConfigPath = `${HOME_DIR}/blokctl.json`;
|
|
9
|
+
const analytics = new PosthogAnalytics({
|
|
10
|
+
version: version,
|
|
11
|
+
cliConfigPath: cliConfigPath,
|
|
12
|
+
});
|
|
13
|
+
const trackCommandExecution = async ({ command, args, execution }) => {
|
|
14
|
+
await analytics.trackCommandExecution({
|
|
15
|
+
command: command,
|
|
16
|
+
args: args,
|
|
17
|
+
execution,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
export { program, trackCommandExecution, Command };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BLOK_URL: string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare class LocalTokenManager {
|
|
2
|
+
private storageDir;
|
|
3
|
+
private tokenFile;
|
|
4
|
+
constructor();
|
|
5
|
+
private ensureStorage;
|
|
6
|
+
private getEncryptionKey;
|
|
7
|
+
private encrypt;
|
|
8
|
+
private decrypt;
|
|
9
|
+
storeToken(token: string): boolean;
|
|
10
|
+
getToken(): string | null;
|
|
11
|
+
clearToken(): boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const tokenManager: LocalTokenManager;
|
|
14
|
+
export { LocalTokenManager, tokenManager };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
class LocalTokenManager {
|
|
6
|
+
storageDir;
|
|
7
|
+
tokenFile;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.storageDir = path.join(os.homedir(), ".blok/token");
|
|
10
|
+
this.tokenFile = path.join(this.storageDir, "token.enc");
|
|
11
|
+
this.ensureStorage();
|
|
12
|
+
}
|
|
13
|
+
ensureStorage() {
|
|
14
|
+
try {
|
|
15
|
+
if (!fs.existsSync(this.storageDir)) {
|
|
16
|
+
fs.mkdirSync(this.storageDir, { mode: 0o700 });
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
fs.chmodSync(this.storageDir, 0o700);
|
|
20
|
+
}
|
|
21
|
+
if (!fs.existsSync(this.tokenFile)) {
|
|
22
|
+
fs.writeFileSync(this.tokenFile, "", { mode: 0o600 });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
fs.chmodSync(this.tokenFile, 0o600);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error("Failed to initialize secure storage:", error.message);
|
|
30
|
+
throw new Error("Could not set up secure token storage, please check permissions.");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
getEncryptionKey() {
|
|
34
|
+
const machineId = os.hostname();
|
|
35
|
+
const salt = crypto
|
|
36
|
+
.createHash("sha256")
|
|
37
|
+
.update(os.userInfo().username + os.arch() + os.platform())
|
|
38
|
+
.digest("hex");
|
|
39
|
+
return crypto.scryptSync(machineId + salt, "salt", 32);
|
|
40
|
+
}
|
|
41
|
+
encrypt(text) {
|
|
42
|
+
const iv = crypto.randomBytes(16);
|
|
43
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", this.getEncryptionKey(), iv);
|
|
44
|
+
let encrypted = cipher.update(text, "utf8", "hex");
|
|
45
|
+
encrypted += cipher.final("hex");
|
|
46
|
+
const authTag = cipher.getAuthTag().toString("hex");
|
|
47
|
+
return `${iv.toString("hex")}:${authTag}:${encrypted}`;
|
|
48
|
+
}
|
|
49
|
+
decrypt(encryptedText) {
|
|
50
|
+
const parts = encryptedText.split(":");
|
|
51
|
+
if (parts.length !== 3) {
|
|
52
|
+
throw new Error("Invalid encrypted text format");
|
|
53
|
+
}
|
|
54
|
+
const [ivHex, authTagHex, encrypted] = parts;
|
|
55
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
56
|
+
const authTag = Buffer.from(authTagHex, "hex");
|
|
57
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", this.getEncryptionKey(), iv);
|
|
58
|
+
decipher.setAuthTag(authTag);
|
|
59
|
+
let decrypted = decipher.update(encrypted, "hex", "utf8");
|
|
60
|
+
decrypted += decipher.final("utf8");
|
|
61
|
+
return decrypted;
|
|
62
|
+
}
|
|
63
|
+
storeToken(token) {
|
|
64
|
+
try {
|
|
65
|
+
const encrypted = this.encrypt(token);
|
|
66
|
+
fs.writeFileSync(this.tokenFile, encrypted, { mode: 0o600 });
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("Failed to store token:", error.message);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
getToken() {
|
|
75
|
+
try {
|
|
76
|
+
if (!fs.existsSync(this.tokenFile))
|
|
77
|
+
return null;
|
|
78
|
+
const encrypted = fs.readFileSync(this.tokenFile, "utf8");
|
|
79
|
+
return this.decrypt(encrypted);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
clearToken() {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(this.tokenFile)) {
|
|
88
|
+
fs.unlinkSync(this.tokenFile);
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error("Failed to clear token:", error.message);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const tokenManager = new LocalTokenManager();
|
|
99
|
+
export { LocalTokenManager, tokenManager };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function isNonInteractive(): boolean;
|
|
2
|
+
export declare function setNonInteractive(value: boolean): void;
|
|
3
|
+
export declare function resolveOrThrow<T>(flagName: string, flagValue: T | undefined, defaultValue?: T): T;
|
|
4
|
+
export declare function validateChoice<T extends string>(flagName: string, value: T, allowed: readonly T[]): T;
|
|
5
|
+
export declare function parseCommaSeparated(value: string): string[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
let _nonInteractive = false;
|
|
2
|
+
export function isNonInteractive() {
|
|
3
|
+
return _nonInteractive || process.env.BLOK_NON_INTERACTIVE === "1";
|
|
4
|
+
}
|
|
5
|
+
export function setNonInteractive(value) {
|
|
6
|
+
_nonInteractive = value;
|
|
7
|
+
}
|
|
8
|
+
export function resolveOrThrow(flagName, flagValue, defaultValue) {
|
|
9
|
+
if (flagValue !== undefined)
|
|
10
|
+
return flagValue;
|
|
11
|
+
if (defaultValue !== undefined)
|
|
12
|
+
return defaultValue;
|
|
13
|
+
if (isNonInteractive()) {
|
|
14
|
+
throw new Error(`Missing required flag --${flagName} (non-interactive mode). ` +
|
|
15
|
+
`Run without --non-interactive to use interactive prompts, or provide --${flagName}.`);
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
export function validateChoice(flagName, value, allowed) {
|
|
20
|
+
if (!allowed.includes(value)) {
|
|
21
|
+
throw new Error(`Invalid value "${value}" for --${flagName}. Allowed: ${allowed.join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export function parseCommaSeparated(value) {
|
|
26
|
+
return value
|
|
27
|
+
.split(",")
|
|
28
|
+
.map((s) => s.trim())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare enum VersionUpdateType {
|
|
2
|
+
PATCH = "patch",
|
|
3
|
+
MINOR = "minor",
|
|
4
|
+
MAJOR = "major"
|
|
5
|
+
}
|
|
6
|
+
type PackageManagerType = {
|
|
7
|
+
[key: string]: {
|
|
8
|
+
INSTALL: string;
|
|
9
|
+
BUILD: string;
|
|
10
|
+
PUBLISH: (opts: {
|
|
11
|
+
registry: string;
|
|
12
|
+
npmrcDir: string;
|
|
13
|
+
}) => string;
|
|
14
|
+
INSTALL_NODE: (opts: {
|
|
15
|
+
node: string;
|
|
16
|
+
registry: string;
|
|
17
|
+
npmrcDir: string;
|
|
18
|
+
}) => string;
|
|
19
|
+
UPDATE_VERSION: (opts: {
|
|
20
|
+
type: VersionUpdateType;
|
|
21
|
+
}) => string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
declare class PackageManager {
|
|
25
|
+
private static instance;
|
|
26
|
+
private detectedManager;
|
|
27
|
+
private constructor();
|
|
28
|
+
static getInstance(): PackageManager;
|
|
29
|
+
private isAvailable;
|
|
30
|
+
getAvailableManagers(): Promise<string[]>;
|
|
31
|
+
getManager(preferedManager?: string): Promise<PackageManagerType[string]>;
|
|
32
|
+
}
|
|
33
|
+
export default PackageManager;
|
|
34
|
+
declare const manager: PackageManager;
|
|
35
|
+
export { manager };
|