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

@constela/ai

v8.0.0

Published

AI provider abstraction layer for Constela DSL

Readme

@constela/ai

AI-powered DSL generation for Constela. Generate UI components and views from natural language prompts.

Installation

npm install @constela/ai

Quick Start

Generate a component from a natural language description:

import { createDslGenerator } from '@constela/ai';

const generator = createDslGenerator({
  provider: 'anthropic', // or 'openai'
});

const result = await generator.generate({
  prompt: 'Create a card component with title, description, and action button',
  output: 'component',
});

console.log(result.dsl);
// {
//   "kind": "element",
//   "tag": "div",
//   "props": { "class": "card" },
//   "children": [...]
// }

Environment Variables

Set your API key:

# For Anthropic (Claude)
export ANTHROPIC_API_KEY=sk-ant-...

# For OpenAI
export OPENAI_API_KEY=sk-...

Features

AI Providers

Two providers are supported:

| Provider | Model | Environment Variable | |----------|-------|---------------------| | Anthropic | Claude Sonnet | ANTHROPIC_API_KEY | | OpenAI | GPT-4o | OPENAI_API_KEY |

// Use Anthropic
const generator = createDslGenerator({ provider: 'anthropic' });

// Use OpenAI
const generator = createDslGenerator({ provider: 'openai' });

Output Types

Generate different types of DSL:

// Generate a reusable component
const component = await generator.generate({
  prompt: 'A notification badge with count',
  output: 'component',
});

// Generate a full page/view
const view = await generator.generate({
  prompt: 'A user profile page with avatar, bio, and recent posts',
  output: 'view',
});

Security Validation

All generated DSL is automatically validated:

Forbidden Tags (blocked by default):

  • script, iframe, object, embed, form

Forbidden Actions (cannot be used even with whitelist):

  • import, call, dom

Restricted Actions (require explicit whitelist):

  • fetch

URL Validation:

  • Blocks javascript:, data:, vbscript: schemes
  • Supports domain whitelisting
const generator = createDslGenerator({
  provider: 'anthropic',
  security: {
    allowedTags: ['a', 'button', 'input'],
    allowedActions: ['set', 'update', 'navigate'],
    allowedUrlPatterns: ['https://api.example.com/*'],
    maxNestingDepth: 32,
  },
});

Generation Context

Provide context for more accurate generation:

const generator = createDslGenerator({
  provider: 'anthropic',
  context: {
    existingComponents: ['Button', 'Card', 'Input'],
    theme: { primaryColor: '#3b82f6' },
    schema: { user: { name: 'string', email: 'string' } },
  },
});

CLI: Suggest Command

Analyze DSL files for improvements:

# Analyze for accessibility issues
constela suggest app.json --aspect accessibility

# Analyze for performance
constela suggest app.json --aspect performance

# Analyze for security
constela suggest app.json --aspect security

# Analyze for UX
constela suggest app.json --aspect ux

# Use OpenAI instead of Anthropic
constela suggest app.json --aspect accessibility --provider openai

# Output as JSON
constela suggest app.json --aspect ux --json

Example output:

=== Suggestions for app.json (accessibility) ===

[HIGH] Missing aria-label on button
   Recommendation: Add aria-label="Submit form" to the button element
   Location: view.children[0].props

[MED] Low color contrast in text
   Recommendation: Increase contrast ratio to meet WCAG AA standards
   Location: view.children[2].props.style

Total: 2 suggestion(s)

DSL Data Source

Use AI to generate content at build time:

{
  "version": "1.0",
  "data": {
    "hero": {
      "type": "ai",
      "provider": "anthropic",
      "prompt": "Create a hero section with gradient background and CTA",
      "output": "component"
    }
  },
  "view": {
    "kind": "component",
    "name": "hero",
    "props": {}
  }
}

Generate Action

Generate DSL at runtime in response to user actions:

{
  "actions": [
    {
      "name": "generateCard",
      "steps": [
        {
          "do": "generate",
          "provider": "anthropic",
          "prompt": { "expr": "state", "name": "userPrompt" },
          "output": "component",
          "result": "generatedCard",
          "onSuccess": [
            { "do": "set", "target": "card", "value": { "expr": "var", "name": "generatedCard" } }
          ],
          "onError": [
            { "do": "set", "target": "error", "value": { "expr": "lit", "value": "Generation failed" } }
          ]
        }
      ]
    }
  ]
}

API Reference

createDslGenerator(options)

Creates a new DSL generator instance.

interface DslGeneratorOptions {
  provider: 'anthropic' | 'openai';
  providerInstance?: AiProvider;  // Custom provider instance
  security?: SecurityOptions;
  context?: GenerationContext;
}

generator.generate(options)

Generates DSL from a prompt.

interface GenerateOptions {
  prompt: string;
  output: 'component' | 'view' | 'suggestion';
  context?: GenerationContext;
  security?: SecurityOptions;
}

interface GenerateResult {
  dsl: Record<string, unknown>;
  raw: string;
  validated: boolean;
  errors?: string[];
}

generator.validate(dsl, security?)

Validates DSL against security rules.

const result = generator.validate(dsl, {
  allowedTags: ['div', 'span', 'button'],
});

if (!result.valid) {
  console.error('Validation errors:', result.errors);
}

Direct Provider Access

import { getProvider, AnthropicProvider, OpenAIProvider } from '@constela/ai';

// Get provider by type
const provider = getProvider('anthropic');

// Or create directly
const anthropic = new AnthropicProvider({ model: 'claude-sonnet-4-20250514' });
const openai = new OpenAIProvider({ model: 'gpt-4o' });

const response = await provider.generate('Generate a button component', {
  systemPrompt: 'You are a UI component generator...',
  maxTokens: 4096,
  temperature: 0.7,
});

Security Utilities

import {
  isForbiddenTag,
  isForbiddenAction,
  isRestrictedAction,
  validateUrl,
  FORBIDDEN_TAGS,
  FORBIDDEN_ACTIONS,
} from '@constela/ai';

// Check if tag is forbidden
isForbiddenTag('script'); // true
isForbiddenTag('div');    // false

// Validate URL
const result = validateUrl('https://example.com/api', {
  allowedDomains: ['example.com'],
  allowRelative: true,
});

Error Handling

import { AiError, ValidationError, SecurityError } from '@constela/ai';

try {
  const result = await generator.generate({ prompt, output: 'component' });
} catch (err) {
  if (err instanceof SecurityError) {
    console.error('Security violation:', err.violation);
  } else if (err instanceof ValidationError) {
    console.error('Validation failed:', err.violations);
  } else if (err instanceof AiError) {
    console.error('AI error:', err.code, err.message);
  }
}

Error codes:

  • PROVIDER_NOT_CONFIGURED - API key not set
  • PROVIDER_NOT_FOUND - Unknown provider type
  • API_ERROR - Provider API call failed
  • VALIDATION_ERROR - Generated DSL validation failed
  • SECURITY_VIOLATION - Security rule violated
  • RATE_LIMIT_EXCEEDED - API rate limit hit

License

MIT