npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@well-prado/blok-workflow-analyzer

v1.1.1

Published

Automatic workflow analysis and type inference for Blok Framework

Readme

@blok-framework/workflow-analyzer

Automatic workflow analysis and type inference for Blok Framework

Eliminates manual type definitions by automatically inferring types from workflow nodes. Inspired by Laravel + Inertia.js, powered by TypeScript AST parsing.

✨ Features

  • 🔍 Automatic Workflow Discovery - Scans and analyzes all workflows
  • 🎯 Smart Type Inference - Extracts types from node JSON schemas
  • 🚀 Zero Manual Work - No type definitions needed!
  • Fast & Cached - Analysis results are cached for performance
  • 👀 Watch Mode - Auto-regenerate on file changes
  • 🎨 Perfect TypeScript - Generates production-ready types
  • 🔐 Security Analysis - Detects auth requirements automatically

📦 Installation

npm install @blok-framework/workflow-analyzer
# or
pnpm add @blok-framework/workflow-analyzer

🚀 Quick Start

import { WorkflowAnalyzer } from "@blok-framework/workflow-analyzer";

// Create analyzer
const analyzer = new WorkflowAnalyzer({
  projectRoot: process.cwd(),
});

// Analyze single workflow
const analysis = await analyzer.analyzeWorkflow("admin-logs");
console.log(analysis.inputType); // Perfect TypeScript types!
console.log(analysis.outputType);

// Analyze all workflows
const allAnalyses = await analyzer.analyzeAllWorkflows();
console.log(`Analyzed ${allAnalyses.size} workflows`);

// Watch for changes
analyzer.watch((event) => {
  console.log(`Workflow ${event.type}:`, event.workflowKey);
});

📖 API Reference

WorkflowAnalyzer

Main class for analyzing workflows.

Constructor

new WorkflowAnalyzer(config: AnalyzerConfig)

Config Options:

  • projectRoot (required): Project root directory
  • workflowsDir (optional): Workflows directory (default: src/workflows)
  • nodesDir (optional): Nodes directory (default: src/nodes)
  • cache (optional): Enable caching (default: true)
  • middlewarePatterns (optional): Custom middleware patterns to skip

Methods

analyzeWorkflow(workflowKey: string): Promise<WorkflowAnalysis>

Analyzes a single workflow and returns complete type information.

const analysis = await analyzer.analyzeWorkflow("admin-logs");

// analysis contains:
// - workflowKey: string
// - name, version, description
// - endpoint, method, path
// - inputType, outputType (TypeScript types!)
// - requiresAuth, requiredRole
// - dataNodes: string[]
// - structure: WorkflowStructure
analyzeAllWorkflows(): Promise<Map<string, WorkflowAnalysis>>

Analyzes all workflows in the project.

const analyses = await analyzer.analyzeAllWorkflows();

for (const [key, analysis] of analyses) {
  console.log(`${key}: ${analysis.dataNodes.join(", ")}`);
}
watch(callback: WorkflowChangeCallback): void

Watches for workflow file changes and triggers callback.

analyzer.watch(async (event) => {
  if (event.type === "changed") {
    const analysis = await analyzer.analyzeWorkflow(event.workflowKey);
    // Regenerate types...
  }
});
clearCache(): void

Clears the analysis cache.

analyzer.clearCache();

🎯 How It Works

1. Workflow Discovery

The analyzer scans your workflows directory and discovers all workflow files:

// Automatically finds:
src/workflows/
├── admin/admin-logs.ts
├── auth/register.ts
├── profile/profile-update.ts
└── ...

2. Workflow Parsing

Each workflow is parsed using TypeScript AST to extract:

  • Workflow metadata (name, version, description)
  • HTTP trigger information
  • Node references
  • Conditional branches
  • Exported types

3. Node Schema Loading

For each node referenced in a workflow:

  1. Locate the node file (supports multiple patterns)
  2. Extract inputSchema and outputSchema (JSON Schema format)
  3. Parse schema properties and types

4. Type Inference

Smart type inference engine:

  • Analyzes HTTP trigger parameters
  • Examines first step's input requirements
  • Checks last step's output shape
  • Detects authentication requirements
  • Identifies admin-only workflows

5. Type Generation

Generates perfect TypeScript types:

// Input: Workflow with system-action-logger node
// Output: Perfect TypeScript types!

export interface AdminLogsInput {
  action: "log" | "query" | "getStats" | "cleanup" | "export";
  phase?: "start" | "complete";
  userId?: string;
  // ... 14 more fields
}

export interface AdminLogsOutput {
  success?: boolean;
  message?: string;
  data?: Record<string, any>;
}

🔧 Integration with Codegen

Perfect integration with @blok-framework/codegen:

import { WorkflowAnalyzer } from "@blok-framework/workflow-analyzer";
import { TypeGenerator } from "@blok-framework/codegen";

// Analyze workflows
const analyzer = new WorkflowAnalyzer({ projectRoot });
const analyses = await analyzer.analyzeAllWorkflows();

// Generate types
const generator = new TypeGenerator();
const types = generator.generateFromAnalysis(analyses);

// Write to files
await writeFile("generated-types.ts", types);

📊 Supported Patterns

Node Patterns

✅ Folder with index.ts: src/nodes/auth/user-register/index.ts
✅ Direct TypeScript file: src/nodes/notifications/get-user-notifications.ts
✅ Nested categories: src/nodes/security/system-action-logger/index.ts

Workflow Patterns

✅ Simple workflows (single node)
✅ Multi-step workflows (multiple nodes)
✅ Conditional workflows (if-else branches)
✅ Middleware workflows (auth, interceptors)
✅ Any HTTP method (GET, POST, PUT, PATCH, DELETE)

Middleware Detection

Automatically skips common middleware nodes:

  • authentication-checker
  • request-interceptor
  • error
  • @nanoservice-ts/* (framework nodes)

Custom patterns can be added via config:

const analyzer = new WorkflowAnalyzer({
  projectRoot,
  middlewarePatterns: [
    "authentication-checker",
    "request-interceptor",
    "my-custom-middleware",
  ],
});

🎯 Best Practices

1. Node Schema Quality

Ensure your nodes have comprehensive JSON schemas:

export default class MyNode extends NanoService<MyInput> {
  constructor() {
    super();

    // ✅ Good: Comprehensive schema
    this.inputSchema = {
      type: "object",
      properties: {
        action: {
          type: "string",
          enum: ["create", "update", "delete"],
          description: "Operation to perform", // ← Descriptions help!
        },
        data: {
          type: "object",
          description: "Operation data",
        },
      },
      required: ["action"],
    };

    this.outputSchema = {
      type: "object",
      properties: {
        success: { type: "boolean" },
        data: { type: "object" },
      },
    };
  }
}

2. Workflow Organization

Organize workflows by category:

src/workflows/
├── admin/          # Admin-only workflows
├── auth/           # Authentication workflows
├── profile/        # User profile workflows
├── notifications/  # Notification workflows
└── api/            # Public API workflows

3. Cache Management

Use caching for better performance:

// Enable caching (default: true)
const analyzer = new WorkflowAnalyzer({
  projectRoot,
  cache: true,
});

// Clear cache when needed
analyzer.clearCache();

🐛 Troubleshooting

Issue: Node not found

Solution: Check that node file follows supported patterns:

  • src/nodes/category/node-name/index.ts
  • src/nodes/category/node-name.ts

Issue: Types not accurate

Solution: Ensure node has proper inputSchema and outputSchema:

this.inputSchema = { ... };  // Must be valid JSON Schema
this.outputSchema = { ... }; // Must be valid JSON Schema

Issue: Middleware node detected as main node

Solution: Add to middleware patterns:

const analyzer = new WorkflowAnalyzer({
  projectRoot,
  middlewarePatterns: ["your-middleware-node"],
});

📚 Examples

Example 1: Analyze Specific Workflow

import { WorkflowAnalyzer } from "@blok-framework/workflow-analyzer";

const analyzer = new WorkflowAnalyzer({ projectRoot: __dirname });
const analysis = await analyzer.analyzeWorkflow("admin-logs");

console.log(`Workflow: ${analysis.name}`);
console.log(`Endpoint: ${analysis.method} ${analysis.endpoint}`);
console.log(`Auth Required: ${analysis.requiresAuth}`);
console.log(`Data Nodes: ${analysis.dataNodes.join(", ")}`);

Example 2: Generate Report

const analyses = await analyzer.analyzeAllWorkflows();

const report = {
  total: analyses.size,
  requireAuth: Array.from(analyses.values()).filter((a) => a.requiresAuth)
    .length,
  adminOnly: Array.from(analyses.values()).filter(
    (a) => a.requiredRole === "ADMIN"
  ).length,
  byMethod: {},
};

console.log("Workflow Analysis Report:", report);

Example 3: Watch Mode Integration

import { WorkflowAnalyzer } from "@blok-framework/workflow-analyzer";
import { TypeGenerator } from "@blok-framework/codegen";

const analyzer = new WorkflowAnalyzer({ projectRoot });
const generator = new TypeGenerator();

// Watch for changes and regenerate types
analyzer.watch(async (event) => {
  console.log(`\n📝 Workflow ${event.type}: ${event.workflowKey}`);

  if (event.type !== "removed") {
    const analysis = await analyzer.analyzeWorkflow(event.workflowKey);
    const types = generator.generateFromAnalysis(
      new Map([[event.workflowKey, analysis]])
    );

    await writeFile("generated-types.ts", types);
    console.log("✅ Types regenerated!");
  }
});

console.log("👀 Watching for workflow changes...");

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

📄 License

MIT © Blok Framework Team

🔗 Related Packages

📖 Documentation


Built with ❤️ by the Blok Framework Team

From 150 lines of manual types to ZERO with perfect type safety!