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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@well-prado/blok-codegen

v1.0.10

Published

Automatic TypeScript code generation CLI for Blok Framework workflows with type-safe hooks and API clients

Readme

@well-prado/blok-codegen

Automatic TypeScript code generation from Blok Framework workflows with type safety and React hooks.

npm version License: MIT

Overview

The @well-prado/blok-codegen package automatically generates TypeScript types, interfaces, and React hooks from your Blok Framework workflows. This ensures type safety across your entire application and eliminates the need to manually maintain types as your API evolves.

Features

  • 🔄 Automatic Code Generation - Generate types and hooks from live workflows
  • 🛡️ Type Safety - Complete TypeScript coverage for all workflows
  • 🎣 React Hooks - Auto-generated hooks for each workflow
  • 📝 Documentation - Generated JSDoc comments with workflow descriptions
  • 🔍 Schema Validation - Runtime validation based on workflow schemas
  • Watch Mode - Automatic regeneration when workflows change
  • 🎯 Selective Generation - Generate only the workflows you need

Installation

npm install @well-prado/blok-codegen

Global Installation

For CLI usage across projects:

npm install -g @well-prado/blok-codegen

Quick Start

1. Basic Usage

Generate types from your Blok backend:

# Generate types and hooks
npx blok-codegen pull --url http://localhost:4000 --out src/blok-types

# Watch for changes and regenerate
npx blok-codegen watch --url http://localhost:4000 --out src/blok-types

2. Configuration File

Create a blok-codegen.config.js file:

module.exports = {
  url: "http://localhost:4000",
  output: "src/blok-types",
  watch: true,
  include: ["user-*", "auth-*"], // Only generate these workflows
  exclude: ["internal-*"], // Skip these workflows
  typescript: {
    strict: true,
    exactOptionalPropertyTypes: true,
  },
  hooks: {
    enabled: true,
    prefix: "use",
    suffix: "",
  },
};

3. Package.json Scripts

Add convenient scripts to your package.json:

{
  "scripts": {
    "blok:codegen": "blok-codegen pull --url http://localhost:4000 --out src/blok-types",
    "blok:watch": "blok-codegen watch --url http://localhost:4000 --out src/blok-types",
    "blok:codegen:check": "node scripts/check-types.js || npm run blok:codegen"
  }
}

CLI Reference

Commands

pull

Generate types from workflows once.

blok-codegen pull [options]

Options:

  • --url <url> - Blok backend URL (default: http://localhost:4000)
  • --out <path> - Output directory (default: src/blok-types)
  • --include <patterns> - Include only matching workflows
  • --exclude <patterns> - Exclude matching workflows
  • --config <file> - Configuration file path
  • --verbose - Detailed output

Examples:

# Basic generation
blok-codegen pull --url http://localhost:4000

# With filtering
blok-codegen pull --include "user-*,auth-*" --exclude "internal-*"

# Custom output directory
blok-codegen pull --out generated/types

# Using config file
blok-codegen pull --config blok.config.js

watch

Watch for workflow changes and regenerate automatically.

blok-codegen watch [options]

Options: Same as pull command.

Example:

# Watch mode with custom polling interval
blok-codegen watch --url http://localhost:4000 --interval 5000

init

Initialize configuration file and setup.

blok-codegen init [options]

Options:

  • --config <file> - Configuration file name (default: blok-codegen.config.js)
  • --typescript - Generate TypeScript configuration
  • --react - Include React hooks configuration

validate

Validate generated types against current workflows.

blok-codegen validate [options]

Options:

  • --url <url> - Blok backend URL
  • --types <path> - Path to generated types directory

Generated Code Structure

The codegen creates the following files in your output directory:

src/blok-types/
├── types.ts          # TypeScript interfaces for all workflows
├── hooks.ts          # React hooks for each workflow
├── metadata.ts       # Workflow metadata and schemas
└── index.ts          # Re-exports everything

Generated Types Example

// types.ts
export interface UserLoginInput {
  email: string;
  password: string;
  rememberMe?: boolean;
}

export interface UserLoginOutput {
  success: boolean;
  user: {
    id: string;
    name: string;
    email: string;
    role: "admin" | "user";
  };
  token: string;
}

export interface GetUserProfileInput {
  userId?: string;
}

export interface GetUserProfileOutput {
  user: {
    id: string;
    name: string;
    email: string;
    avatar?: string;
    preferences: {
      theme: "light" | "dark";
      notifications: boolean;
    };
  };
}

Generated Hooks Example

// hooks.ts
import {
  useWorkflowQuery,
  useWorkflowMutation,
} from "@well-prado/blok-react-sdk";
import type {
  UserLoginInput,
  UserLoginOutput,
  GetUserProfileInput,
  GetUserProfileOutput,
} from "./types";

/**
 * Login user with email and password
 * @param input - Login credentials
 */
export function useUserLogin() {
  return useWorkflowMutation<UserLoginOutput, UserLoginInput>("user-login");
}

/**
 * Get user profile information
 * @param input - User ID (optional, defaults to current user)
 */
export function useGetUserProfile(input?: GetUserProfileInput) {
  return useWorkflowQuery<GetUserProfileOutput>("get-user-profile", input);
}

/**
 * Update user profile
 * @param input - Updated profile data
 */
export function useUpdateUserProfile() {
  return useWorkflowMutation<void, Partial<GetUserProfileOutput["user"]>>(
    "update-user-profile"
  );
}

Usage in Components

import { useUserLogin, useGetUserProfile } from "./blok-types/hooks";

function LoginForm() {
  const login = useUserLogin();
  const { data: profile } = useGetUserProfile();

  const handleLogin = async (email: string, password: string) => {
    try {
      const result = await login.mutateAsync({ email, password });
      console.log("Logged in as:", result.user.name);
    } catch (error) {
      console.error("Login failed:", error);
    }
  };

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        const formData = new FormData(e.target);
        handleLogin(formData.get("email"), formData.get("password"));
      }}
    >
      <input name="email" type="email" required />
      <input name="password" type="password" required />
      <button type="submit" disabled={login.isPending}>
        {login.isPending ? "Logging in..." : "Login"}
      </button>
    </form>
  );
}

Configuration Options

Complete Configuration Example

// blok-codegen.config.js
module.exports = {
  // Backend URL
  url: process.env.BLOK_API_URL || "http://localhost:4000",

  // Output directory
  output: "src/blok-types",

  // Watch mode settings
  watch: {
    enabled: false,
    interval: 3000, // Poll every 3 seconds
    debounce: 500, // Debounce changes
  },

  // Workflow filtering
  include: [
    "user-*", // All user workflows
    "auth-*", // All auth workflows
    "admin-*", // All admin workflows
  ],
  exclude: [
    "internal-*", // Skip internal workflows
    "test-*", // Skip test workflows
  ],

  // TypeScript generation options
  typescript: {
    strict: true,
    exactOptionalPropertyTypes: true,
    noImplicitAny: true,
    outputInterfaces: true,
    outputTypes: true,
    enumStyle: "union", // 'union' | 'enum'
  },

  // React hooks generation
  hooks: {
    enabled: true,
    prefix: "use",
    suffix: "",
    queryHooks: true, // Generate useWorkflowQuery hooks
    mutationHooks: true, // Generate useWorkflowMutation hooks
    customHooks: true, // Generate workflow-specific hooks
  },

  // Output file configuration
  files: {
    types: "types.ts",
    hooks: "hooks.ts",
    metadata: "metadata.ts",
    index: "index.ts",
  },

  // Documentation generation
  docs: {
    enabled: true,
    includeExamples: true,
    includeSchemas: true,
  },

  // Validation options
  validation: {
    enabled: true,
    strict: false,
    runtime: true, // Generate runtime validators
  },
};

Environment-Specific Configurations

// blok-codegen.config.js
const isDevelopment = process.env.NODE_ENV === "development";

module.exports = {
  url: isDevelopment ? "http://localhost:4000" : "https://api.production.com",

  watch: {
    enabled: isDevelopment,
    interval: isDevelopment ? 2000 : 10000,
  },

  typescript: {
    strict: !isDevelopment, // Less strict in development
  },
};

Advanced Usage

Custom Templates

Create custom code generation templates:

// blok-codegen.config.js
module.exports = {
  templates: {
    hooks: "templates/hooks.hbs",
    types: "templates/types.hbs",
  },
};
{{!-- templates/hooks.hbs --}}
import { useWorkflowQuery, useWorkflowMutation } from '@well-prado/blok-react-sdk';
{{#each workflows}}

/**
 * {{description}}
 * Generated hook for {{name}} workflow
 */
export function use{{pascalCase name}}() {
  {{#if isQuery}}
  return useWorkflowQuery<{{outputType}}>('{{name}}');
  {{else}}
  return useWorkflowMutation<{{outputType}}, {{inputType}}>('{{name}}');
  {{/if}}
}
{{/each}}

Programmatic Usage

Use the codegen API programmatically:

const { BlokCodegen } = require("@well-prado/blok-codegen");

async function generateTypes() {
  const codegen = new BlokCodegen({
    url: "http://localhost:4000",
    output: "src/types",
  });

  try {
    const result = await codegen.generate();
    console.log(`Generated ${result.filesCreated} files`);
    console.log(`Found ${result.workflowsProcessed} workflows`);
  } catch (error) {
    console.error("Generation failed:", error);
  }
}

generateTypes();

Integration with Build Tools

Webpack Plugin

// webpack.config.js
const BlokCodegenPlugin = require("@well-prado/blok-codegen/webpack");

module.exports = {
  plugins: [
    new BlokCodegenPlugin({
      url: "http://localhost:4000",
      output: "src/blok-types",
      watch: process.env.NODE_ENV === "development",
    }),
  ],
};

Vite Plugin

// vite.config.js
import { defineConfig } from "vite";
import { blokCodegen } from "@well-prado/blok-codegen/vite";

export default defineConfig({
  plugins: [
    blokCodegen({
      url: "http://localhost:4000",
      output: "src/blok-types",
    }),
  ],
});

Workflow Discovery

The codegen discovers workflows through your Blok backend's discovery endpoint:

Automatic Discovery

# Discovers all available workflows
blok-codegen pull --url http://localhost:4000

Manual Workflow Specification

// blok-codegen.config.js
module.exports = {
  workflows: [
    {
      name: "user-login",
      input: {
        email: "string",
        password: "string",
      },
      output: {
        success: "boolean",
        user: "User",
        token: "string",
      },
    },
  ],
};

Type Safety Features

Input Validation

Generated types include runtime validation:

import { validateUserLoginInput } from "./blok-types/validators";

const loginData = { email: "[email protected]", password: "123" };

if (validateUserLoginInput(loginData)) {
  // TypeScript knows loginData is valid UserLoginInput
  const result = await userLogin.mutateAsync(loginData);
}

Schema Evolution

The codegen tracks schema changes and warns about breaking changes:

blok-codegen pull --check-breaking-changes

Output:

⚠️  Breaking changes detected:
  - user-login: removed field 'rememberMe'
  - get-user-profile: 'avatar' is now required

Development Workflow

Typical Development Flow

  1. Start your Blok backend:

    npm run dev:backend
  2. Generate initial types:

    npm run blok:codegen
  3. Start watch mode:

    npm run blok:watch
  4. Develop your frontend with full type safety:

    import { useGetUserProfile } from "./blok-types/hooks";
    
    function Profile() {
      const { data } = useGetUserProfile();
      return <h1>{data?.user.name}</h1>; // ✅ Fully typed
    }

Pre-commit Hooks

Ensure types are up-to-date before commits:

{
  "husky": {
    "hooks": {
      "pre-commit": "npm run blok:codegen:check"
    }
  }
}

Testing

Generated Code Testing

Test the generated types and hooks:

// __tests__/blok-types.test.ts
import { validateUserLoginInput } from "../blok-types/validators";
import { UserLoginInput } from "../blok-types/types";

describe("Generated Types", () => {
  test("validates correct input", () => {
    const validInput: UserLoginInput = {
      email: "[email protected]",
      password: "password123",
    };

    expect(validateUserLoginInput(validInput)).toBe(true);
  });

  test("rejects invalid input", () => {
    const invalidInput = {
      email: "not-an-email",
      password: "",
    };

    expect(validateUserLoginInput(invalidInput)).toBe(false);
  });
});

Mock Generated Hooks

// __mocks__/blok-types/hooks.ts
export const useUserLogin = jest.fn(() => ({
  mutateAsync: jest.fn(),
  isPending: false,
}));

export const useGetUserProfile = jest.fn(() => ({
  data: { user: { name: "Test User" } },
  isLoading: false,
}));

Troubleshooting

Common Issues

  1. "Workflow discovery failed"

    • Ensure your backend is running
    • Check the URL is correct
    • Verify the discovery endpoint is enabled
  2. "No workflows found"

    • Check include/exclude patterns
    • Verify workflows are properly registered
    • Use --verbose flag for detailed output
  3. "Generated types are outdated"

    • Run npm run blok:codegen to regenerate
    • Check if workflows have changed on the backend
    • Verify the backend URL is correct
  4. TypeScript compilation errors

    • Ensure generated types are in your tsconfig include
    • Check for naming conflicts with existing types
    • Verify TypeScript version compatibility

Debug Mode

Enable debug output for troubleshooting:

DEBUG=blok-codegen:* blok-codegen pull --verbose

Validation

Validate your setup:

blok-codegen validate --url http://localhost:4000 --types src/blok-types

Best Practices

1. Version Control

Commit generated files to version control:

# Don't ignore generated types
!src/blok-types/

2. Naming Conventions

Use consistent workflow naming:

// ✅ Good
"user-login";
"user-register";
"user-profile-update";

// ❌ Avoid
"loginUser";
"userLogin";
"Login";

3. Workflow Organization

Organize workflows by domain:

module.exports = {
  include: [
    "auth-*", // Authentication workflows
    "user-*", // User management
    "admin-*", // Admin operations
    "public-*", // Public APIs
  ],
};

4. Type Safety

Use strict TypeScript settings:

{
  "compilerOptions": {
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitAny": true
  }
}

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Related Packages