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

@shing.wong/sure-factor

v0.4.0

Published

Database schema to production-grade UI — type catalog, validation, sanitization, i18n, audio, and tiered code generation.

Readme

sure-factor

Database schema → production-grade UI components. A code generation framework that introspects SQL schemas, matches columns to a typed catalog, and generates validated, sanitized, internationalized form UIs at three tiers — vibe, prototype, and production.

import { introspectSchemaFromDdl } from '@shing.wong/sure-factor/introspect'
import { matchColumnToTypeSync, loadAllTypesSync } from '@shing.wong/sure-factor'
import { generateForTier } from '@shing.wong/sure-factor/generate'

const schema = introspectSchemaFromDdl(`CREATE TABLE patients (
  id UUID PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  full_name VARCHAR(100),
  zip VARCHAR(5)
);`)

const output = generateForTier(schema, { tier: 'production', component: 'form' })
// → { routes, template, i18n, styles, validation, sanitization, ... }

Why sure-factor?

| Problem | How sure-factor solves it | |---------|--------------------------| | Forms are repetitive | SQL schema → full form UI in one step. Introspect, match, generate — no hand-written forms. | | Validation is scattered | Type definitions encode regex, length, and lookup validation per tier. Same validation for vibe (quick) and production (strict). | | Sanitization is an afterthought | Declarative pipeline per type: [trim, lowercase, normalize(NFKC), slice(0, 254)]. Input and output pipelines are separate. | | i18n is tedious | Type hints include English, Spanish, and French placeholders, help text, and error messages. Generated forms are multi-language from day one. | | Code quality varies by stage | Three tiers: vibe (quick regex), prototype (full validation + 2-3 languages), production (lookup datasets + encryption + audit). | | No standard type catalog | 15 built-in types (email, zip5, icd10, ssn, phone, url, ...) with match rules, validation, sanitization, i18n, and security policies. |

How it compares

| | sure-factor | QuickDBD / dbdiagram | Prisma | Low-Code platforms | |---|---|---|---|---| | SQL schema → UI | ✅ Full pipeline | ❌ Diagram only | ⚠️ Schema only | ❌ Proprietary DSL | | Type catalog | ✅ 15 types, YAML-defined | ❌ | ⚠️ Native types only | ❌ | | Tiered generation | ✅ vibe / prototype / production | ❌ | ❌ | ❌ | | i18n built-in | ✅ en/es/fr per type | ❌ | ❌ | ❌ | | Sanitization pipeline | ✅ Declarative input + output steps | ❌ | ❌ | ❌ | | Lookup datasets | ✅ ICD-10, ZIP codes | ❌ | ❌ | ❌ | | Audio feedback | ✅ Error bell, success chime, voice help | ❌ | ❌ | ❌ | | Export formats | ✅ HTML + CSS + JS + YAML + JSON + XML | ❌ | ❌ | ❌ | | Framework | Agnostic (generates HTML/CSS/JS) | ❌ | ❌ | ❌ | | File size | ~1 MB (catalog + engine) | N/A | ~15 MB | N/A |

Architecture

                    ┌──────────┐
   DDL or SQL ─────▶│introspect│
                    │DDL→Schema│
                    └────┬─────┘
                         │ SchemaInfo
                         ▼
                    ┌──────────┐    ┌─────────────┐
                    │  match   │◀───│catalog/types │
                    │ col→type │    │15 YAML defs  │
                    └────┬─────┘    └─────────────┘
                         │ TypeMatchResult
                         ▼
                    ┌──────────┐    ┌────────────────┐
                    │ generate │◀───│catalog/components│
                    │ tiered   │    │5 templates      │
                    │ output   │    └────────────────┘
                    └────┬─────┘
                         │ routes, template, i18n, styles,
                         │ validation, sanitization, scripts
                         ▼
                    ┌──────────┐
                    │  format  │
                    │(Prettier)│
                    └──────────┘

Three phases:

  1. Introspect — Parse DDL or query information_schema → SchemaInfo (tables, columns, types, constraints, foreign keys)
  2. Match — Match each column to catalog type definitions using name patterns + data type rules → TypeMatchResult with confidence scoring
  3. Generate — Produce tier-aware output: routes, templates, i18n, sanitization pipeline, validation rules, theme CSS, and sure-state stores

Installation

npm install @shing.wong/sure-factor

No peer dependencies. pg and prettier are regular dependencies, so live schema introspection and code formatting work without extra setup.

Requires Node >= 20.

Quick Start

import { introspectSchemaFromDdl } from '@shing.wong/sure-factor/introspect'
import { loadAllTypesSync, matchColumnToTypeSync } from '@shing.wong/sure-factor'
import { generateForTier } from '@shing.wong/sure-factor/generate'
import { generateStore } from '@shing.wong/sure-factor/generate-store'
import { sanitize } from '@shing.wong/sure-factor/sanitize'
import { convert } from '@shing.wong/sure-factor/serialize'

// 1. Introspect — parse DDL into typed schema
const schema = introspectSchemaFromDdl(`
  CREATE TABLE patients (
    id UUID PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    full_name VARCHAR(100) NOT NULL,
    diagnosis VARCHAR(8),
    zip VARCHAR(5)
  );
`)

// …or introspect a live database (the `pg` driver ships as a dependency):
// import { introspectSchema } from '@shing.wong/sure-factor'
// const live = await introspectSchema(process.env.DATABASE_URL!, ['public'])

// 2. Match — match columns to catalog types
const allTypes = loadAllTypesSync()
const emailCol = schema.tables[0]!.columns.find(c => c.columnName === 'email')!
const result = matchColumnToTypeSync(emailCol, allTypes)
// → { type: { name: 'email', confidence: 1 }, confidence: 1 }

// 3. Generate — produce tiered UI output
const output = generateForTier(schema, { tier: 'production', component: 'form' })
// → {
//     routes: "app.post('/patients', ...)",
//     template: "<form class='sure-form'>...",
//     i18n: { email_placeholder: '[email protected]', ... },
//     styles: "@layer sure.tokens, ... sure-ui compose [form, buttons]...",
//     notifications: "…showNotification() runtime… | null (inline-only)",
//     validation: "z.string().regex(/^[a-zA-Z0-9.../).max(254)",
//     sanitization: "[trim, lowercase, normalize(NFKC), ...]"
//   }

// 4. Generate a sure-state store
const store = generateStore({
  tableName: 'patients',
  columns: schema.tables[0]!.columns,
  tier: 'production',
})
// → { interfaceCode, apiCode, storeCode, fullCode }

// 5. Sanitize input
sanitize('  [email protected]  ', ['trim', 'lowercase', 'normalize(NFKC)'])
// → '[email protected]'

// 6. Serialize between formats
convert(yamlString, 'yaml', 'json')   // YAML → JSON
convert(jsonString, 'json', 'md')     // JSON → Markdown

Type Catalog

15 built-in type definitions in catalog/types/:

| Type | Match patterns | Validation | Sanitization | Security | |------|---------------|------------|--------------|----------| | email | %email%, %mail% | RFC 5322 regex | trim, lowercase, normalize(NFKC) | Unicode normalization | | zip5 | %zip%, %postal% | ^\d{5}$ | stripNonDigits, slice(5) | — | | zip9 | %zip9%, %zip+4% | ^\d{5}-\d{4}$ | format to 5+4 | — | | ssn | %ssn%, %social% | ^\d{3}-\d{2}-\d{4}$ | stripNonDigits, format | Encrypt at rest | | ein | %ein% | ^\d{2}-\d{7}$ | stripNonDigits, format | Encrypt at rest | | full-name | %name%, %full_name% | 2-100 chars | collapseWhitespace, title case | — | | icd10 | %diagnosis%, %icd%, %code% | ^[A-Z]\d{2}\.\d{1,2}$ | uppercase | Lookup dataset | | intl-phone | %phone% | E.164 | stripNonDigits | — | | us-phone | %phone% with US hint | ^\d{10}$ | format (XXX) XXX-XXXX | — | | us-address | %address%, %street% | Multi-line | collapseWhitespace | — | | date-iso | %date%, %created% | ISO 8601 | trim | — | | date-us | %date% with US hint | MM/DD/YYYY | format | — | | password | %password%, %pwd% | 8+ chars, complexity | N/A (hash server-side) | Bcrypt | | credit-card | %card%, %cc% | Luhn check | stripNonDigits | Encrypt at rest | | url | %url%, %website% | URL regex | trim, lowercase | — |

Example type definition

# catalog/types/email.yaml
name: email
description: Email address conforming to RFC 5322
match:
  sql: column_name LIKE '%email%' OR column_name LIKE '%mail%'
  regex: ^[^@]+@[^@]+\.[^@]+$
  maxLength: 254
validation:
  regex: ^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$
  maxLength: 254
sanitize:
  input: [trim, lowercase, normalize(NFKC), slice(0, 254)]
  output: [htmlEscape]
hints:
  en: { placeholder: '[email protected]', help: 'Email address' }
  es: { placeholder: '[email protected]', help: 'Dirección de correo' }
  fr: { placeholder: '[email protected]', help: 'Adresse e-mail' }
tiers:
  vibe:
    validation: { regex: ^[^@]+@[^@]+\.[^@]+$ }
    sanitize: [trim, lowercase]
  prototype:
    validation: { regex: [full RFC], maxLength: 254 }
    sanitize: [trim, lowercase, normalize(NFKC), slice(254)]
    hints: { en, es }
  production:
    validation: { regex: [full RFC], maxLength: 254, lookup: null }
    sanitize: [trim, lowercase, normalize(NFKC), slice(254)]
    hints: { en, es, fr }
security:
  encrypt: false
  notes:
    - 'Normalize Unicode NFKC to prevent homoglyph attacks'
    - 'Lowercase to ensure case-insensitive matching'

Component Catalog

5 component templates in catalog/components/:

| Component | Description | Notification Modes | CSS Classes | |-----------|-------------|-------------------|-------------| | form | Single-column create/edit form | inline, toast, statusBar, sidePanel | .sure-form__* | | form-modal | Modal dialog form | inline, toast, statusBar | .sure-modal__* | | data-table | Read-only data table | toast | .sure-table__* | | crud-resource | Full CRUD with table + modal | inline, toast, statusBar, sidePanel | .sure-crud__* | | search-filter | Search with filter controls | inline, toast | .sure-search__* |

Tiers

Generation progresses through three quality tiers — same schema, different output depth:

| Feature | Vibe | Prototype | Production | |---------|------|-----------|------------| | Validation | Basic regex | Type + regex + DB constraints | Full + lookup datasets | | Sanitization | Trim + escape | Full input pipeline | + DOMPurify for rich text | | i18n | English | en + es | en + es + fr | | Notifications | Inline | inline + toast + statusBar | All 4 modes | | Audio | None | Error bell | Chime + speech | | Security | Param queries | + CSRF | + Encryption + audit | | State sync | — | — | sure-state + versioning | | CSS themes | sure-ui compose (7 themes) | sure-ui compose (7 themes) | sure-ui compose (7 themes) |

Sanitization Pipeline

Declarative step functions that compose into input and output pipelines:

import { sanitize, sanitizeInput, sanitizeOutput } from '@shing.wong/sure-factor/sanitize'

// Available steps: trim, lowercase, uppercase, stripNonDigits,
//   stripDirectionOverrides, stripZeroWidth, stripControl,
//   collapseWhitespace, htmlEscape, normalize(form), slice(n)

sanitize('  [email protected]  ', ['trim', 'lowercase', 'normalize(NFKC)'])
// → '[email protected]'

sanitize('<script>alert("xss")</script>', ['htmlEscape'])
// → '&lt;script&gt;alert(&quot;xss&quot;)&lt;&#x2F;script&gt;'

Rich text output

sanitizeOutput(value, true) filters rich text through a tag and attribute allowlist rather than passing it through:

sanitizeOutput('<p>hi <strong>there</strong></p>', true)
// → '<p>hi <strong>there</strong></p>'

sanitizeOutput('<img src=x onerror=alert(1)>', true)
// → ''  (element dropped)

sanitizeOutput('<a href="javascript:alert(1)">x</a>', true)
// → '<a>x</a>'  (unsafe URL dropped)

Permitted elements are a, b, blockquote, br, code, del, em, h1-h6, hr, i, li, ol, p, pre, s, span, strong, sub, sup, u and ul, with class/title on any element and href/title/rel/target on links. Everything else — including table, img, form and every on* handler — is dropped. This was a pass-through before 0.2.0; see CHANGELOG.md before upgrading.

Serialization

Convert between YAML, JSON, XML, and Markdown — useful for exporting catalog definitions:

import { convert, toYaml, toJson, fromJson, toMarkdown, toXml, fromXml } from '@shing.wong/sure-factor/serialize'

convert(yamlString, 'yaml', 'json')    // YAML → JSON
convert(jsonString, 'json', 'yaml')    // JSON → YAML
convert(yamlString, 'yaml', 'xml')     // YAML → XML
convert(xmlString, 'xml', 'md')        // XML → Markdown

Store Generation

Generate a sure-state compatible store from a schema:

import { generateStore } from '@shing.wong/sure-factor/generate-store'

const store = generateStore({
  tableName: 'patients',
  columns: schema.tables[0]!.columns,
  tier: 'production',
  sync: 'server-first',
  versioning: true,
})

// store.interfaceCode — TypeScript interface
// store.apiCode — API client methods
// store.storeCode — sure-state createEntityStore call
// store.fullCode — complete file

Formatting

Generated output can be formatted via Prettier:

import { formatCode, formatGeneratedOutput, formatGeneratedStoreOutput } from '@shing.wong/sure-factor/format'

const formatted = await formatGeneratedOutput(output)
// → same as output, but with formattedRoutes, formattedTemplate, etc.

Assets

| Asset | Path | Description | |-------|------|-------------| | i18n | catalog/assets/i18n/{en,es,fr}.json | Locale strings for components | | Audio | catalog/assets/audio/ | Error bell, success chime, voice help (JS audio generators) | | Lookup data | catalog/assets/data/{icd10-codes,us-zip-codes}.json | Validation datasets | | Agent skill | .opencode/skills/sure-factor/SKILL.md | How an agent should drive this package |

Theme CSS is not vendored: styles is composed on demand from @shing.wong/sure-ui — pass any of its seven themes via generateForTier(schema, { theme: 'forest' }).

Agent skill

The package ships an OpenCode skill covering the parts of this API that are not obvious from the signatures — scoping the DDL before introspecting it, taking columns out of the schema rather than constructing them, reading the catalog YAML instead of dumping the loader, and editing the spec rather than the generated output.

Point OpenCode at it from your opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "skills": ["./node_modules/@shing.wong/sure-factor/.opencode/skills"]
}

Only the skill's name and description are loaded up front; the body is read when the agent decides the skill applies. Its claims are executed by this package's test suite, so it cannot drift from the code without a test failing.

It is plain Markdown — copy it anywhere you prefer to keep instructions, or point the skills array at any local directory or HTTP catalog.

Related Projects

| Project | Role | |---------|------| | sure-ui | Theme CSS + notification runtime for generated output | | sure-state | Client-server state sync (Zustand + WebSocket) | | sure-gentic | Agent framework for LLM-powered code generation | | sure-web-testing | Browser testing via MCP for generated UIs |

Development

git clone [email protected]:ShingWong/sure-factor.git
cd sure-factor
npm install
npm run build
npm test                 # 176 tests (173 unit + 3 Playwright render)
npm run test:unit        # 173, no browser required
npm run test:e2e         # 3, needs `npx playwright install chromium`
npm run lint             # tsc --noEmit, includes test files
npm run verify           # lint + build + test + export check (what CI runs)

npm run test:e2e runs only the tests under src/e2e/, which drive a real Chromium. npm run test:unit covers everything else and needs no browser.