@well-prado/blok-codegen
v1.0.10
Published
Automatic TypeScript code generation CLI for Blok Framework workflows with type-safe hooks and API clients
Maintainers
Readme
@well-prado/blok-codegen
Automatic TypeScript code generation from Blok Framework workflows with type safety and React hooks.
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-codegenGlobal Installation
For CLI usage across projects:
npm install -g @well-prado/blok-codegenQuick 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-types2. 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.jswatch
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 5000init
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 everythingGenerated 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:4000Manual 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-changesOutput:
⚠️ Breaking changes detected:
- user-login: removed field 'rememberMe'
- get-user-profile: 'avatar' is now requiredDevelopment Workflow
Typical Development Flow
Start your Blok backend:
npm run dev:backendGenerate initial types:
npm run blok:codegenStart watch mode:
npm run blok:watchDevelop 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
"Workflow discovery failed"
- Ensure your backend is running
- Check the URL is correct
- Verify the discovery endpoint is enabled
"No workflows found"
- Check include/exclude patterns
- Verify workflows are properly registered
- Use
--verboseflag for detailed output
"Generated types are outdated"
- Run
npm run blok:codegento regenerate - Check if workflows have changed on the backend
- Verify the backend URL is correct
- Run
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 --verboseValidation
Validate your setup:
blok-codegen validate --url http://localhost:4000 --types src/blok-typesBest 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
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
Related Packages
@well-prado/blok-react-sdk- React hooks and components@well-prado/blok-front-sdk-core- Core utilities and client@well-prado/blok-admin-dashboard- Complete backend solution@well-prado/blok-cli- CLI for project management
