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

@memberjunction/codegen-lib

v2.129.0

Published

Library used by the CodeGen executable to generate code for the MemberJunction platform. Contains a reusable object model that can be called by any other server-side application/library.

Readme

@memberjunction/codegen-lib

🚀 The most sophisticated code generation engine you've ever seen - automatically transforms your database schema into a complete, type-safe, full-stack application with AI-powered intelligence.

What Makes This Badass?

MemberJunction's CodeGen doesn't just generate boilerplate code. It's an AI-powered, metadata-driven architecture that creates bulletproof, production-ready applications from your database schema with zero manual intervention.

🧠 AI-Powered Intelligence

  • CHECK Constraint Translation: Our AI automatically translates complex SQL CHECK constraints into perfect TypeScript union types and Zod validation schemas
  • Smart Type Inference: Analyzes relationships and generates contextually appropriate Angular form controls (dropdowns, search boxes, checkboxes)
  • Intelligent Naming: AI-driven naming conventions ensure your generated code follows best practices

⚡ Synchronization Across Everything

Watch your database changes instantly propagate through your entire stack:

Database Schema Change → TypeScript Entities → Angular Forms → SQL Procedures → GraphQL Schema

One command. Complete synchronization. Zero breaking changes.

🎯 What Gets Generated (Automatically)

  • TypeScript Entity Classes with full type safety and validation
  • Angular Form Components with proper field types and validation
  • SQL Stored Procedures for all CRUD operations
  • Database Views with optimized joins and indexing
  • GraphQL Schemas and resolvers
  • Zod Validation Schemas from SQL constraints
  • Complete API Endpoints with type-safe parameters

Installation

npm install @memberjunction/codegen-lib

The Magic in Action

From This SQL Constraint:

ALTER TABLE [AIPrompt]
ADD [PromptRole] nvarchar(20) NOT NULL
    CONSTRAINT [CK_AIPrompt_PromptRole] CHECK ([PromptRole] IN (N'System', N'User', N'Assistant', N'SystemOrUser'))

To This TypeScript (Automatically):

PromptRole: z.union([
    z.literal('System'), 
    z.literal('User'), 
    z.literal('Assistant'), 
    z.literal('SystemOrUser')
]).describe('Determines how the prompt is used in conversation...')

To This Angular Form (Automatically):

<mj-form-field 
    [record]="record"
    FieldName="PromptRole"
    Type="dropdownlist"  // AI chose dropdown based on constraint
    [EditMode]="EditMode"
></mj-form-field>

To This SQL Procedure (Automatically):

CREATE PROCEDURE [spCreateAIPrompt]
    @PromptRole nvarchar(20),
    -- 20+ other parameters auto-generated
AS BEGIN
    -- Complete CRUD logic with validation
END

All from ONE schema change. All type-safe. All production-ready.

Quick Start - Watch The Magic

import { initializeConfig, runCodeGen } from '@memberjunction/codegen-lib';

// Initialize configuration
await initializeConfig();

// Generate your entire application stack
await runCodeGen();

// That's it. Seriously.

Your database schema just became:

  • 295+ TypeScript entity classes with full validation
  • Complete Angular UI with smart form controls
  • All SQL stored procedures for every operation
  • GraphQL API with type-safe resolvers
  • Perfect type safety across your entire stack

Core Capabilities

🏗️ Entity Subclass Generation

Generates bullet-proof TypeScript classes from your database schema:

// Auto-generated from your schema
export class AIPromptEntity extends BaseEntity {
  // 30+ properties with perfect types
  PromptRole: 'System' | 'User' | 'Assistant' | 'SystemOrUser';
  
  // AI-powered validation from CHECK constraints
  validate(): ValidationResult {
    return this.validateWithZod(AIPromptSchema);
  }
}

🎨 Angular Component Generation

Creates production-ready Angular forms with intelligent field types:

// Auto-detects relationships and creates search components
<mj-form-field 
    FieldName="CategoryID"
    Type="textbox"           // Smart field type selection
    LinkType="Record"        // Auto-detected relationship
    LinkComponentType="Search" // AI chose search over dropdown
></mj-form-field>

🗃️ SQL Script Generation

Generates optimized database objects with best practices:

-- Auto-generated indexes for performance
CREATE INDEX IDX_AUTO_MJ_FKEY_AIPrompt_CategoryID
ON [AIPrompt] ([CategoryID]);

-- Complete CRUD procedures with validation
CREATE PROCEDURE [spCreateAIPrompt]
    @PromptRole nvarchar(20) -- Validated against CHECK constraint
-- Full implementation auto-generated

🌲 Automatic Recursive Hierarchy Support

CodeGen automatically detects self-referential foreign keys and generates Root{FieldName} columns in base views using efficient recursive CTEs. This enables instant root node lookup for hierarchical data structures with zero overhead when not selected.

How It Works:

For any table with a self-referential foreign key (like ParentTaskIDTask.ID), CodeGen automatically:

  1. Detects the recursive relationship - Identifies foreign keys where RelatedEntityID === entity.ID
  2. Generates a recursive CTE - Creates SQL that traverses the hierarchy to find the root
  3. Adds Root columns - Exposes Root{FieldName} in the base view (e.g., RootParentTaskID)
  4. Zero-overhead when unused - SQL optimizer eliminates the CTE when column not selected

Example - Task Hierarchy:

CREATE TABLE [Task] (
    [ID] uniqueidentifier PRIMARY KEY,
    [ParentTaskID] uniqueidentifier FOREIGN KEY REFERENCES [Task]([ID]),
    [Name] nvarchar(255)
);

CodeGen Automatically Generates:

CREATE VIEW [vwTasks]
AS
WITH
    CTE_RootParentTaskID AS (
        -- Anchor: rows with no parent (root nodes)
        SELECT
            [ID],
            [ID] AS [RootParentTaskID]
        FROM
            [__mj].[Task]
        WHERE
            [ParentTaskID] IS NULL

        UNION ALL

        -- Recursive: traverse up the hierarchy
        SELECT
            child.[ID],
            parent.[RootParentTaskID]
        FROM
            [__mj].[Task] child
        INNER JOIN
            CTE_RootParentTaskID parent ON child.[ParentTaskID] = parent.[ID]
    )
SELECT
    t.*,
    CTE_RootParentTaskID.[RootParentTaskID]  -- Auto-generated root column
FROM
    [__mj].[Task] AS t
LEFT OUTER JOIN
    CTE_RootParentTaskID
  ON
    t.[ID] = CTE_RootParentTaskID.[ID]

Benefits:

  • Automatic Detection - No configuration needed, works for any recursive FK
  • Multiple Recursive FKs - Handles tables with multiple self-referential relationships
  • SQL Optimizer Magic - CTE only executes when RootParentTaskID is selected
  • Always Correct - No stale data (unlike computed columns or triggers)
  • TypeScript Integration - Root fields automatically appear in entity classes
  • Naming Convention - Consistent Root{FieldName} pattern across all entities

Use Cases:

  • Organizational Charts - Employee.ManagerIDRootManagerID finds CEO
  • Task Hierarchies - Task.ParentTaskIDRootParentTaskID finds root project
  • Category Trees - Category.ParentCategoryIDRootParentCategoryID finds top level
  • Comment Threads - Comment.ParentCommentIDRootParentCommentID finds original post
  • Bill of Materials - Part.ParentPartIDRootParentPartID finds top-level assembly

Performance Note:

The CTE approach is ideal for read-heavy workloads (typical in business applications). The SQL optimizer completely eliminates the CTE from the execution plan when the root column isn't selected, meaning zero overhead for queries that don't need hierarchy information.

🎯 Smart Delete Procedures with Cascade Handling

Our generated delete procedures are production-grade with intelligent handling of:

1. Result Feedback - Know What Happened

-- Returns NULL for all PKs when no record found
IF @@ROWCOUNT = 0
    SELECT NULL AS [CustomerID], NULL AS [OrderID]
ELSE
    SELECT @CustomerID AS [CustomerID], @OrderID AS [OrderID]

2. Cascade Deletes via Stored Procedure Calls

Instead of basic DELETE statements, we generate cursor-based cascade operations that respect your business logic:

-- BAD: Direct DELETE (bypasses business logic)
DELETE FROM OrderItems WHERE OrderID = @OrderID

-- GOOD: Cursor-based SP calls (respects custom logic)
DECLARE @RelatedItemID INT
DECLARE cascade_delete_OrderItem_cursor CURSOR FOR 
    SELECT [ItemID] FROM [OrderItems] WHERE [OrderID] = @OrderID

OPEN cascade_delete_OrderItem_cursor
FETCH NEXT FROM cascade_delete_OrderItem_cursor INTO @RelatedItemID

WHILE @@FETCH_STATUS = 0
BEGIN
    -- Calls YOUR stored procedure, enabling N-level cascades
    EXEC [spDeleteOrderItem] @RelatedItemID
    FETCH NEXT FROM cascade_delete_OrderItem_cursor INTO @RelatedItemID
END

CLOSE cascade_delete_OrderItem_cursor
DEALLOCATE cascade_delete_OrderItem_cursor

Benefits:

  • Respects custom delete logic in related entities
  • Enables multi-level cascades (if OrderItem has its own cascades)
  • Maintains referential integrity through proper SP calls
  • Clear result feedback - NULL means no record deleted

3. Nullable Foreign Key Handling

For nullable FKs, we update via stored procedures too:

-- Fetch all fields, update only the FK to NULL
DECLARE cascade_update_Customer_cursor CURSOR FOR 
    SELECT * FROM [Customers] WHERE [RegionID] = @RegionID

-- In cursor loop:
SET @UpdateRegionID = NULL  -- Only FK changes
EXEC [spUpdateCustomer] @CustomerID, @Name, @Email, @UpdateRegionID

4. Configuration Error Detection

CodeGen warns you about misconfigured cascade scenarios:

-- WARNING: Orders has non-nullable FK to Customer but doesn't allow delete API
-- This will cause a referential integrity violation

The warnings appear both in generated SQL and console output during generation.

🔄 Smart Update Procedures with Result Validation

Our update procedures also provide clear feedback when operating on non-existent records:

-- Check if update affected any rows
IF @@ROWCOUNT = 0
    -- Return empty result set (maintains column structure)
    SELECT TOP 0 * FROM [vwCustomer] WHERE 1=0
ELSE
    -- Return the updated record with calculated fields
    SELECT * FROM [vwCustomer] WHERE [CustomerID] = @CustomerID

Why This Matters:

  • Empty result set = Record not found (update failed)
  • Record returned = Update successful
  • Maintains schema = Calling code doesn't break
  • Includes calculated fields = Get the latest computed values

🌐 GraphQL Schema Generation

Creates type-safe GraphQL APIs from your entities:

type AIPrompt {
  id: ID!
  promptRole: PromptRoleEnum!  # Auto-generated from CHECK constraint
  category: AIPromptCategory   # Auto-resolved relationships
}

enum PromptRoleEnum {
  SYSTEM
  USER
  ASSISTANT
  SYSTEMORUSER
}

🔬 Database Schema Introspection

Reverse-engineers your entire database into metadata:

const schemaInfo = await analyzeSchema(connection);
// Discovers tables, relationships, constraints, indexes
// Feeds AI engine for intelligent code generation

Advanced Features That Blow Minds

🎨 AI-Powered Form Layout Generation

CodeGen uses AI to automatically organize entity fields into semantic categories with icons, creating intuitive form layouts without manual configuration.

What It Does:

  1. Field Categorization - Groups fields into domain-specific categories (e.g., "Billing Address", "Pricing and Charges", "System Metadata")
  2. Category Icons - Assigns Font Awesome icons to each category for visual navigation
  3. Category Descriptions - Generates tooltip descriptions for UX enhancement
  4. Entity Importance Analysis - Determines if entities should appear in navigation for new users
  5. Smart Display Names - Converts technical field names to user-friendly labels (e.g., BillToAddress1 → "Billing Address Line 1")

Entity Importance Detection:

The AI uses FK ratio analysis to classify entities:

| Entity Type | FK Ratio | Example | DefaultForNewUser | |-------------|----------|---------|-------------------| | Primary | 10-30% | Contact, Order, Deal | ✅ Yes | | Supporting | 20-40% | OrderItem, Address | Sometimes | | Reference/Type | 0-20% | OrderStatus, ContactType | ❌ No | | Junction | 40-80% | UserRole, ContactAccount | ❌ No |

Stability Guarantees:

The system enforces category stability to prevent unnecessary churn on existing entities:

What's Preserved (Never Changed by AI):

  • ✅ Existing category names - AI cannot rename "Personal Info" to "Personal Details"
  • ✅ Existing category icons - Icons set by admins or previous runs are preserved
  • ✅ Existing category descriptions - Descriptions are only added, never modified

What AI Can Do:

  • ✅ Assign NEW fields to existing categories
  • ✅ Assign NEW fields to NEW categories (when no existing category fits)
  • ✅ Move existing fields between EXISTING categories (with discretion)
  • ❌ Move existing fields to NEW categories (blocked - prevents renaming)

Enforcement Example:

Field 'Email' is in category 'Contact Info'
LLM suggests moving to 'Communication Details' (new category)
→ REJECTED: Cannot move existing field to new category
→ Field stays in 'Contact Info'

Control Flags on EntityField:

  • AutoUpdateCategory - If FALSE, field's category is locked
  • AutoUpdateDisplayName - If FALSE, display name is locked
  • AutoUpdateIsNameField - If FALSE, name field designation is locked

DefaultForNewUser - Only for New Entities:

The DefaultForNewUser flag is only set when an entity is first created, not on subsequent updates. This ensures:

  • Admins retain full control over navigation visibility
  • CodeGen won't override manual admin decisions
  • Existing entity configurations remain stable

Storage Format:

Category information is stored in EntitySetting with two formats for compatibility:

New Format (FieldCategoryInfo):

{
  "Billing Address": {
    "icon": "fa fa-file-invoice",
    "description": "Address for invoice delivery and billing correspondence"
  },
  "System Metadata": {
    "icon": "fa fa-cog",
    "description": "System-managed audit and tracking fields"
  }
}

Legacy Format (FieldCategoryIcons) - maintained for backwards compatibility:

{
  "Billing Address": "fa fa-file-invoice",
  "System Metadata": "fa fa-cog"
}

🤖 AI-Powered CHECK Constraint Translation

Our AI doesn't just copy constraints - it understands intent:

-- Complex constraint
CHECK ([Status] IN ('Draft', 'Published', 'Archived') 
       AND [PublishedAt] IS NOT NULL WHEN [Status] = 'Published')

Becomes perfect TypeScript:

Status: z.union([z.literal('Draft'), z.literal('Published'), z.literal('Archived')])
  .refine((status, ctx) => {
    if (status === 'Published' && !this.PublishedAt) {
      ctx.addIssue({ code: 'custom', message: 'Published items must have PublishedAt' });
    }
  })

🔄 Real-Time Synchronization

Change your database schema → Everything updates automatically:

  1. Flyway migration executes
  2. CodeGen detects changes
  3. Regenerates affected code
  4. Type safety maintained across entire stack
  5. Zero manual intervention

🚀 Performance Optimization

  • Intelligent caching prevents unnecessary regeneration
  • Incremental updates for changed entities only
  • Optimized SQL with proper indexing strategies
  • Lazy loading for large schema datasets

🔒 Enterprise-Grade Security

  • Parameterized queries in all generated SQL
  • Input validation at every layer
  • SQL injection protection built-in
  • Type-safe APIs prevent runtime errors

Configuration

Create a .memberjunctionrc file:

{
  "memberjunction": {
    "database": {
      "server": "localhost",
      "database": "YourDatabase",
      "trustedConnection": true
    },
    "directories": {
      "output": "./generated",
      "entities": "./generated/entities",
      "actions": "./generated/actions",
      "angular": "./generated/angular",
      "sql": "./generated/sql"
    },
    "ai": {
      "enabled": true,
      "provider": "openai"  // Powers constraint translation
    }
  }
}

Real-World Example

Starting with a simple table:

CREATE TABLE [Customer] (
    [ID] uniqueidentifier PRIMARY KEY DEFAULT newsequentialid(),
    [Name] nvarchar(255) NOT NULL,
    [Status] nvarchar(20) CHECK ([Status] IN ('Active', 'Inactive', 'Suspended')),
    [CreatedAt] datetimeoffset DEFAULT getutcdate()
);

One CodeGen run produces:

TypeScript Entity (175 lines)

export class CustomerEntity extends BaseEntity {
    Status: 'Active' | 'Inactive' | 'Suspended';
    // + complete validation, save methods, relationships
}

Angular Component (89 lines)

@Component({
    template: `Complete form with validation and smart controls`
})
export class CustomerDetailsComponent {
    // Ready for production use
}

SQL Procedures (200+ lines)

-- spCreateCustomer, spUpdateCustomer, spDeleteCustomer
-- Complete with validation and error handling

GraphQL Schema (45 lines)

type Customer {
    # Complete type-safe schema
}

Total: 500+ lines of production code from 6 lines of SQL.

API Reference

Core Functions

// Generate everything at once
await runCodeGen();

// Generate specific components
await generateEntitySubClasses(options);
await generateAngularEntityCode(options); 
await generateSQLScripts(options);
await generateGraphQLServerCode(options);

Entity Subclass Generation

import { generateEntitySubClasses } from '@memberjunction/codegen-lib';

const result = await generateEntitySubClasses({
  outputDirectory: './generated/entities',
  generateLoader: true,
  generateCustomEntityClasses: true,
  aiEnhanced: true,           // Enable AI features
  incrementalMode: true,      // Only update changed entities
  validateGenerated: true     // Compile-check generated code
});

Action Subclass Generation

import { generateActionSubClasses } from '@memberjunction/codegen-lib';

const result = await generateActionSubClasses({
  outputDirectory: './generated/actions',
  generateLoader: true
});

GraphQL Server Generation

import { generateGraphQLServerCode } from '@memberjunction/codegen-lib';

await generateGraphQLServerCode({
  outputDirectory: './generated/graphql',
  entities: entityMetadata
});

SQL Code Generation

import { generateSQLScripts } from '@memberjunction/codegen-lib';

await generateSQLScripts({
  outputDirectory: './generated/sql',
  includeStoredProcedures: true,
  includeViews: true
});

Angular Component Generation

import { generateAllAngularEntityCode } from '@memberjunction/codegen-lib';

await generateAllAngularEntityCode({
  outputDirectory: './generated/angular',
  entities: entityMetadata
});

Performance Stats

On a typical MemberJunction database with 150+ tables:

  • Entity Generation: 2.3 seconds
  • Angular Components: 4.7 seconds
  • SQL Procedures: 1.8 seconds
  • Total Stack Generation: <10 seconds

For 295 entity classes and thousands of generated files.

Integration with MemberJunction Ecosystem

Works seamlessly with:

  • @memberjunction/core - Entity framework
  • @memberjunction/ai - AI-powered features
  • @memberjunction/angular-explorer - UI framework
  • @memberjunction/graphql-dataprovider - API layer
  • @memberjunction/sqlserver-dataprovider - Data access

Advanced Features

Custom Templates

You can provide custom templates for code generation:

import { setCustomTemplate } from '@memberjunction/codegen-lib';

setCustomTemplate('entity', myCustomEntityTemplate);

Schema Analysis

import { analyzeSchema } from '@memberjunction/codegen-lib';

const schemaInfo = await analyzeSchema(databaseConnection);
// Work with schema information

Progress Tracking

import { onProgress } from '@memberjunction/codegen-lib';

onProgress((status) => {
  console.log(`Progress: ${status.message} (${status.percentage}%)`);
});

Force Regeneration with Smart Filtering

Need to regenerate specific SQL objects without schema changes? Our force regeneration feature gives you surgical precision over what gets regenerated:

// In mj.config.cjs
forceRegeneration: {
  enabled: true,
  // Filter to specific entities using SQL WHERE clause
  entityWhereClause: "SchemaName = 'CRM' AND __mj_UpdatedAt >= '2025-06-24'",
  
  // Granular control over what gets regenerated
  baseViews: true,      // Regenerate base views
  spCreate: false,      // Skip create procedures
  spUpdate: true,       // Regenerate update procedures
  spDelete: false,      // Skip delete procedures
  indexes: true,        // Regenerate foreign key indexes
  fullTextSearch: false // Skip full-text search components
}

Common Scenarios:

Regenerate views for recently modified entities:

forceRegeneration: {
  enabled: true,
  entityWhereClause: "__mj_UpdatedAt >= '2025-06-24 22:00:00'",
  baseViews: true
}

Regenerate all stored procedures for a specific schema:

forceRegeneration: {
  enabled: true,
  entityWhereClause: "SchemaName = 'Sales'",
  allStoredProcedures: true
}

Regenerate specific SQL object for a single entity:

forceRegeneration: {
  enabled: true,
  entityWhereClause: "Name = 'Customer'",
  spUpdate: true  // Just regenerate the update procedure
}

Regenerate everything (no filtering):

forceRegeneration: {
  enabled: true,
  // No entityWhereClause = regenerate for ALL entities
  allStoredProcedures: true,
  baseViews: true,
  indexes: true
}

How It Works:

  1. Entity Filtering: The entityWhereClause runs against the Entity metadata table to select which entities qualify
  2. Type Filtering: Individual flags control which SQL object types get regenerated
  3. Smart Combination: Only regenerates the intersection (selected entities AND selected types)
  4. Error Handling: Invalid WHERE clauses stop execution with clear error messages

Error Handling

The library provides comprehensive error handling:

try {
  await runCodeGen();
} catch (error) {
  if (error.code === 'CONFIG_NOT_FOUND') {
    // Handle missing configuration
  } else if (error.code === 'DB_CONNECTION_FAILED') {
    // Handle database connection errors
  }
}

Why This Changes Everything

Before MemberJunction CodeGen:

  • Weeks of manual entity creation
  • Inconsistent validation logic
  • Type mismatches between layers
  • Manual Angular form creation
  • Brittle SQL procedures
  • Schema changes break everything

After MemberJunction CodeGen:

  • 10 seconds to regenerate entire stack
  • Perfect type safety across all layers
  • AI-powered intelligent code generation
  • Zero manual intervention
  • Production-ready from day one

Best Practices

  1. Configuration Management - Use environment-specific configuration files
  2. Output Organization - Keep generated code in separate directories
  3. Version Control - Consider excluding generated files from version control
  4. Regular Updates - Regenerate code when metadata changes
  5. Custom Extensions - Extend generated classes rather than modifying them

Contributing

When contributing to this package:

  1. Test with real schemas - We generate production apps
  2. Maintain AI accuracy - Constraint translation must be perfect
  3. Performance matters - Large schemas must generate quickly
  4. Type safety is sacred - Never compromise type correctness

License

This package is part of the MemberJunction ecosystem and follows the same licensing terms.


Ready to experience the future of application development?

npm install @memberjunction/codegen-lib

Your database schema deserves better than manual code generation. Give it the AI-powered, production-ready, full-stack treatment it deserves.