Skip to content

Atscript

Types, validation, databases — from one source.

Define once. Validate, query, and generate everywhere.

Atscript

You've written this type three times today.

Once in Drizzle. Once in Zod. Once in your UI config. Atscript replaces all of them.

Before 3 files
db/schema.ts
ts
import { pgTable, serial, varchar, integer, uniqueIndex } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull(),
  name: varchar('name', { length: 100 }).notNull(),
  age: integer('age').notNull(),
  role: varchar('role', { enum: ['admin', 'user'] }),
}, (t) => [uniqueIndex().on(t.email)])
validation/user.schema.ts
ts
import { createInsertSchema } from 'drizzle-zod'
import { users } from '../db/schema'

export const insertUserSchema = createInsertSchema(users, {
  email: (s) => s.email.email(),
  name: (s) => s.name.min(2).max(100),
  age: (s) => s.age.positive(),
})
components/UserForm.tsx
tsx
const fieldConfig = {
  email: { label: 'Email Address', placeholder: 'alice@company.com' },
  name:  { label: 'Full Name', placeholder: 'Alice Smith' },
  age:   { label: 'Age', type: 'number' },
  role:  { label: 'Role', component: 'select' },
}
After 1 file
user.as
atscript
@db.table 'users'
export interface User {
  @db.id
  id: number

  @meta.label "Email Address"
  @ui.placeholder "alice@company.com"
  @db.index.unique 'email_idx'
  email: string.email

  @meta.label "Full Name"
  @ui.placeholder "Alice Smith"
  @expect.minLength 2
  @expect.maxLength 100
  @db.index.fulltext 'search_idx'
  name: string

  @meta.label "Age"
  age: number.int.positive

  @meta.label "Role"
  @ui.component "select"
  role?: 'admin' | 'user'
}

@meta.* annotations are built-in. @db.* annotations power real database integrations. Add your own via the plugin system.

TypeScript Types
+
Runtime Validators
+
JSON Schema
+
DB Schemas
+
Rich Metadata

Released under the ISC License.