blokctl 0.2.0 → 0.2.2
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/cost/index.js +1 -1
- package/dist/commands/create/project.js +23 -23
- package/dist/commands/create/utils/Examples.d.ts +4 -4
- package/dist/commands/create/utils/Examples.js +9 -9
- package/dist/commands/generate/GenerationAnalytics.test.js +1 -1
- package/dist/commands/generate/NodeGenerator.js +5 -5
- package/dist/commands/generate/NodeGenerator.test.js +2 -2
- package/dist/commands/generate/TriggerGenerator.js +5 -5
- package/dist/commands/generate/TriggerGenerator.test.js +7 -7
- package/dist/commands/generate/e2e/NodeGenerator.e2e.test.js +5 -5
- package/dist/commands/generate/e2e/TriggerGenerator.e2e.test.js +6 -6
- package/dist/commands/generate/e2e/WorkflowGenerator.e2e.test.js +2 -2
- package/dist/commands/generate/prompts/create-fn-node.system.js +8 -8
- package/dist/commands/generate/prompts/create-node.system.js +2 -2
- package/dist/commands/generate/prompts/create-trigger.system.js +4 -4
- package/dist/commands/generate/prompts/create-workflow.system.js +9 -9
- package/dist/commands/generate/prompts/register-node.system.js +2 -2
- package/dist/commands/generate/validators/CompilationValidator.test.js +5 -5
- package/dist/commands/generate/validators/NodeValidator.js +2 -2
- package/dist/commands/generate/validators/NodeValidator.test.js +10 -10
- package/dist/commands/generate/validators/WorkflowValidator.test.js +4 -4
- package/dist/commands/graph/index.js +1 -1
- package/dist/commands/marketplace/runtime.d.ts +1 -1
- package/dist/commands/profile/index.js +1 -1
- package/dist/commands/trace/startStudio.js +1 -1
- package/package.json +3 -3
|
@@ -3,7 +3,7 @@ import * as p from "@clack/prompts";
|
|
|
3
3
|
import { program, trackCommandExecution } from "../../services/commander.js";
|
|
4
4
|
import { loadWorkflow, loadWorkflows } from "../../services/workflow-loader.js";
|
|
5
5
|
async function getCostEstimator() {
|
|
6
|
-
const { CostEstimator } = await import("@
|
|
6
|
+
const { CostEstimator } = await import("@blokjs/runner");
|
|
7
7
|
return CostEstimator;
|
|
8
8
|
}
|
|
9
9
|
program
|
|
@@ -370,13 +370,13 @@ export async function createProject(opts, version, currentPath = false, localRep
|
|
|
370
370
|
packageJsonContent.version = "1.0.0";
|
|
371
371
|
packageJsonContent.author = "";
|
|
372
372
|
const workspacePackageMap = {
|
|
373
|
-
"@
|
|
374
|
-
"@
|
|
375
|
-
"@
|
|
376
|
-
"@
|
|
377
|
-
"@
|
|
378
|
-
"@
|
|
379
|
-
"@
|
|
373
|
+
"@blokjs/api-call": "nodes/web/api-call@1.0.0",
|
|
374
|
+
"@blokjs/helper": "core/workflow-helper",
|
|
375
|
+
"@blokjs/if-else": "nodes/control-flow/if-else@1.0.0",
|
|
376
|
+
"@blokjs/runner": "core/runner",
|
|
377
|
+
"@blokjs/shared": "core/shared",
|
|
378
|
+
"@blokjs/trigger-pubsub": "triggers/pubsub",
|
|
379
|
+
"@blokjs/trigger-queue": "triggers/queue",
|
|
380
380
|
};
|
|
381
381
|
for (const depGroup of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
382
382
|
const deps = packageJsonContent[depGroup];
|
|
@@ -426,12 +426,12 @@ export async function createProject(opts, version, currentPath = false, localRep
|
|
|
426
426
|
}
|
|
427
427
|
const triggerPackageDeps = {};
|
|
428
428
|
if (selectedTriggers.includes("pubsub")) {
|
|
429
|
-
const pubsubRef = localRepoPath ? `file:${path.resolve(repoSource, "triggers/pubsub")}` : "@
|
|
430
|
-
triggerPackageDeps["@
|
|
429
|
+
const pubsubRef = localRepoPath ? `file:${path.resolve(repoSource, "triggers/pubsub")}` : "@blokjs/trigger-pubsub";
|
|
430
|
+
triggerPackageDeps["@blokjs/trigger-pubsub"] = localRepoPath ? pubsubRef : "workspace:*";
|
|
431
431
|
}
|
|
432
432
|
if (selectedTriggers.includes("queue")) {
|
|
433
|
-
const queueRef = localRepoPath ? `file:${path.resolve(repoSource, "triggers/queue")}` : "@
|
|
434
|
-
triggerPackageDeps["@
|
|
433
|
+
const queueRef = localRepoPath ? `file:${path.resolve(repoSource, "triggers/queue")}` : "@blokjs/trigger-queue";
|
|
434
|
+
triggerPackageDeps["@blokjs/trigger-queue"] = localRepoPath ? queueRef : "workspace:*";
|
|
435
435
|
}
|
|
436
436
|
if (Object.keys(triggerPackageDeps).length > 0) {
|
|
437
437
|
packageJsonContent.dependencies = {
|
|
@@ -532,11 +532,11 @@ export async function createProject(opts, version, currentPath = false, localRep
|
|
|
532
532
|
function generateSharedNodesFile(triggers, _repoSource) {
|
|
533
533
|
const nodeImports = new Set();
|
|
534
534
|
const nodeExports = new Map();
|
|
535
|
-
nodeImports.add('import ApiCall from "@
|
|
536
|
-
nodeImports.add('import IfElse from "@
|
|
537
|
-
nodeImports.add('import type { BlokService } from "@
|
|
538
|
-
nodeExports.set("@
|
|
539
|
-
nodeExports.set("@
|
|
535
|
+
nodeImports.add('import ApiCall from "@blokjs/api-call";');
|
|
536
|
+
nodeImports.add('import IfElse from "@blokjs/if-else";');
|
|
537
|
+
nodeImports.add('import type { BlokService } from "@blokjs/runner";');
|
|
538
|
+
nodeExports.set("@blokjs/api-call", "ApiCall");
|
|
539
|
+
nodeExports.set("@blokjs/if-else", "IfElse");
|
|
540
540
|
for (const trigger of triggers) {
|
|
541
541
|
if (trigger === "sse") {
|
|
542
542
|
nodeImports.add('import WelcomeMessage from "./nodes/welcome-message/index";');
|
|
@@ -580,7 +580,7 @@ function generateSharedWorkflowsFile(triggers) {
|
|
|
580
580
|
}
|
|
581
581
|
const importSection = imports.length > 0 ? `${imports.join("\n")}\n` : "";
|
|
582
582
|
const entriesSection = workflowEntries.length > 0 ? workflowEntries.join("\n") : "\t// Add your workflows here";
|
|
583
|
-
return `import type { HelperResponse } from "@
|
|
583
|
+
return `import type { HelperResponse } from "@blokjs/helper";
|
|
584
584
|
|
|
585
585
|
${importSection}
|
|
586
586
|
const workflows: Record<string, HelperResponse> = {
|
|
@@ -592,7 +592,7 @@ export default workflows;
|
|
|
592
592
|
}
|
|
593
593
|
function generateTriggerEntryFile(triggerKind) {
|
|
594
594
|
if (triggerKind === "http") {
|
|
595
|
-
return `import { DefaultLogger } from "@
|
|
595
|
+
return `import { DefaultLogger } from "@blokjs/runner";
|
|
596
596
|
import { type Span, metrics, trace } from "@opentelemetry/api";
|
|
597
597
|
import HttpTrigger from "./runner/HttpTrigger";
|
|
598
598
|
|
|
@@ -640,7 +640,7 @@ if (process.env.DISABLE_TRIGGER_RUN !== "true") {
|
|
|
640
640
|
`;
|
|
641
641
|
}
|
|
642
642
|
if (triggerKind === "sse") {
|
|
643
|
-
return `import { DefaultLogger } from "@
|
|
643
|
+
return `import { DefaultLogger } from "@blokjs/runner";
|
|
644
644
|
import { type Span, metrics, trace } from "@opentelemetry/api";
|
|
645
645
|
import SSEServer from "./runner/SSEServer";
|
|
646
646
|
|
|
@@ -688,7 +688,7 @@ export default class App {
|
|
|
688
688
|
`;
|
|
689
689
|
}
|
|
690
690
|
if (triggerKind === "pubsub") {
|
|
691
|
-
return `import { DefaultLogger } from "@
|
|
691
|
+
return `import { DefaultLogger } from "@blokjs/runner";
|
|
692
692
|
import { type Span, metrics, trace } from "@opentelemetry/api";
|
|
693
693
|
import PubSubServer from "./runner/PubSubServer";
|
|
694
694
|
|
|
@@ -732,7 +732,7 @@ if (process.env.DISABLE_TRIGGER_RUN !== "true") {
|
|
|
732
732
|
`;
|
|
733
733
|
}
|
|
734
734
|
if (triggerKind === "queue") {
|
|
735
|
-
return `import { DefaultLogger } from "@
|
|
735
|
+
return `import { DefaultLogger } from "@blokjs/runner";
|
|
736
736
|
import { type Span, metrics, trace } from "@opentelemetry/api";
|
|
737
737
|
import QueueServer from "./runner/QueueServer";
|
|
738
738
|
|
|
@@ -831,7 +831,7 @@ function updatePubSubProvider(triggerDestDir, provider) {
|
|
|
831
831
|
const config = adapterConfigs[provider];
|
|
832
832
|
if (!config)
|
|
833
833
|
return;
|
|
834
|
-
content = content.replace(/import \{ PubSubTrigger, \w+ \} from "@blok\/trigger-pubsub";/, `import { PubSubTrigger, ${config.importName} } from "@
|
|
834
|
+
content = content.replace(/import \{ PubSubTrigger, \w+ \} from "@blok\/trigger-pubsub";/, `import { PubSubTrigger, ${config.importName} } from "@blokjs/trigger-pubsub";`);
|
|
835
835
|
content = content.replace(/(export default class \w+ extends PubSubTrigger \{[\s\S]*?)\n\tprotected adapter = new \w+\(\{[\s\S]*?\}\);/, `$1\n\tprotected adapter = ${config.init};`);
|
|
836
836
|
fsExtra.writeFileSync(serverPath, content);
|
|
837
837
|
}
|
|
@@ -871,7 +871,7 @@ function updateQueueProvider(triggerDestDir, provider) {
|
|
|
871
871
|
const config = adapterConfigs[provider];
|
|
872
872
|
if (!config)
|
|
873
873
|
return;
|
|
874
|
-
content = content.replace(/import \{ QueueTrigger, \w+ \} from "@blok\/trigger-queue";/, `import { QueueTrigger, ${config.importName} } from "@
|
|
874
|
+
content = content.replace(/import \{ QueueTrigger, \w+ \} from "@blok\/trigger-queue";/, `import { QueueTrigger, ${config.importName} } from "@blokjs/trigger-queue";`);
|
|
875
875
|
content = content.replace(/(export default class \w+ extends QueueTrigger \{[\s\S]*?)\n\tprotected adapter = new \w+\(\{[\s\S]*?\}\);/, `$1\n\tprotected adapter = ${config.init};`);
|
|
876
876
|
fsExtra.writeFileSync(serverPath, content);
|
|
877
877
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const node_file = "import ApiCall from \"@
|
|
1
|
+
declare const node_file = "import ApiCall from \"@blokjs/api-call\";\nimport IfElse from \"@blokjs/if-else\";\nimport type { NodeBase } from \"@blokjs/shared\";\nimport ChainInit from \"./nodes/chain-init/index\";\nimport ChainVerify from \"./nodes/chain-verify/index\";\nimport ExampleNodes from \"./nodes/examples/index\";\nimport RuntimeBridge from \"./nodes/runtime-bridge/index\";\n\nconst nodes: {\n\t[key: string]: NodeBase;\n} = {\n\t\"@blokjs/api-call\": ApiCall,\n\t\"@blokjs/if-else\": IfElse,\n\t\"chain-init\": ChainInit,\n\t\"chain-verify\": ChainVerify,\n\t\"runtime-bridge\": RuntimeBridge,\n\t...ExampleNodes,\n};\n\nexport default nodes;\n";
|
|
2
2
|
declare const package_dependencies: {
|
|
3
3
|
ai: string;
|
|
4
4
|
"@ai-sdk/openai": string;
|
|
@@ -33,7 +33,7 @@ declare const php_dockerfile = "FROM php:8.2-cli-alpine AS builder\nWORKDIR /app
|
|
|
33
33
|
declare const ruby_node_file = "require_relative '../../lib/blok'\n\nmodule Blok\n module Nodes\n class {{NODE_NAME_PASCAL}}Node < Blok::NodeHandler\n def execute(ctx, config)\n # Access request body\n name = ctx.request.body.is_a?(Hash) ? ctx.request.body['name'] : nil\n name ||= 'World'\n\n # Access configuration\n prefix = config['prefix'] || 'Hello'\n\n message = \"#{prefix}, #{name}!\"\n\n # Store in context for downstream nodes\n ctx.vars['greeting'] = message\n\n # Return response\n {\n 'message' => message,\n 'timestamp' => Time.now.utc.iso8601,\n 'language' => 'Ruby'\n }\n end\n end\n end\nend\n";
|
|
34
34
|
declare const ruby_gemfile = "source 'https://rubygems.org'\n\nruby '>= 3.1'\n\ngem 'sinatra', '~> 4.0'\ngem 'puma', '~> 6.4'\ngem 'rackup', '~> 2.1'\n";
|
|
35
35
|
declare const ruby_dockerfile = "FROM ruby:3.2-alpine AS builder\nRUN apk add --no-cache build-base\nWORKDIR /app\nCOPY Gemfile Gemfile.lock ./\nRUN bundle install --without development test\n\nFROM ruby:3.2-alpine\nRUN apk --no-cache add ca-certificates wget\nWORKDIR /app\nCOPY --from=builder /usr/local/bundle /usr/local/bundle\nCOPY . .\n\nEXPOSE 8080\nENV PORT=8080\nENV RACK_ENV=production\nHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\\n CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1\n\nCMD [\"bundle\", \"exec\", \"puma\", \"-b\", \"tcp://0.0.0.0:8080\"]\n";
|
|
36
|
-
declare const agents_md = "# Blok Project\n\nBlok is a TypeScript-first workflow orchestration framework. It executes declarative workflows (JSON or TypeScript DSL) composed of steps (nodes) that run across 8 language runtimes: NodeJS, Python3, Go, Rust, Java, C#, PHP, and Ruby.\n\n## Project Structure\n\n```\n\u251C\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 nodes/ # TypeScript node implementations\n\u251C\u2500\u2500 runtimes/ # Non-NodeJS runtime nodes (Go, Python3, etc.)\n\u2502 \u2514\u2500\u2500 {lang}/nodes/ # Language-specific node implementations\n\u251C\u2500\u2500 workflows/\n\u2502 \u251C\u2500\u2500 json/ # Workflow definitions (JSON)\n\u2502 \u251C\u2500\u2500 yaml/ # Workflow definitions (YAML)\n\u2502 \u2514\u2500\u2500 toml/ # Workflow definitions (TOML)\n\u251C\u2500\u2500 .blok/\n\u2502 \u251C\u2500\u2500 config.json # Runtime configuration (ports, start commands)\n\u2502 \u2514\u2500\u2500 runtimes/ # Auto-generated runtime scaffolds\n\u251C\u2500\u2500 .env.local # Environment variables (ports, paths)\n\u2514\u2500\u2500 supervisord.conf # Process management config\n```\n\n## Commands\n\n```bash\nnpm run dev # Start dev server (or blokctl dev for multi-runtime)\nnpm run build # Build project\nnpm test # Run tests\nblokctl create node <name> # Scaffold a new node\nblokctl create workflow <n># Scaffold a new workflow\nblokctl trace # Open Blok Studio (trace visualization)\nblokctl studio # Alias for blokctl trace\n```\n\n## Context \u2014 Critical Data Flow\n\nThe Context type is the central execution state passed through every step.\n\n```typescript\ntype Context = {\n id: string; // Unique request ID\n request: RequestContext; // Incoming request (body, headers, params, query)\n response: ResponseContext; // Current step output \u2014 OVERWRITTEN every step\n vars?: VarsContext; // Persistent variables \u2014 PERSISTS across workflow\n config: ConfigContext; // Node config (inputs resolved by Mapper)\n env?: EnvContext; // process.env access\n logger: LoggerContext;\n error: ErrorContext;\n};\n```\n\n### The Two Critical Rules\n\n**Rule 1: \\`ctx.response.data\\` is OVERWRITTEN after every step.**\nEach step's output replaces the previous \\`ctx.response.data\\`. If you need a step's output later, store it in \\`ctx.vars\\`.\n\n**Rule 2: \\`ctx.vars\\` PERSISTS across the entire workflow.**\nUse \\`set_var: true\\` on a step to auto-store its output in \\`ctx.vars[stepName]\\`. Downstream steps access it via \\`ctx.vars['step-name']\\`.\n\n### Data Flow Example\n\n```\nStep 1: \"fetch-user\" (set_var: true)\n \u2192 ctx.response.data = { id: \"123\", name: \"Alice\" }\n \u2192 ctx.vars[\"fetch-user\"] = { id: \"123\", name: \"Alice\" }\n\nStep 2: \"transform\"\n \u2192 ctx.response.data = { result: \"done\" } \u2190 Step 1 output GONE from response\n \u2192 ctx.vars[\"fetch-user\"] still available\n\nStep 3: \"output\"\n \u2192 Can read ctx.vars[\"fetch-user\"].name \u2190 still \"Alice\"\n```\n\n### Blueprint Mapper \u2014 Expression Resolution\n\nNode inputs support dynamic expressions resolved BEFORE node execution:\n\n```json\n{\n \"inputs\": {\n \"userId\": \"js/ctx.request.body.userId\",\n \"chain\": \"js/ctx.vars['previous-step'].chain\",\n \"previous\": \"js/ctx.response.data.result\"\n }\n}\n```\n\nAvailable in js/ expressions: \\`ctx\\`, \\`data\\` (ctx.response.data), \\`func\\` (ctx.func), \\`vars\\` (ctx.vars)\n\n---\n\n## Creating Nodes with defineNode\n\nUse \\`defineNode()\\` for all new nodes. Never use the legacy class-based pattern.\n\n```typescript\nimport { defineNode } from \"@
|
|
37
|
-
declare const claude_md = "# Blok Project \u2014 Claude Code Guide\n\nRead \\`AGENTS.md\\` for full architecture and API details. This file contains Claude-specific guidance.\n\n## Quick Commands\n\n\\`\\`\\`bash\nnpm run dev # Start dev server\nblokctl dev # Multi-runtime dev server\nblokctl create node <name> # Scaffold new node\nblokctl create workflow <name> # Scaffold new workflow\nblokctl trace # Open Blok Studio\nnpm test # Run tests\n\\`\\`\\`\n\n## Context Rules (Memorize These)\n\n1. **\\`ctx.response.data\\` is OVERWRITTEN every step.** Previous output GONE unless stored in vars.\n2. **\\`ctx.vars\\` PERSISTS across the workflow.** Use \\`set_var: true\\` or \\`js/ctx.vars['step']\\`.\n3. **Blueprint Mapper resolves \\`js/\\` expressions BEFORE node execution.**\n\nWhen users have data flow issues, check these three things first.\n\n## Debugging Workflows\n\n1. **Verify structure**: Every \\`steps[].name\\` must match a key in \\`nodes\\`\n2. **Trace data flow**: Which steps have \\`set_var: true\\`? Do \\`js/\\` expressions reference correct step names?\n3. **Check runtimes**: SDK containers running? \\`GET http://localhost:{port}/health\\`\n4. **Check Studio traces**: \\`/__blok/runs/:id\\` shows step-by-step inputs/outputs/errors\n\n### Common Errors\n\n| Error | Fix |\n|-------|-----|\n| \\`Node type X not found\\` | Wrong \\`type\\` in step \u2014 use module, local, or runtime.* |\n| \\`Validation failed\\` | Zod schema mismatch \u2014 check input schema vs actual data |\n| \\`Runtime execution error\\` | SDK container not running \u2014 check health endpoint |\n| \\`ctx.vars['X'] undefined\\` | Source step missing \\`set_var: true\\` or name mismatch |\n\n## Generating Code\n\nAlways use \\`defineNode()\\`. Never class-based BlokService.\n\n\\`\\`\\`typescript\nimport { defineNode } from \"@
|
|
38
|
-
declare const function_first_node_file = "import { defineNode } from \"@
|
|
36
|
+
declare const agents_md = "# Blok Project\n\nBlok is a TypeScript-first workflow orchestration framework. It executes declarative workflows (JSON or TypeScript DSL) composed of steps (nodes) that run across 8 language runtimes: NodeJS, Python3, Go, Rust, Java, C#, PHP, and Ruby.\n\n## Project Structure\n\n```\n\u251C\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 nodes/ # TypeScript node implementations\n\u251C\u2500\u2500 runtimes/ # Non-NodeJS runtime nodes (Go, Python3, etc.)\n\u2502 \u2514\u2500\u2500 {lang}/nodes/ # Language-specific node implementations\n\u251C\u2500\u2500 workflows/\n\u2502 \u251C\u2500\u2500 json/ # Workflow definitions (JSON)\n\u2502 \u251C\u2500\u2500 yaml/ # Workflow definitions (YAML)\n\u2502 \u2514\u2500\u2500 toml/ # Workflow definitions (TOML)\n\u251C\u2500\u2500 .blok/\n\u2502 \u251C\u2500\u2500 config.json # Runtime configuration (ports, start commands)\n\u2502 \u2514\u2500\u2500 runtimes/ # Auto-generated runtime scaffolds\n\u251C\u2500\u2500 .env.local # Environment variables (ports, paths)\n\u2514\u2500\u2500 supervisord.conf # Process management config\n```\n\n## Commands\n\n```bash\nnpm run dev # Start dev server (or blokctl dev for multi-runtime)\nnpm run build # Build project\nnpm test # Run tests\nblokctl create node <name> # Scaffold a new node\nblokctl create workflow <n># Scaffold a new workflow\nblokctl trace # Open Blok Studio (trace visualization)\nblokctl studio # Alias for blokctl trace\n```\n\n## Context \u2014 Critical Data Flow\n\nThe Context type is the central execution state passed through every step.\n\n```typescript\ntype Context = {\n id: string; // Unique request ID\n request: RequestContext; // Incoming request (body, headers, params, query)\n response: ResponseContext; // Current step output \u2014 OVERWRITTEN every step\n vars?: VarsContext; // Persistent variables \u2014 PERSISTS across workflow\n config: ConfigContext; // Node config (inputs resolved by Mapper)\n env?: EnvContext; // process.env access\n logger: LoggerContext;\n error: ErrorContext;\n};\n```\n\n### The Two Critical Rules\n\n**Rule 1: \\`ctx.response.data\\` is OVERWRITTEN after every step.**\nEach step's output replaces the previous \\`ctx.response.data\\`. If you need a step's output later, store it in \\`ctx.vars\\`.\n\n**Rule 2: \\`ctx.vars\\` PERSISTS across the entire workflow.**\nUse \\`set_var: true\\` on a step to auto-store its output in \\`ctx.vars[stepName]\\`. Downstream steps access it via \\`ctx.vars['step-name']\\`.\n\n### Data Flow Example\n\n```\nStep 1: \"fetch-user\" (set_var: true)\n \u2192 ctx.response.data = { id: \"123\", name: \"Alice\" }\n \u2192 ctx.vars[\"fetch-user\"] = { id: \"123\", name: \"Alice\" }\n\nStep 2: \"transform\"\n \u2192 ctx.response.data = { result: \"done\" } \u2190 Step 1 output GONE from response\n \u2192 ctx.vars[\"fetch-user\"] still available\n\nStep 3: \"output\"\n \u2192 Can read ctx.vars[\"fetch-user\"].name \u2190 still \"Alice\"\n```\n\n### Blueprint Mapper \u2014 Expression Resolution\n\nNode inputs support dynamic expressions resolved BEFORE node execution:\n\n```json\n{\n \"inputs\": {\n \"userId\": \"js/ctx.request.body.userId\",\n \"chain\": \"js/ctx.vars['previous-step'].chain\",\n \"previous\": \"js/ctx.response.data.result\"\n }\n}\n```\n\nAvailable in js/ expressions: \\`ctx\\`, \\`data\\` (ctx.response.data), \\`func\\` (ctx.func), \\`vars\\` (ctx.vars)\n\n---\n\n## Creating Nodes with defineNode\n\nUse \\`defineNode()\\` for all new nodes. Never use the legacy class-based pattern.\n\n```typescript\nimport { defineNode } from \"@blokjs/runner\";\nimport { z } from \"zod\";\n\nexport default defineNode({\n name: \"fetch-user\",\n description: \"Fetches user by ID\",\n\n input: z.object({\n userId: z.string().uuid(),\n }),\n\n output: z.object({\n user: z.object({\n id: z.string(),\n name: z.string(),\n email: z.string().email(),\n }),\n }),\n\n async execute(ctx, input) {\n const user = await fetchUser(input.userId);\n return { user };\n },\n});\n```\n\n### Key Behaviors\n\n- Zod input/output validation runs automatically\n- ZodError is mapped to GlobalError with HTTP 400\n- \\`flow: true\\` nodes return NodeBase[] for conditional execution\n- \\`contentType\\` sets response Content-Type (e.g., \"text/html\")\n- Always \\`export default defineNode(...)\\`\n\n---\n\n## Workflow Structure (JSON)\n\n```json\n{\n \"name\": \"My Workflow\",\n \"version\": \"1.0.0\",\n \"trigger\": {\n \"http\": { \"method\": \"POST\", \"path\": \"/api/process\", \"accept\": \"application/json\" }\n },\n \"steps\": [\n { \"name\": \"fetch\", \"node\": \"@blokjs/api-call\", \"type\": \"module\" },\n { \"name\": \"process\", \"node\": \"my-node\", \"type\": \"module\", \"set_var\": true },\n { \"name\": \"go-step\", \"node\": \"chain-test\", \"type\": \"runtime.go\" }\n ],\n \"nodes\": {\n \"fetch\": { \"inputs\": { \"url\": \"https://api.example.com\", \"method\": \"GET\" } },\n \"process\": { \"inputs\": { \"data\": \"js/ctx.response.data\" } },\n \"go-step\": { \"inputs\": { \"processed\": \"js/ctx.vars['process']\" } }\n }\n}\n```\n\n### Step Types\n\n| Type | Description |\n|------|-------------|\n| \\`module\\` | TypeScript node from registered modules |\n| \\`local\\` | TypeScript node from filesystem (NODES_PATH) |\n| \\`runtime.python3\\` | Python3 SDK container (port 9007) |\n| \\`runtime.go\\` | Go SDK container (port 9001) |\n| \\`runtime.rust\\` | Rust SDK container (port 9002) |\n| \\`runtime.java\\` | Java SDK container (port 9003) |\n| \\`runtime.csharp\\` | C# SDK container (port 9004) |\n| \\`runtime.php\\` | PHP SDK container (port 9005) |\n| \\`runtime.ruby\\` | Ruby SDK container (port 9006) |\n\n### Conditional Workflow (if-else)\n\n```json\n{\n \"nodes\": {\n \"filter\": {\n \"conditions\": [\n {\n \"type\": \"if\",\n \"condition\": \"ctx.request.query.active === \\\\\"true\\\\\"\",\n \"steps\": [{ \"name\": \"active-path\", \"node\": \"handle-active\", \"type\": \"module\" }]\n },\n {\n \"type\": \"else\",\n \"steps\": [{ \"name\": \"default-path\", \"node\": \"handle-default\", \"type\": \"module\" }]\n }\n ]\n }\n }\n}\n```\n\n---\n\n## Trigger Types\n\n| Trigger | Example Config |\n|---------|---------------|\n| \\`http\\` | \\`{ \"method\": \"GET\", \"path\": \"/\", \"accept\": \"application/json\" }\\` |\n| \\`grpc\\` | \\`{ \"service\": \"UserService\", \"method\": \"GetUser\" }\\` |\n| \\`cron\\` | \\`{ \"schedule\": \"0 * * * *\", \"timezone\": \"UTC\" }\\` |\n| \\`queue\\` | \\`{ \"provider\": \"kafka\", \"topic\": \"events\" }\\` |\n| \\`pubsub\\` | \\`{ \"provider\": \"gcp\", \"topic\": \"updates\" }\\` |\n| \\`webhook\\` | \\`{ \"source\": \"github\", \"events\": [\"push\"] }\\` |\n| \\`websocket\\` | \\`{ \"events\": [\"message\"], \"path\": \"/ws\" }\\` |\n| \\`sse\\` | \\`{ \"events\": [\"update\"], \"path\": \"/stream\" }\\` |\n| \\`worker\\` | \\`{ \"queue\": \"jobs\", \"concurrency\": 5 }\\` |\n\n---\n\n## Runtime Adapter System\n\nAll non-NodeJS SDKs communicate via HTTP:\n- **POST /execute** \u2014 Execute node with context\n- **GET /health** \u2014 Health check\n\nEnvironment variables: \\`RUNTIME_{LANG}_HOST\\` / \\`RUNTIME_{LANG}_PORT\\`\n\nRuntime nodes auto-save \\`result.data\\` to \\`ctx.vars[stepName]\\`.\n\n---\n\n## Blok Studio\n\nReal-time workflow trace visualization UI.\n\n- Launch: \\`blokctl trace\\` or \\`blokctl studio\\`\n- API: \\`/__blok/runs\\`, \\`/__blok/runs/:id\\`, \\`/__blok/runs/:id/stream\\` (SSE)\n- Disable: \\`BLOK_TRACE_ENABLED=false\\`\n\n---\n\n## Do NOT\n\n- Do NOT rely on \\`ctx.response.data\\` for data from non-previous steps \u2014 it gets overwritten\n- Do NOT create class-based nodes \u2014 use \\`defineNode()\\` instead\n- Do NOT use \\`any\\` type \u2014 use \\`unknown\\` and narrow with Zod\n- Do NOT hardcode runtime ports \u2014 use environment variables\n- Do NOT skip Zod input/output schemas\n- Do NOT edit files in \\`.blok/runtimes/\\` \u2014 they are auto-generated\n\n## Do\n\n- Use \\`ctx.vars\\` with \\`set_var: true\\` to pass data between non-adjacent steps\n- Use \\`js/ctx.vars['step-name'].field\\` in workflow inputs for data flow\n- Use Zod schemas for all input/output validation\n- Use \\`defineNode()\\` for all new nodes\n- Handle errors via GlobalError with appropriate HTTP status codes\n- Keep nodes focused \u2014 one responsibility per node\n";
|
|
37
|
+
declare const claude_md = "# Blok Project \u2014 Claude Code Guide\n\nRead \\`AGENTS.md\\` for full architecture and API details. This file contains Claude-specific guidance.\n\n## Quick Commands\n\n\\`\\`\\`bash\nnpm run dev # Start dev server\nblokctl dev # Multi-runtime dev server\nblokctl create node <name> # Scaffold new node\nblokctl create workflow <name> # Scaffold new workflow\nblokctl trace # Open Blok Studio\nnpm test # Run tests\n\\`\\`\\`\n\n## Context Rules (Memorize These)\n\n1. **\\`ctx.response.data\\` is OVERWRITTEN every step.** Previous output GONE unless stored in vars.\n2. **\\`ctx.vars\\` PERSISTS across the workflow.** Use \\`set_var: true\\` or \\`js/ctx.vars['step']\\`.\n3. **Blueprint Mapper resolves \\`js/\\` expressions BEFORE node execution.**\n\nWhen users have data flow issues, check these three things first.\n\n## Debugging Workflows\n\n1. **Verify structure**: Every \\`steps[].name\\` must match a key in \\`nodes\\`\n2. **Trace data flow**: Which steps have \\`set_var: true\\`? Do \\`js/\\` expressions reference correct step names?\n3. **Check runtimes**: SDK containers running? \\`GET http://localhost:{port}/health\\`\n4. **Check Studio traces**: \\`/__blok/runs/:id\\` shows step-by-step inputs/outputs/errors\n\n### Common Errors\n\n| Error | Fix |\n|-------|-----|\n| \\`Node type X not found\\` | Wrong \\`type\\` in step \u2014 use module, local, or runtime.* |\n| \\`Validation failed\\` | Zod schema mismatch \u2014 check input schema vs actual data |\n| \\`Runtime execution error\\` | SDK container not running \u2014 check health endpoint |\n| \\`ctx.vars['X'] undefined\\` | Source step missing \\`set_var: true\\` or name mismatch |\n\n## Generating Code\n\nAlways use \\`defineNode()\\`. Never class-based BlokService.\n\n\\`\\`\\`typescript\nimport { defineNode } from \"@blokjs/runner\";\nimport { z } from \"zod\";\n\nexport default defineNode({\n name: \"node-name\",\n description: \"What this node does\",\n input: z.object({ /* Zod schema */ }),\n output: z.object({ /* Zod schema */ }),\n async execute(ctx, input) {\n return { /* must match output schema */ };\n },\n});\n\\`\\`\\`\n\n### Checklist:\n- Zod input schema covers all inputs\n- Zod output schema matches execute() return\n- Node name matches workflow references\n- No \\`any\\` types \u2014 use \\`z.unknown()\\` if dynamic\n- \\`export default defineNode(...)\\`\n\n## Blok Studio Help\n\n- Launch: \\`blokctl trace\\` or navigate to \\`/__blok\\`\n- \"No output\" \u2192 Node not returning data or Zod output validation failed\n- \"Step error\" \u2192 Expand error \u2014 check if 400 (validation) or 500 (runtime)\n- \"Vars not passing\" \u2192 Source step needs \\`set_var: true\\`, target needs \\`js/ctx.vars['name']\\`\n\n## Do NOT\n\n- Do NOT suggest class-based BlokService for new nodes\n- Do NOT generate code with \\`any\\` types\n- Do NOT assume \\`ctx.response.data\\` persists across steps\n- Do NOT skip Zod schemas when creating nodes\n- Do NOT edit files in \\`.blok/runtimes/\\`\n";
|
|
38
|
+
declare const function_first_node_file = "import { defineNode } from \"@blokjs/runner\";\nimport { z } from \"zod\";\n\n/**\n * A function-first node that demonstrates the modern defineNode pattern.\n * This node is type-safe, validated, and requires 60% less boilerplate.\n */\nexport default defineNode({\n\tname: \"{{NODE_NAME}}\",\n\tdescription: \"A function-first node with Zod validation\",\n\n\t// Input schema using Zod - automatically validated\n\tinput: z.object({\n\t\tmessage: z.string().optional().default(\"Hello World\"),\n\t}),\n\n\t// Output schema using Zod - automatically validated\n\toutput: z.object({\n\t\tmessage: z.string(),\n\t\ttimestamp: z.string(),\n\t}),\n\n\t// Execute function - type-safe with inferred types from Zod schemas\n\tasync execute(ctx, input) {\n\t\t// Your business logic here\n\t\t// - ctx.vars: Access workflow variables\n\t\t// - ctx.request: Access HTTP request data\n\t\t// - ctx.logger: Log messages\n\t\t// - ctx.env: Access environment variables\n\n\t\t// Example: Store data for downstream nodes\n\t\tctx.vars[\"processed-message\"] = input.message;\n\n\t\t// Return type-safe output (validated automatically)\n\t\treturn {\n\t\t\tmessage: `Processed: ${input.message}`,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t},\n});\n";
|
|
39
39
|
export { node_file, package_dependencies, package_dev_dependencies, python3_file, examples_url, workflow_template, supervisord_nodejs, supervisord_python, go_node_file, go_mod_file, go_dockerfile, java_node_file, java_pom_file, java_dockerfile, rust_node_file, rust_cargo_file, rust_dockerfile, csharp_node_file, csharp_csproj_file, csharp_dockerfile, php_node_file, php_composer_file, php_dockerfile, ruby_node_file, ruby_gemfile, ruby_dockerfile, function_first_node_file, agents_md, claude_md, };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const node_file = `import ApiCall from "@
|
|
2
|
-
import IfElse from "@
|
|
3
|
-
import type { NodeBase } from "@
|
|
1
|
+
const node_file = `import ApiCall from "@blokjs/api-call";
|
|
2
|
+
import IfElse from "@blokjs/if-else";
|
|
3
|
+
import type { NodeBase } from "@blokjs/shared";
|
|
4
4
|
import ChainInit from "./nodes/chain-init/index";
|
|
5
5
|
import ChainVerify from "./nodes/chain-verify/index";
|
|
6
6
|
import ExampleNodes from "./nodes/examples/index";
|
|
@@ -9,8 +9,8 @@ import RuntimeBridge from "./nodes/runtime-bridge/index";
|
|
|
9
9
|
const nodes: {
|
|
10
10
|
[key: string]: NodeBase;
|
|
11
11
|
} = {
|
|
12
|
-
"@
|
|
13
|
-
"@
|
|
12
|
+
"@blokjs/api-call": ApiCall,
|
|
13
|
+
"@blokjs/if-else": IfElse,
|
|
14
14
|
"chain-init": ChainInit,
|
|
15
15
|
"chain-verify": ChainVerify,
|
|
16
16
|
"runtime-bridge": RuntimeBridge,
|
|
@@ -707,7 +707,7 @@ Available in js/ expressions: \\\`ctx\\\`, \\\`data\\\` (ctx.response.data), \\\
|
|
|
707
707
|
Use \\\`defineNode()\\\` for all new nodes. Never use the legacy class-based pattern.
|
|
708
708
|
|
|
709
709
|
\`\`\`typescript
|
|
710
|
-
import { defineNode } from "@
|
|
710
|
+
import { defineNode } from "@blokjs/runner";
|
|
711
711
|
import { z } from "zod";
|
|
712
712
|
|
|
713
713
|
export default defineNode({
|
|
@@ -753,7 +753,7 @@ export default defineNode({
|
|
|
753
753
|
"http": { "method": "POST", "path": "/api/process", "accept": "application/json" }
|
|
754
754
|
},
|
|
755
755
|
"steps": [
|
|
756
|
-
{ "name": "fetch", "node": "@
|
|
756
|
+
{ "name": "fetch", "node": "@blokjs/api-call", "type": "module" },
|
|
757
757
|
{ "name": "process", "node": "my-node", "type": "module", "set_var": true },
|
|
758
758
|
{ "name": "go-step", "node": "chain-test", "type": "runtime.go" }
|
|
759
759
|
],
|
|
@@ -903,7 +903,7 @@ When users have data flow issues, check these three things first.
|
|
|
903
903
|
Always use \\\`defineNode()\\\`. Never class-based BlokService.
|
|
904
904
|
|
|
905
905
|
\\\`\\\`\\\`typescript
|
|
906
|
-
import { defineNode } from "@
|
|
906
|
+
import { defineNode } from "@blokjs/runner";
|
|
907
907
|
import { z } from "zod";
|
|
908
908
|
|
|
909
909
|
export default defineNode({
|
|
@@ -939,7 +939,7 @@ export default defineNode({
|
|
|
939
939
|
- Do NOT skip Zod schemas when creating nodes
|
|
940
940
|
- Do NOT edit files in \\\`.blok/runtimes/\\\`
|
|
941
941
|
`;
|
|
942
|
-
const function_first_node_file = `import { defineNode } from "@
|
|
942
|
+
const function_first_node_file = `import { defineNode } from "@blokjs/runner";
|
|
943
943
|
import { z } from "zod";
|
|
944
944
|
|
|
945
945
|
/**
|
|
@@ -369,7 +369,7 @@ describe("GenerationAnalytics", () => {
|
|
|
369
369
|
success: false,
|
|
370
370
|
attempts: 3,
|
|
371
371
|
durationMs: 5000,
|
|
372
|
-
errors: ['TS2304: Cannot find name "defineNode"', "TS2307: Cannot find module '@
|
|
372
|
+
errors: ['TS2304: Cannot find name "defineNode"', "TS2307: Cannot find module '@blokjs/runner'"],
|
|
373
373
|
promptVersion: "v1",
|
|
374
374
|
});
|
|
375
375
|
analytics.recordEvent({
|
|
@@ -116,9 +116,9 @@ export default class NodeGenerator {
|
|
|
116
116
|
"",
|
|
117
117
|
"Please fix ALL the errors listed above and regenerate the complete code.",
|
|
118
118
|
"Make sure to:",
|
|
119
|
-
"- Import defineNode from '@
|
|
119
|
+
"- Import defineNode from '@blokjs/runner'",
|
|
120
120
|
"- Import z from 'zod'",
|
|
121
|
-
"- Import Context type from '@
|
|
121
|
+
"- Import Context type from '@blokjs/shared'",
|
|
122
122
|
"- Use z.object({...}) for input and output schemas",
|
|
123
123
|
"- Make the execute function async",
|
|
124
124
|
"- Export as default: export default defineNode({...})",
|
|
@@ -129,13 +129,13 @@ export default class NodeGenerator {
|
|
|
129
129
|
getSemanticGuidance(error) {
|
|
130
130
|
const errorLower = error.toLowerCase();
|
|
131
131
|
if (errorLower.includes("missing") && errorLower.includes("definenode")) {
|
|
132
|
-
return "Add: import { defineNode } from '@
|
|
132
|
+
return "Add: import { defineNode } from '@blokjs/runner';";
|
|
133
133
|
}
|
|
134
134
|
if (errorLower.includes("missing") && errorLower.includes("zod")) {
|
|
135
135
|
return "Add: import { z } from 'zod';";
|
|
136
136
|
}
|
|
137
137
|
if (errorLower.includes("cannot find") && errorLower.includes("definenode")) {
|
|
138
|
-
return "Ensure defineNode is imported from '@
|
|
138
|
+
return "Ensure defineNode is imported from '@blokjs/runner'";
|
|
139
139
|
}
|
|
140
140
|
if (errorLower.includes("z.object") || errorLower.includes("zod schema")) {
|
|
141
141
|
return "Use z.object({...}) for both input and output schemas with proper Zod types";
|
|
@@ -159,7 +159,7 @@ export default class NodeGenerator {
|
|
|
159
159
|
return "Use ctx.request.body, ctx.request.query, ctx.request.params for HTTP data; ctx.vars for cross-node data";
|
|
160
160
|
}
|
|
161
161
|
if (errorLower.includes("cannot find module") || errorLower.includes("module not found")) {
|
|
162
|
-
return "Check import paths. Use '@
|
|
162
|
+
return "Check import paths. Use '@blokjs/runner' for defineNode and '@blokjs/shared' for Context/GlobalError";
|
|
163
163
|
}
|
|
164
164
|
if (errorLower.includes("property") && errorLower.includes("does not exist")) {
|
|
165
165
|
return "Verify property names match your Zod schemas. Use z.infer<typeof schema> for type inference.";
|
|
@@ -8,7 +8,7 @@ describe("NodeGenerator", () => {
|
|
|
8
8
|
const guidance = getGuidance("Missing defineNode import");
|
|
9
9
|
expect(guidance).not.toBeNull();
|
|
10
10
|
expect(guidance).toContain("defineNode");
|
|
11
|
-
expect(guidance).toContain("@
|
|
11
|
+
expect(guidance).toContain("@blokjs/runner");
|
|
12
12
|
});
|
|
13
13
|
it("should provide guidance for missing Zod import", () => {
|
|
14
14
|
const guidance = getGuidance("Missing zod import");
|
|
@@ -56,7 +56,7 @@ describe("NodeGenerator", () => {
|
|
|
56
56
|
expect(guidance).toContain("plain object");
|
|
57
57
|
});
|
|
58
58
|
it("should provide guidance for module not found", () => {
|
|
59
|
-
const guidance = getGuidance("Cannot find module '@
|
|
59
|
+
const guidance = getGuidance("Cannot find module '@blokjs/core'");
|
|
60
60
|
expect(guidance).not.toBeNull();
|
|
61
61
|
expect(guidance).toContain("import paths");
|
|
62
62
|
});
|
|
@@ -90,8 +90,8 @@ export default class TriggerGenerator {
|
|
|
90
90
|
if (!code.includes("extends TriggerBase") && !code.includes("extends") && !code.includes("TriggerBase")) {
|
|
91
91
|
errors.push("Trigger must extend TriggerBase");
|
|
92
92
|
}
|
|
93
|
-
if (!code.includes("TriggerBase") && !code.includes("@
|
|
94
|
-
errors.push("Missing TriggerBase import from @
|
|
93
|
+
if (!code.includes("TriggerBase") && !code.includes("@blokjs/runner")) {
|
|
94
|
+
errors.push("Missing TriggerBase import from @blokjs/runner");
|
|
95
95
|
}
|
|
96
96
|
if (!code.includes("loadNodes")) {
|
|
97
97
|
errors.push("Missing loadNodes() method");
|
|
@@ -179,7 +179,7 @@ export default class TriggerGenerator {
|
|
|
179
179
|
"",
|
|
180
180
|
"Please fix ALL the errors listed above and regenerate the complete trigger code.",
|
|
181
181
|
"Make sure to:",
|
|
182
|
-
"- Extend TriggerBase from @
|
|
182
|
+
"- Extend TriggerBase from @blokjs/runner",
|
|
183
183
|
"- Include loadNodes() and loadWorkflows() methods",
|
|
184
184
|
"- Use this.createContext() to create Context objects",
|
|
185
185
|
"- Call super() in the constructor",
|
|
@@ -192,7 +192,7 @@ export default class TriggerGenerator {
|
|
|
192
192
|
getSemanticGuidance(error) {
|
|
193
193
|
const errorLower = error.toLowerCase();
|
|
194
194
|
if (errorLower.includes("triggerbase") && (errorLower.includes("extend") || errorLower.includes("missing"))) {
|
|
195
|
-
return "import { TriggerBase } from '@
|
|
195
|
+
return "import { TriggerBase } from '@blokjs/runner'; class MyTrigger extends TriggerBase { ... }";
|
|
196
196
|
}
|
|
197
197
|
if (errorLower.includes("loadnodes") && errorLower.includes("missing")) {
|
|
198
198
|
return "Add: private loadNodes(): void { this.nodeMap.nodes = new NodeMap(); ... }";
|
|
@@ -210,7 +210,7 @@ export default class TriggerGenerator {
|
|
|
210
210
|
return "Set ctx.request = { body: messageData, headers: {}, query: {}, params: {} } before executing workflow";
|
|
211
211
|
}
|
|
212
212
|
if (errorLower.includes("cannot find module") || errorLower.includes("module not found")) {
|
|
213
|
-
return "Use '@
|
|
213
|
+
return "Use '@blokjs/runner' for TriggerBase, Runner, NodeMap and '@blokjs/shared' for Context, DefaultLogger";
|
|
214
214
|
}
|
|
215
215
|
if (errorLower.includes("export") && errorLower.includes("default")) {
|
|
216
216
|
return "Use: export default class <Name>Trigger extends TriggerBase { ... }";
|
|
@@ -6,8 +6,8 @@ describe("TriggerGenerator", () => {
|
|
|
6
6
|
const validate = (code) => generator.validateTriggerStructure(code);
|
|
7
7
|
it("should pass for valid trigger code", () => {
|
|
8
8
|
const validCode = `
|
|
9
|
-
import TriggerBase from "@
|
|
10
|
-
import { NodeMap } from "@
|
|
9
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
10
|
+
import { NodeMap } from "@blokjs/runner";
|
|
11
11
|
|
|
12
12
|
export default class MyTrigger extends TriggerBase {
|
|
13
13
|
constructor() {
|
|
@@ -56,7 +56,7 @@ export default class MyTrigger {
|
|
|
56
56
|
});
|
|
57
57
|
it("should fail for trigger missing loadNodes", () => {
|
|
58
58
|
const code = `
|
|
59
|
-
import TriggerBase from "@
|
|
59
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
60
60
|
|
|
61
61
|
export default class MyTrigger extends TriggerBase {
|
|
62
62
|
constructor() {
|
|
@@ -77,7 +77,7 @@ export default class MyTrigger extends TriggerBase {
|
|
|
77
77
|
});
|
|
78
78
|
it("should fail for trigger missing loadWorkflows", () => {
|
|
79
79
|
const code = `
|
|
80
|
-
import TriggerBase from "@
|
|
80
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
81
81
|
|
|
82
82
|
export default class MyTrigger extends TriggerBase {
|
|
83
83
|
constructor() {
|
|
@@ -98,7 +98,7 @@ export default class MyTrigger extends TriggerBase {
|
|
|
98
98
|
});
|
|
99
99
|
it("should fail for trigger missing createContext", () => {
|
|
100
100
|
const code = `
|
|
101
|
-
import TriggerBase from "@
|
|
101
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
102
102
|
|
|
103
103
|
export default class MyTrigger extends TriggerBase {
|
|
104
104
|
constructor() {
|
|
@@ -121,7 +121,7 @@ export default class MyTrigger extends TriggerBase {
|
|
|
121
121
|
});
|
|
122
122
|
it("should fail for constructor without super()", () => {
|
|
123
123
|
const code = `
|
|
124
|
-
import TriggerBase from "@
|
|
124
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
125
125
|
|
|
126
126
|
export default class MyTrigger extends TriggerBase {
|
|
127
127
|
constructor() {
|
|
@@ -143,7 +143,7 @@ export default class MyTrigger extends TriggerBase {
|
|
|
143
143
|
});
|
|
144
144
|
it("should warn when request data is not populated on context", () => {
|
|
145
145
|
const code = `
|
|
146
|
-
import TriggerBase from "@
|
|
146
|
+
import TriggerBase from "@blokjs/runner/TriggerBase";
|
|
147
147
|
|
|
148
148
|
export default class MyTrigger extends TriggerBase {
|
|
149
149
|
constructor() {
|
|
@@ -19,9 +19,9 @@ const mockedGenerateText = vi.mocked(generateText);
|
|
|
19
19
|
const mockedValidateCode = vi.mocked(CompilationValidator.validateCode);
|
|
20
20
|
const mockedValidateStructure = vi.mocked(NodeValidator.validateFunctionFirstStructure);
|
|
21
21
|
const VALID_FUNCTION_FIRST_NODE = `
|
|
22
|
-
import type { Context } from "@
|
|
22
|
+
import type { Context } from "@blokjs/shared";
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { defineNode } from "@
|
|
24
|
+
import { defineNode } from "@blokjs/runner";
|
|
25
25
|
|
|
26
26
|
export default defineNode({
|
|
27
27
|
name: "fetch-user",
|
|
@@ -43,8 +43,8 @@ export default defineNode({
|
|
|
43
43
|
});
|
|
44
44
|
`;
|
|
45
45
|
const VALID_CLASS_BASED_NODE = `
|
|
46
|
-
import BlokService, { BlokResponse, GlobalError } from "@
|
|
47
|
-
import type { Context } from "@
|
|
46
|
+
import BlokService, { BlokResponse, GlobalError } from "@blokjs/runner";
|
|
47
|
+
import type { Context } from "@blokjs/shared";
|
|
48
48
|
|
|
49
49
|
type InputType = { message: string; };
|
|
50
50
|
|
|
@@ -179,7 +179,7 @@ describe("NodeGenerator E2E", () => {
|
|
|
179
179
|
mockedValidateCode.mockReturnValue({ success: true, errors: [], warnings: [] });
|
|
180
180
|
mockedValidateStructure.mockReturnValue({
|
|
181
181
|
valid: false,
|
|
182
|
-
errors: ["Missing defineNode import from @
|
|
182
|
+
errors: ["Missing defineNode import from @blokjs/runner"],
|
|
183
183
|
warnings: [],
|
|
184
184
|
suggestions: [],
|
|
185
185
|
});
|
|
@@ -14,8 +14,8 @@ import * as CompilationValidator from "../validators/CompilationValidator.js";
|
|
|
14
14
|
const mockedGenerateText = vi.mocked(generateText);
|
|
15
15
|
const mockedValidateCode = vi.mocked(CompilationValidator.validateCode);
|
|
16
16
|
const VALID_QUEUE_TRIGGER = `
|
|
17
|
-
import { TriggerBase, type GlobalOptions, NodeMap, Runner } from "@
|
|
18
|
-
import { type Context, DefaultLogger } from "@
|
|
17
|
+
import { TriggerBase, type GlobalOptions, NodeMap, Runner } from "@blokjs/runner";
|
|
18
|
+
import { type Context, DefaultLogger } from "@blokjs/shared";
|
|
19
19
|
|
|
20
20
|
export default class KafkaQueueTrigger extends TriggerBase {
|
|
21
21
|
private nodeMap: GlobalOptions = <GlobalOptions>{};
|
|
@@ -41,7 +41,7 @@ export default class KafkaQueueTrigger extends TriggerBase {
|
|
|
41
41
|
}
|
|
42
42
|
`;
|
|
43
43
|
const VALID_CRON_TRIGGER = `
|
|
44
|
-
import { TriggerBase, type GlobalOptions, NodeMap } from "@
|
|
44
|
+
import { TriggerBase, type GlobalOptions, NodeMap } from "@blokjs/runner";
|
|
45
45
|
|
|
46
46
|
export default class DailyCronTrigger extends TriggerBase {
|
|
47
47
|
private nodeMap: GlobalOptions = <GlobalOptions>{};
|
|
@@ -62,7 +62,7 @@ export default class DailyCronTrigger extends TriggerBase {
|
|
|
62
62
|
}
|
|
63
63
|
`;
|
|
64
64
|
const VALID_WEBHOOK_TRIGGER = `
|
|
65
|
-
import { TriggerBase, type GlobalOptions, NodeMap } from "@
|
|
65
|
+
import { TriggerBase, type GlobalOptions, NodeMap } from "@blokjs/runner";
|
|
66
66
|
|
|
67
67
|
export default class GitHubWebhookTrigger extends TriggerBase {
|
|
68
68
|
private nodeMap: GlobalOptions = <GlobalOptions>{};
|
|
@@ -98,7 +98,7 @@ export default class BrokenTrigger {
|
|
|
98
98
|
}
|
|
99
99
|
`;
|
|
100
100
|
const INVALID_TRIGGER_NO_METHODS = `
|
|
101
|
-
import { TriggerBase } from "@
|
|
101
|
+
import { TriggerBase } from "@blokjs/runner";
|
|
102
102
|
|
|
103
103
|
export default class MinimalTrigger extends TriggerBase {
|
|
104
104
|
constructor() {
|
|
@@ -112,7 +112,7 @@ export default class MinimalTrigger extends TriggerBase {
|
|
|
112
112
|
}
|
|
113
113
|
`;
|
|
114
114
|
const INVALID_TRIGGER_NO_CONTEXT = `
|
|
115
|
-
import { TriggerBase } from "@
|
|
115
|
+
import { TriggerBase } from "@blokjs/runner";
|
|
116
116
|
|
|
117
117
|
export default class NoContextTrigger extends TriggerBase {
|
|
118
118
|
constructor() {
|
|
@@ -22,7 +22,7 @@ const VALID_HTTP_WORKFLOW = JSON.stringify({
|
|
|
22
22
|
steps: [
|
|
23
23
|
{
|
|
24
24
|
name: "fetch-user",
|
|
25
|
-
node: "@
|
|
25
|
+
node: "@blokjs/api-call",
|
|
26
26
|
type: "module",
|
|
27
27
|
},
|
|
28
28
|
],
|
|
@@ -314,7 +314,7 @@ describe("WorkflowGenerator E2E", () => {
|
|
|
314
314
|
steps: [
|
|
315
315
|
{
|
|
316
316
|
name: "route-request",
|
|
317
|
-
node: "@
|
|
317
|
+
node: "@blokjs/if-else",
|
|
318
318
|
type: "module",
|
|
319
319
|
},
|
|
320
320
|
],
|
|
@@ -8,8 +8,8 @@ What to return:
|
|
|
8
8
|
|
|
9
9
|
1. Proper imports:
|
|
10
10
|
* \`z\` from \`zod\`
|
|
11
|
-
* \`Context\` from \`@
|
|
12
|
-
* \`defineNode\` from \`@
|
|
11
|
+
* \`Context\` from \`@blokjs/shared\`
|
|
12
|
+
* \`defineNode\` from \`@blokjs/runner\`
|
|
13
13
|
2. A clear and structured \`input\` schema using Zod (z.object with proper types).
|
|
14
14
|
3. A matching \`output\` schema using Zod.
|
|
15
15
|
4. A single exported node instance created via \`defineNode\` with:
|
|
@@ -50,9 +50,9 @@ Real-World Examples to Guide You:
|
|
|
50
50
|
**Example 1: API Call Node**
|
|
51
51
|
|
|
52
52
|
\`\`\`typescript
|
|
53
|
-
import type { Context } from "@
|
|
53
|
+
import type { Context } from "@blokjs/shared";
|
|
54
54
|
import { z } from "zod";
|
|
55
|
-
import { defineNode } from "@
|
|
55
|
+
import { defineNode } from "@blokjs/runner";
|
|
56
56
|
|
|
57
57
|
export default defineNode({
|
|
58
58
|
name: "api-call",
|
|
@@ -120,9 +120,9 @@ export default defineNode({
|
|
|
120
120
|
**Example 2: Fetch User Node**
|
|
121
121
|
|
|
122
122
|
\`\`\`typescript
|
|
123
|
-
import type { Context } from "@
|
|
123
|
+
import type { Context } from "@blokjs/shared";
|
|
124
124
|
import { z } from "zod";
|
|
125
|
-
import { defineNode } from "@
|
|
125
|
+
import { defineNode } from "@blokjs/runner";
|
|
126
126
|
|
|
127
127
|
export default defineNode({
|
|
128
128
|
name: "fetch-user",
|
|
@@ -174,9 +174,9 @@ async function fetchUserFromDatabase(userId: string, includeMetadata: boolean) {
|
|
|
174
174
|
|
|
175
175
|
Template to follow (adapt and fill based on the user's request):
|
|
176
176
|
|
|
177
|
-
import type { Context } from "@
|
|
177
|
+
import type { Context } from "@blokjs/shared";
|
|
178
178
|
import { z } from "zod";
|
|
179
|
-
import { defineNode } from "@
|
|
179
|
+
import { defineNode } from "@blokjs/runner";
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
182
|
* [Brief description of what this node does]
|
|
@@ -31,8 +31,8 @@ Format:
|
|
|
31
31
|
* Return the entire code, from imports to the end of the class, as it would appear in a \`.ts\` file.
|
|
32
32
|
|
|
33
33
|
Node class template:
|
|
34
|
-
import { type IBlokResponse, BlokService, BlokResponse } from "@
|
|
35
|
-
import { type Context, GlobalError } from "@
|
|
34
|
+
import { type IBlokResponse, BlokService, BlokResponse } from "@blokjs/runner";
|
|
35
|
+
import { type Context, GlobalError } from "@blokjs/shared";
|
|
36
36
|
|
|
37
37
|
type InputType = {
|
|
38
38
|
message?: string;
|
|
@@ -6,7 +6,7 @@ What to return:
|
|
|
6
6
|
* Return only a complete TypeScript file containing a trigger class, ready to be saved directly into \`triggers/<trigger-name>/src/<TriggerName>Trigger.ts\`.
|
|
7
7
|
* It must include:
|
|
8
8
|
|
|
9
|
-
1. Proper imports from \`@
|
|
9
|
+
1. Proper imports from \`@blokjs/runner\` and \`@blokjs/shared\`
|
|
10
10
|
2. A trigger class that extends \`TriggerBase\`
|
|
11
11
|
3. \`loadNodes()\` and \`loadWorkflows()\` methods
|
|
12
12
|
4. A main start method (e.g., \`listen()\`, \`startConsumer()\`, \`start()\`)
|
|
@@ -18,7 +18,7 @@ What to return:
|
|
|
18
18
|
|
|
19
19
|
All triggers MUST follow this pattern:
|
|
20
20
|
|
|
21
|
-
1. **Extend TriggerBase** from \`@
|
|
21
|
+
1. **Extend TriggerBase** from \`@blokjs/runner\`
|
|
22
22
|
2. **Load nodes and workflows** in constructor
|
|
23
23
|
3. **Listen for external events** (HTTP, queue messages, cron, webhooks, etc.)
|
|
24
24
|
4. **For each event:**
|
|
@@ -166,8 +166,8 @@ class SSETrigger extends TriggerBase {
|
|
|
166
166
|
|
|
167
167
|
\`\`\`typescript
|
|
168
168
|
import { trace } from "@opentelemetry/api";
|
|
169
|
-
import { TriggerBase, type GlobalOptions, NodeMap, Runner } from "@
|
|
170
|
-
import { type Context, DefaultLogger } from "@
|
|
169
|
+
import { TriggerBase, type GlobalOptions, NodeMap, Runner } from "@blokjs/runner";
|
|
170
|
+
import { type Context, DefaultLogger } from "@blokjs/shared";
|
|
171
171
|
import nodes from "../Nodes.js";
|
|
172
172
|
import workflows from "../workflows/index.js";
|
|
173
173
|
|
|
@@ -126,14 +126,14 @@ Steps are an ordered array of step objects:
|
|
|
126
126
|
"steps": [
|
|
127
127
|
{
|
|
128
128
|
"name": "step-key-name",
|
|
129
|
-
"node": "@
|
|
129
|
+
"node": "@blokjs/api-call",
|
|
130
130
|
"type": "module"
|
|
131
131
|
}
|
|
132
132
|
]
|
|
133
133
|
\`\`\`
|
|
134
134
|
|
|
135
135
|
- \`name\`: Unique identifier for this step (used as key in \`nodes\` map)
|
|
136
|
-
- \`node\`: Node package/module name (e.g., "@
|
|
136
|
+
- \`node\`: Node package/module name (e.g., "@blokjs/api-call" for module types, or custom node names for local types)
|
|
137
137
|
- \`type\`: "module" (from node_modules), "local" (from src/nodes/), or "runtime.python3" (Python runtime)
|
|
138
138
|
|
|
139
139
|
## Nodes Configuration
|
|
@@ -226,9 +226,9 @@ Node inputs support these patterns:
|
|
|
226
226
|
|
|
227
227
|
## Available Built-in Nodes
|
|
228
228
|
|
|
229
|
-
- \`@
|
|
230
|
-
- \`@
|
|
231
|
-
- \`@
|
|
229
|
+
- \`@blokjs/api-call\`: Makes HTTP API calls (inputs: url, method, headers, body, responseType)
|
|
230
|
+
- \`@blokjs/if-else\`: Conditional routing (uses conditions array instead of inputs)
|
|
231
|
+
- \`@blokjs/react\`: Server-side React rendering (inputs: template, props)
|
|
232
232
|
- \`error\`: Returns error response (inputs: message, code)
|
|
233
233
|
|
|
234
234
|
## Constraints
|
|
@@ -261,7 +261,7 @@ Node inputs support these patterns:
|
|
|
261
261
|
"steps": [
|
|
262
262
|
{
|
|
263
263
|
"name": "get-countries",
|
|
264
|
-
"node": "@
|
|
264
|
+
"node": "@blokjs/api-call",
|
|
265
265
|
"type": "module"
|
|
266
266
|
}
|
|
267
267
|
],
|
|
@@ -294,7 +294,7 @@ Node inputs support these patterns:
|
|
|
294
294
|
"steps": [
|
|
295
295
|
{
|
|
296
296
|
"name": "filter-request",
|
|
297
|
-
"node": "@
|
|
297
|
+
"node": "@blokjs/if-else",
|
|
298
298
|
"type": "module"
|
|
299
299
|
}
|
|
300
300
|
],
|
|
@@ -374,7 +374,7 @@ Node inputs support these patterns:
|
|
|
374
374
|
},
|
|
375
375
|
{
|
|
376
376
|
"name": "notify-user",
|
|
377
|
-
"node": "@
|
|
377
|
+
"node": "@blokjs/api-call",
|
|
378
378
|
"type": "module"
|
|
379
379
|
}
|
|
380
380
|
],
|
|
@@ -413,7 +413,7 @@ Node inputs support these patterns:
|
|
|
413
413
|
"steps": [
|
|
414
414
|
{
|
|
415
415
|
"name": "fetch-metrics",
|
|
416
|
-
"node": "@
|
|
416
|
+
"node": "@blokjs/api-call",
|
|
417
417
|
"type": "module"
|
|
418
418
|
},
|
|
419
419
|
{
|
|
@@ -3,14 +3,14 @@ const registerNodeSystemPrompt = {
|
|
|
3
3
|
|
|
4
4
|
You will receive:
|
|
5
5
|
- The current full content of the TypeScript file.
|
|
6
|
-
- The import path of the new node (e.g., "@
|
|
6
|
+
- The import path of the new node (e.g., "@blokjs/my-new-node" or "./nodes/remove-properties").
|
|
7
7
|
- The class name of the new node (e.g., "RemovePropertiesFromArray").
|
|
8
8
|
- The string **registry key** to register it under (e.g., "remove-properties").
|
|
9
9
|
|
|
10
10
|
Your task:
|
|
11
11
|
|
|
12
12
|
1. Add an \`import\` statement for the new node in the correct location, maintaining **alphabetical order** among existing regular imports.
|
|
13
|
-
2. The line \`import type { NodeBase } from "@
|
|
13
|
+
2. The line \`import type { NodeBase } from "@blokjs/shared";\` must remain in place and not be reordered.
|
|
14
14
|
3. Add a new entry to the \`nodes\` object using the provided registry key only. Example:
|
|
15
15
|
"remove-properties": new RemovePropertiesFromArray(),
|
|
16
16
|
4. **Do not modify any existing imports or registry entries.** Their keys must remain exactly as they appear.
|
|
@@ -4,7 +4,7 @@ describe("CompilationValidator", () => {
|
|
|
4
4
|
describe("validateCode", () => {
|
|
5
5
|
it("should pass for valid function-first node", () => {
|
|
6
6
|
const validCode = `
|
|
7
|
-
import { defineNode } from "@
|
|
7
|
+
import { defineNode } from "@blokjs/runner";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
export default defineNode({
|
|
@@ -58,7 +58,7 @@ export default defineNode({
|
|
|
58
58
|
});
|
|
59
59
|
it("should pass for code with type errors (type checking limitations)", () => {
|
|
60
60
|
const invalidCode = `
|
|
61
|
-
import { defineNode } from "@
|
|
61
|
+
import { defineNode } from "@blokjs/runner";
|
|
62
62
|
import { z } from "zod";
|
|
63
63
|
|
|
64
64
|
export default defineNode({
|
|
@@ -86,7 +86,7 @@ export default defineNode({
|
|
|
86
86
|
});
|
|
87
87
|
it("should document syntax validation limitations", () => {
|
|
88
88
|
const invalidCode = `
|
|
89
|
-
import { defineNode } from "@
|
|
89
|
+
import { defineNode } from "@blokjs/runner";
|
|
90
90
|
import { z } from "zod";
|
|
91
91
|
|
|
92
92
|
export default defineNode({
|
|
@@ -110,7 +110,7 @@ export default defineNode({
|
|
|
110
110
|
});
|
|
111
111
|
it("should pass for code with proper async/await usage", () => {
|
|
112
112
|
const validCode = `
|
|
113
|
-
import { defineNode } from "@
|
|
113
|
+
import { defineNode } from "@blokjs/runner";
|
|
114
114
|
import { z } from "zod";
|
|
115
115
|
|
|
116
116
|
export default defineNode({
|
|
@@ -139,7 +139,7 @@ export default defineNode({
|
|
|
139
139
|
describe("validateFile", () => {
|
|
140
140
|
it("should validate code using file path for context", () => {
|
|
141
141
|
const validCode = `
|
|
142
|
-
import { defineNode } from "@
|
|
142
|
+
import { defineNode } from "@blokjs/runner";
|
|
143
143
|
import { z } from "zod";
|
|
144
144
|
|
|
145
145
|
export default defineNode({
|
|
@@ -92,7 +92,7 @@ export function validateFunctionFirstStructure(context) {
|
|
|
92
92
|
const content = context.content;
|
|
93
93
|
if (!content.includes("import") || !content.includes("defineNode")) {
|
|
94
94
|
result.valid = false;
|
|
95
|
-
result.errors.push("Missing 'defineNode' import from '@
|
|
95
|
+
result.errors.push("Missing 'defineNode' import from '@blokjs/runner'");
|
|
96
96
|
}
|
|
97
97
|
if (!content.includes("import") || !content.includes("zod")) {
|
|
98
98
|
result.valid = false;
|
|
@@ -133,7 +133,7 @@ export function validateClassBasedStructure(context) {
|
|
|
133
133
|
const content = context.content;
|
|
134
134
|
if (!content.includes("BlokService")) {
|
|
135
135
|
result.valid = false;
|
|
136
|
-
result.errors.push("Missing 'BlokService' import from '@
|
|
136
|
+
result.errors.push("Missing 'BlokService' import from '@blokjs/runner'");
|
|
137
137
|
}
|
|
138
138
|
if (!content.includes("class ") || !content.includes("extends BlokService")) {
|
|
139
139
|
result.valid = false;
|
|
@@ -4,7 +4,7 @@ describe("NodeValidator", () => {
|
|
|
4
4
|
describe("validateFunctionFirstStructure", () => {
|
|
5
5
|
it("should pass for valid function-first node", () => {
|
|
6
6
|
const validCode = `
|
|
7
|
-
import { defineNode } from "@
|
|
7
|
+
import { defineNode } from "@blokjs/runner";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
export default defineNode({
|
|
@@ -33,7 +33,7 @@ export default defineNode({
|
|
|
33
33
|
});
|
|
34
34
|
it("should fail for class-based node (old pattern)", () => {
|
|
35
35
|
const classBasedCode = `
|
|
36
|
-
import { BlokService } from "@
|
|
36
|
+
import { BlokService } from "@blokjs/runner";
|
|
37
37
|
|
|
38
38
|
export default class TestNode extends BlokService {
|
|
39
39
|
async handle(ctx: any, input: any) {
|
|
@@ -53,7 +53,7 @@ export default class TestNode extends BlokService {
|
|
|
53
53
|
});
|
|
54
54
|
it("should fail for node missing execute function", () => {
|
|
55
55
|
const incompleteCode = `
|
|
56
|
-
import { defineNode } from "@
|
|
56
|
+
import { defineNode } from "@blokjs/runner";
|
|
57
57
|
import { z } from "zod";
|
|
58
58
|
|
|
59
59
|
export default defineNode({
|
|
@@ -76,7 +76,7 @@ export default defineNode({
|
|
|
76
76
|
});
|
|
77
77
|
it("should fail for node missing name property", () => {
|
|
78
78
|
const invalidCode = `
|
|
79
|
-
import { defineNode } from "@
|
|
79
|
+
import { defineNode } from "@blokjs/runner";
|
|
80
80
|
import { z } from "zod";
|
|
81
81
|
|
|
82
82
|
export default defineNode({
|
|
@@ -102,7 +102,7 @@ export default defineNode({
|
|
|
102
102
|
});
|
|
103
103
|
it("should fail for node missing description property", () => {
|
|
104
104
|
const invalidCode = `
|
|
105
|
-
import { defineNode } from "@
|
|
105
|
+
import { defineNode } from "@blokjs/runner";
|
|
106
106
|
import { z } from "zod";
|
|
107
107
|
|
|
108
108
|
export default defineNode({
|
|
@@ -128,7 +128,7 @@ export default defineNode({
|
|
|
128
128
|
});
|
|
129
129
|
it("should fail for node missing input schema", () => {
|
|
130
130
|
const invalidCode = `
|
|
131
|
-
import { defineNode } from "@
|
|
131
|
+
import { defineNode } from "@blokjs/runner";
|
|
132
132
|
import { z } from "zod";
|
|
133
133
|
|
|
134
134
|
export default defineNode({
|
|
@@ -154,7 +154,7 @@ export default defineNode({
|
|
|
154
154
|
});
|
|
155
155
|
it("should fail for node missing output schema", () => {
|
|
156
156
|
const invalidCode = `
|
|
157
|
-
import { defineNode } from "@
|
|
157
|
+
import { defineNode } from "@blokjs/runner";
|
|
158
158
|
import { z } from "zod";
|
|
159
159
|
|
|
160
160
|
export default defineNode({
|
|
@@ -180,7 +180,7 @@ export default defineNode({
|
|
|
180
180
|
});
|
|
181
181
|
it("should pass for node with complex input/output schemas", () => {
|
|
182
182
|
const validCode = `
|
|
183
|
-
import { defineNode } from "@
|
|
183
|
+
import { defineNode } from "@blokjs/runner";
|
|
184
184
|
import { z } from "zod";
|
|
185
185
|
|
|
186
186
|
export default defineNode({
|
|
@@ -228,7 +228,7 @@ export default defineNode({
|
|
|
228
228
|
describe("validateExports", () => {
|
|
229
229
|
it("should pass for valid default export", () => {
|
|
230
230
|
const validCode = `
|
|
231
|
-
import { defineNode } from "@
|
|
231
|
+
import { defineNode } from "@blokjs/runner";
|
|
232
232
|
import { z } from "zod";
|
|
233
233
|
|
|
234
234
|
export default defineNode({
|
|
@@ -251,7 +251,7 @@ export default defineNode({
|
|
|
251
251
|
});
|
|
252
252
|
it("should fail for missing default export", () => {
|
|
253
253
|
const invalidCode = `
|
|
254
|
-
import { defineNode } from "@
|
|
254
|
+
import { defineNode } from "@blokjs/runner";
|
|
255
255
|
import { z } from "zod";
|
|
256
256
|
|
|
257
257
|
const myNode = defineNode({
|
|
@@ -388,7 +388,7 @@ describe("WorkflowValidator", () => {
|
|
|
388
388
|
description: "test",
|
|
389
389
|
version: "1.0.0",
|
|
390
390
|
trigger: { http: { method: "*", path: "/:action?" } },
|
|
391
|
-
steps: [{ name: "router", node: "@
|
|
391
|
+
steps: [{ name: "router", node: "@blokjs/if-else", type: "module" }],
|
|
392
392
|
nodes: {
|
|
393
393
|
router: {
|
|
394
394
|
conditions: [
|
|
@@ -545,7 +545,7 @@ describe("WorkflowValidator", () => {
|
|
|
545
545
|
trigger: {
|
|
546
546
|
http: { method: "GET", path: "/", accept: "application/json" },
|
|
547
547
|
},
|
|
548
|
-
steps: [{ name: "get-countries-api", node: "@
|
|
548
|
+
steps: [{ name: "get-countries-api", node: "@blokjs/api-call", type: "module" }],
|
|
549
549
|
nodes: {
|
|
550
550
|
"get-countries-api": {
|
|
551
551
|
inputs: {
|
|
@@ -569,7 +569,7 @@ describe("WorkflowValidator", () => {
|
|
|
569
569
|
trigger: {
|
|
570
570
|
http: { method: "*", path: "/:function?/:id?", accept: "application/json" },
|
|
571
571
|
},
|
|
572
|
-
steps: [{ name: "filter-request", node: "@
|
|
572
|
+
steps: [{ name: "filter-request", node: "@blokjs/if-else", type: "module" }],
|
|
573
573
|
nodes: {
|
|
574
574
|
"filter-request": {
|
|
575
575
|
conditions: [
|
|
@@ -633,7 +633,7 @@ describe("WorkflowValidator", () => {
|
|
|
633
633
|
trigger: {
|
|
634
634
|
cron: { schedule: "0 8 * * *", timezone: "America/New_York", overlap: false },
|
|
635
635
|
},
|
|
636
|
-
steps: [{ name: "fetch-metrics", node: "@
|
|
636
|
+
steps: [{ name: "fetch-metrics", node: "@blokjs/api-call", type: "module" }],
|
|
637
637
|
nodes: {
|
|
638
638
|
"fetch-metrics": {
|
|
639
639
|
inputs: { url: "${ctx.env.METRICS_API_URL}", method: "GET" },
|
|
@@ -3,7 +3,7 @@ import * as p from "@clack/prompts";
|
|
|
3
3
|
import { program, trackCommandExecution } from "../../services/commander.js";
|
|
4
4
|
import { loadWorkflows } from "../../services/workflow-loader.js";
|
|
5
5
|
async function getNodeDependencyGraph() {
|
|
6
|
-
const { NodeDependencyGraph } = await import("@
|
|
6
|
+
const { NodeDependencyGraph } = await import("@blokjs/runner");
|
|
7
7
|
return NodeDependencyGraph;
|
|
8
8
|
}
|
|
9
9
|
program
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CatalogStats, RuntimeKind, RuntimePackageManifest } from "@
|
|
1
|
+
import type { CatalogStats, RuntimeKind, RuntimePackageManifest } from "@blokjs/runner";
|
|
2
2
|
import { Command } from "../../services/commander.js";
|
|
3
3
|
export interface MarketplaceConfig {
|
|
4
4
|
registryUrl: string;
|
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import * as p from "@clack/prompts";
|
|
3
3
|
import { program, trackCommandExecution } from "../../services/commander.js";
|
|
4
4
|
async function getPerformanceProfiler() {
|
|
5
|
-
const { PerformanceProfiler } = await import("@
|
|
5
|
+
const { PerformanceProfiler } = await import("@blokjs/runner");
|
|
6
6
|
return PerformanceProfiler;
|
|
7
7
|
}
|
|
8
8
|
async function queryPrometheus(query, host, token) {
|
|
@@ -61,7 +61,7 @@ export async function startStudio(options) {
|
|
|
61
61
|
p.intro(color.bgCyan(color.black(" Blok Studio ")));
|
|
62
62
|
const staticPath = resolveStaticPath();
|
|
63
63
|
if (!staticPath) {
|
|
64
|
-
p.log.error(`Studio assets not found.\n` + ` Build them first: ${color.cyan("pnpm --filter @
|
|
64
|
+
p.log.error(`Studio assets not found.\n` + ` Build them first: ${color.cyan("pnpm --filter @blokjs/studio build")}`);
|
|
65
65
|
process.exit(1);
|
|
66
66
|
}
|
|
67
67
|
const s = p.spinner();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blokctl",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"author": "Deskree Technologies Inc.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "cli for blok",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"uninstall:local": "npm rm --global blokctl",
|
|
29
29
|
"dev": "npm run uninstall:local && npm run install:local && npm run build:dev && blokctl --help",
|
|
30
30
|
"postbuild": "cp -r ./src/commands/monitor/static ./dist/commands/monitor/ && if [ -d ../../apps/studio/dist ]; then cp -r ../../apps/studio/dist ./dist/studio-dist; fi",
|
|
31
|
-
"build:studio": "bun run --filter @
|
|
31
|
+
"build:studio": "bun run --filter @blokjs/studio build && cp -r ../../apps/studio/dist ./dist/studio-dist"
|
|
32
32
|
},
|
|
33
33
|
"keywords": [
|
|
34
34
|
"blokctl",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"blok"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@
|
|
40
|
+
"@blokjs/runner": "^0.2.0",
|
|
41
41
|
"@clack/prompts": "^1.0.0",
|
|
42
42
|
"chalk": "^5.6.2",
|
|
43
43
|
"commander": "^14.0.3",
|