typion 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +4 -2
- package/bin/typion.js +7 -0
- package/dist/auth/better-auth.d.ts +13 -0
- package/dist/auth/better-auth.js +11 -0
- package/dist/auth/better-auth.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +883 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/column-kinds-Bkm4NJI2.js +47 -0
- package/dist/column-kinds-Bkm4NJI2.js.map +1 -0
- package/dist/context-B4e2eREP.d.ts +2100 -0
- package/dist/contract/index.d.ts +137 -0
- package/dist/contract/index.js +42 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/db/pglite.d.ts +12 -0
- package/dist/db/pglite.js +27 -0
- package/dist/db/pglite.js.map +1 -0
- package/dist/descriptor-Cc3mGp73.js +12 -0
- package/dist/descriptor-Cc3mGp73.js.map +1 -0
- package/dist/errors-ChDBxeS-.js +17 -0
- package/dist/errors-ChDBxeS-.js.map +1 -0
- package/dist/errors-D-CKO-px.js +114 -0
- package/dist/errors-D-CKO-px.js.map +1 -0
- package/dist/handler-BWVU8TCR.d.ts +23 -0
- package/dist/handler-_87bFkbP.js +565 -0
- package/dist/handler-_87bFkbP.js.map +1 -0
- package/dist/hono/index.d.ts +17 -0
- package/dist/hono/index.js +26 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/http/index.d.ts +13 -0
- package/dist/http/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1324 -0
- package/dist/index.js.map +1 -0
- package/dist/issues-DLqCBQT1.js +42 -0
- package/dist/issues-DLqCBQT1.js.map +1 -0
- package/dist/next/index.d.ts +8 -0
- package/dist/next/index.js +18 -0
- package/dist/next/index.js.map +1 -0
- package/dist/operations-D3rOacLX.js +1811 -0
- package/dist/operations-D3rOacLX.js.map +1 -0
- package/dist/schema/index.d.ts +18 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema-Rzzq97cK.js +68 -0
- package/dist/schema-Rzzq97cK.js.map +1 -0
- package/dist/seed/index.d.ts +19 -0
- package/dist/seed/index.js +85 -0
- package/dist/seed/index.js.map +1 -0
- package/dist/structural-BZnjFmCs.js +247 -0
- package/dist/structural-BZnjFmCs.js.map +1 -0
- package/dist/testing/index.d.ts +26 -0
- package/dist/testing/index.js +92 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/typion-Dh2BCSRz.js +1187 -0
- package/dist/typion-Dh2BCSRz.js.map +1 -0
- package/dist/validation/zod.d.ts +21 -0
- package/dist/validation/zod.js +84 -0
- package/dist/validation/zod.js.map +1 -0
- package/docs/README.md +145 -0
- package/docs/access.md +114 -0
- package/docs/auth.md +195 -0
- package/docs/collections.md +172 -0
- package/docs/database.md +76 -0
- package/docs/features/localization.md +112 -0
- package/docs/features/multi-tenant.md +166 -0
- package/docs/features/soft-delete.md +85 -0
- package/docs/features/versions.md +106 -0
- package/docs/hooks.md +106 -0
- package/docs/http.md +188 -0
- package/docs/queries.md +200 -0
- package/docs/testing.md +85 -0
- package/package.json +125 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["run","db.push","db.generate","db.migrate","db.seed","db.status","db.studio"],"sources":["../../src/cli/output.ts","../../src/cli/config.ts","../../src/cli/db.ts","../../src/cli/agents.ts","../../src/cli/init.ts","../../src/cli/make.ts","../../src/cli/index.ts"],"sourcesContent":["// A failure the user can act on: the CLI prints its message without a stack.\nexport class CliError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CliError'\n }\n}\n\nexport type Io = {\n out(line: string): void\n err(line: string): void\n}\n\nexport const consoleIo: Io = {\n out: (line) => console.log(line),\n err: (line) => console.error(line),\n}\n","import { existsSync } from 'node:fs'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { TypionConfig } from '../types/collection.js'\nimport { CliError } from './output.js'\n\nconst NAMES = ['typion.config.ts', 'typion.config.js', 'typion.config.mts', 'typion.config.mjs']\nconst DIRS = ['', 'src', 'app', 'config']\n\nexport type LoadedConfig = {\n readonly config: TypionConfig<any>\n readonly path: string\n readonly dir: string\n}\n\nexport function findConfig(cwd: string, given?: string): string {\n if (given !== undefined) {\n const path = isAbsolute(given) ? given : resolve(cwd, given)\n if (!existsSync(path)) throw new CliError(`No config at ${path}`)\n return path\n }\n let dir = resolve(cwd)\n for (;;) {\n for (const sub of DIRS) {\n for (const name of NAMES) {\n const candidate = join(dir, sub, name)\n if (existsSync(candidate)) return candidate\n }\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n throw new CliError(\n `No typion.config.ts found from ${cwd}. Pass --config <path>, or run \\`typion init\\`.`,\n )\n}\n\n// Node runs TypeScript directly (type stripping), which covers a config written with relative imports. A\n// project whose config uses path aliases (`@/…`) needs jiti, so it is used when the project has it.\nasync function importConfig(path: string): Promise<Record<string, unknown>> {\n try {\n return await withoutTypelessWarning(\n async () => (await import(pathToFileURL(path).href)) as Record<string, unknown>,\n )\n } catch (error) {\n const jiti = await loadJiti(path)\n if (jiti === null) throw error\n return (await jiti.import(path, {})) as Record<string, unknown>\n }\n}\n\n// A project without `\"type\": \"module\"` (a Next.js app) makes Node warn, once per command, that it parsed the config\n// twice to find it is a module: true, and nothing the user can act on without changing how their app is built.\nasync function withoutTypelessWarning<T>(load: () => Promise<T>): Promise<T> {\n const emit = process.emitWarning\n process.emitWarning = ((warning: string | Error, ...rest: unknown[]) => {\n const code = (rest[0] as { code?: string } | undefined)?.code ?? rest[1]\n if (code === 'MODULE_TYPELESS_PACKAGE_JSON') return\n ;(emit as (...args: unknown[]) => void).call(process, warning, ...rest)\n }) as typeof process.emitWarning\n try {\n return await load()\n } finally {\n process.emitWarning = emit\n }\n}\n\ntype Jiti = { import(id: string, opts: object): unknown }\n\nasync function loadJiti(path: string): Promise<Jiti | null> {\n try {\n // Optional, and resolved through a variable so it is not a dependency of the build: a project whose\n // config needs path aliases usually has jiti already (drizzle-kit ships it).\n const id = 'jiti'\n const mod = (await import(id)) as { createJiti: (from: string, options?: object) => Jiti }\n return mod.createJiti(pathToFileURL(path).href, { interopDefault: true })\n } catch {\n return null\n }\n}\n\nfunction pickConfig(exports: Record<string, unknown>, path: string): TypionConfig<any> {\n const candidates = [exports.config, exports.default, ...Object.values(exports)]\n for (const value of candidates) {\n if (\n typeof value === 'object' &&\n value !== null &&\n 'definition' in value &&\n 'schema' in value &&\n typeof (value as { definition?: unknown }).definition === 'object'\n ) {\n return value as TypionConfig<any>\n }\n }\n throw new CliError(\n `${path} exports no Typion config (expected \\`export const config = defineConfig(…)\\`)`,\n )\n}\n\n// A config reads `process.env.DATABASE_URL`, and Next.js, Vite and drizzle-kit read `.env` files for it: the CLI does\n// too, `.env.local` first so that it wins, and never over what the shell already set.\nfunction loadEnv(dir: string): void {\n for (const name of ['.env.local', '.env']) {\n const path = join(dir, name)\n if (existsSync(path)) process.loadEnvFile(path)\n }\n}\n\nexport async function loadConfig(cwd: string, given?: string): Promise<LoadedConfig> {\n loadEnv(cwd)\n const path = findConfig(cwd, given)\n const exports = await importConfig(path)\n return { config: pickConfig(exports, path), path, dir: dirname(path) }\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { sql } from 'drizzle-orm'\nimport type { PgAsyncDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core'\nimport { getTableConfig, PgTable } from 'drizzle-orm/pg-core'\nimport { is } from 'drizzle-orm'\nimport type { LoadedConfig } from './config.js'\nimport { CliError, type Io } from './output.js'\n\nconst BREAKPOINT = '--> statement-breakpoint'\nconst DEFAULT_DIR = 'typion/migrations'\nconst DEFAULT_TABLE = 'typion_migrations'\n\ntype Journal = { version: 1; entries: { idx: number; tag: string; createdAt: string }[] }\n\ntype Api = typeof import('drizzle-kit/api-postgres')\n\nasync function api(): Promise<Api> {\n try {\n return (await import('drizzle-kit/api-postgres')) as Api\n } catch {\n throw new CliError(\n 'The database commands need drizzle-kit installed (`pnpm add -D drizzle-kit`)',\n )\n }\n}\n\nfunction schemaOf(loaded: LoadedConfig): Record<string, unknown> {\n return loaded.config.schema as Record<string, unknown>\n}\n\n// Migrations belong to the project, not to the folder the config happens to sit in, so they are resolved\n// from the nearest package.json above it.\nfunction projectRoot(loaded: LoadedConfig): string {\n let dir = loaded.dir\n for (;;) {\n if (existsSync(join(dir, 'package.json'))) return dir\n const parent = dirname(dir)\n if (parent === dir) return loaded.dir\n dir = parent\n }\n}\n\nfunction migrationsDir(loaded: LoadedConfig): string {\n const dir = loaded.config.migrations?.dir ?? DEFAULT_DIR\n return isAbsolute(dir) ? dir : resolve(projectRoot(loaded), dir)\n}\n\nfunction migrationsTable(loaded: LoadedConfig): { schema: string; table: string } {\n return {\n schema: loaded.config.migrations?.schema ?? 'public',\n table: loaded.config.migrations?.table ?? DEFAULT_TABLE,\n }\n}\n\nfunction readJournal(dir: string): Journal {\n try {\n return JSON.parse(readFileSync(join(dir, 'meta', 'journal.json'), 'utf8')) as Journal\n } catch {\n return { version: 1, entries: [] }\n }\n}\n\nfunction writeJournal(dir: string, journal: Journal): void {\n mkdirSync(join(dir, 'meta'), { recursive: true })\n writeFileSync(join(dir, 'meta', 'journal.json'), `${JSON.stringify(journal, null, 2)}\\n`)\n}\n\nfunction connect(loaded: LoadedConfig): PgAsyncDatabase<PgQueryResultHKT, any> {\n const adapter = loaded.config.db\n if (adapter === undefined) {\n throw new CliError('The config has no database adapter (`db` in defineConfig)')\n }\n adapter.check?.()\n return adapter.connect(loaded.config.definition.relations)\n}\n\nexport async function push(loaded: LoadedConfig, io: Io, options: { force?: boolean }) {\n const { pushSchema } = await api()\n const db = connect(loaded)\n const { sqlStatements, hints, apply } = await pushSchema(schemaOf(loaded), db as never)\n if (sqlStatements.length === 0) {\n io.out('The database already matches the config.')\n return\n }\n for (const statement of sqlStatements) io.out(statement)\n if (hints.length > 0) {\n for (const hint of hints) io.err(`! ${hint.hint}`)\n if (options.force !== true) {\n throw new CliError('These changes can lose data: run again with --force to apply them.')\n }\n }\n await apply()\n io.out(`Applied ${sqlStatements.length} statement(s).`)\n await loaded.config.db?.close?.()\n}\n\nexport async function generate(loaded: LoadedConfig, io: Io, options: { name?: string }) {\n const { generateDrizzleJson, generateMigration } = await api()\n const dir = migrationsDir(loaded)\n const journal = readJournal(dir)\n const last = journal.entries.at(-1)\n const previous =\n last === undefined\n ? await generateDrizzleJson({})\n : (JSON.parse(\n readFileSync(\n join(dir, 'meta', `${String(last.idx).padStart(4, '0')}_snapshot.json`),\n 'utf8',\n ),\n ) as Awaited<ReturnType<typeof generateDrizzleJson>>)\n const current = await generateDrizzleJson(schemaOf(loaded), previous.id)\n const statements = await generateMigration(previous, current)\n if (statements.length === 0) {\n io.out('No changes: the migrations already describe the config.')\n return\n }\n const idx = (last?.idx ?? -1) + 1\n const tag = `${String(idx).padStart(4, '0')}_${(options.name ?? 'change').replace(/[^a-z0-9_-]+/gi, '_')}`\n mkdirSync(join(dir, 'meta'), { recursive: true })\n writeFileSync(join(dir, `${tag}.sql`), `${statements.join(`\\n${BREAKPOINT}\\n`)}\\n`)\n writeFileSync(\n join(dir, 'meta', `${String(idx).padStart(4, '0')}_snapshot.json`),\n `${JSON.stringify(current, null, 2)}\\n`,\n )\n journal.entries.push({ idx, tag, createdAt: new Date().toISOString() })\n writeJournal(dir, journal)\n io.out(`Wrote ${tag}.sql with ${statements.length} statement(s).`)\n}\n\nasync function applied(\n db: PgAsyncDatabase<PgQueryResultHKT, any>,\n where: { schema: string; table: string },\n): Promise<Set<string>> {\n if (where.schema !== 'public') {\n await db.execute(sql.raw(`create schema if not exists \"${where.schema}\"`))\n }\n await db.execute(\n sql.raw(\n `create table if not exists \"${where.schema}\".\"${where.table}\" (` +\n 'tag text primary key, applied_at timestamptz not null default now())',\n ),\n )\n const rows = await db.execute(sql.raw(`select tag from \"${where.schema}\".\"${where.table}\"`))\n const list =\n (rows as unknown as { rows?: { tag: string }[] }).rows ?? (rows as unknown as { tag: string }[])\n return new Set(list.map((row) => row.tag))\n}\n\nexport async function migrate(loaded: LoadedConfig, io: Io) {\n const dir = migrationsDir(loaded)\n const journal = readJournal(dir)\n if (journal.entries.length === 0) {\n io.out('No migrations to apply: run `typion db generate` first.')\n return\n }\n const db = connect(loaded)\n const where = migrationsTable(loaded)\n const done = await applied(db, where)\n const pending = journal.entries.filter((entry) => !done.has(entry.tag))\n if (pending.length === 0) {\n io.out('The database is up to date.')\n await loaded.config.db?.close?.()\n return\n }\n for (const entry of pending) {\n const statements = readFileSync(join(dir, `${entry.tag}.sql`), 'utf8')\n .split(BREAKPOINT)\n .map((statement) => statement.trim())\n .filter((statement) => statement !== '')\n await db.transaction(async (tx) => {\n for (const statement of statements) await tx.execute(sql.raw(statement))\n await tx.execute(\n sql.raw(`insert into \"${where.schema}\".\"${where.table}\" (tag) values ('${entry.tag}')`),\n )\n })\n io.out(`Applied ${entry.tag} (${statements.length} statement(s)).`)\n }\n await loaded.config.db?.close?.()\n}\n\nconst SEED_FILES = ['typion/seed.ts', 'typion/seed.js', 'seed.ts', 'seed.js']\n\nfunction findSeedFile(loaded: LoadedConfig, given?: string): string | null {\n if (given !== undefined) {\n const path = isAbsolute(given) ? given : resolve(process.cwd(), given)\n if (!existsSync(path)) throw new CliError(`No seed file at ${path}`)\n return path\n }\n for (const dir of [projectRoot(loaded), loaded.dir]) {\n for (const name of SEED_FILES) {\n const candidate = join(dir, name)\n if (existsSync(candidate)) return candidate\n }\n }\n return null\n}\n\n// Two ways to fill a database, and they answer different needs: the project's own seed writes meaningful rows\n// through the engine (hooks, versions and validation included), `--random` asks drizzle-seed for plausible\n// ones straight into the tables.\nasync function anyRows(loaded: LoadedConfig): Promise<boolean> {\n const db = connect(loaded)\n for (const entity of Object.values(loaded.config.definition.entities)) {\n if (entity.owner !== 'user') continue\n const where = `\"${entity.pgSchema ?? 'public'}\".\"${entity.tableName}\"`\n const rows = await db.execute(sql.raw(`select 1 from ${where} limit 1`))\n const list = (rows as unknown as { rows?: unknown[] }).rows ?? (rows as unknown as unknown[])\n if (list.length > 0) return true\n }\n return false\n}\n\nexport async function seed(\n loaded: LoadedConfig,\n io: Io,\n options: {\n file?: string\n random?: boolean\n count?: number\n seed?: number\n reset?: boolean\n ifEmpty?: boolean\n },\n) {\n if (options.ifEmpty === true && (await anyRows(loaded))) {\n io.out('The collections already hold rows: nothing seeded.')\n await loaded.config.db?.close?.()\n return\n }\n const { resetTables, seedCollections } = await import('../seed/index.js')\n if (options.reset === true) {\n await resetTables(loaded.config)\n io.out('Emptied every table of the config.')\n }\n if (options.random === true) {\n await seedCollections(loaded.config, { count: options.count, seed: options.seed })\n io.out(`Seeded every collection with ${options.count ?? 10} rows.`)\n await loaded.config.db?.close?.()\n return\n }\n const file = findSeedFile(loaded, options.file)\n if (file === null) {\n throw new CliError(\n 'No seed file found (typion/seed.ts). Write one, point at it with --file, or use --random.',\n )\n }\n const { getTypion } = await import('../runtime/typion.js')\n const typion = await getTypion(loaded.config)\n const seedModule = (await import(pathToFileURL(file).href)) as Record<string, unknown>\n const run = (seedModule.seed ?? seedModule.default) as\n ((args: { typion: unknown; config: unknown }) => unknown) | undefined\n if (typeof run !== 'function') {\n throw new CliError(\n `${file} exports no seed function (\\`export async function seed({ typion })\\`)`,\n )\n }\n await run({ typion, config: loaded.config })\n io.out(`Ran ${file}.`)\n await loaded.config.db?.close?.()\n}\n\nexport async function status(loaded: LoadedConfig, io: Io) {\n const dir = migrationsDir(loaded)\n const journal = readJournal(dir)\n const db = connect(loaded)\n const done = await applied(db, migrationsTable(loaded))\n if (journal.entries.length === 0) io.out('No migrations yet.')\n for (const entry of journal.entries) {\n io.out(`${done.has(entry.tag) ? 'applied' : 'pending'} ${entry.tag}`)\n }\n const tables = Object.values(schemaOf(loaded)).filter((value) => is(value, PgTable)) as PgTable[]\n io.out(\n `${tables.length} table(s) in the config: ${tables.map((t) => getTableConfig(t).name).join(', ')}`,\n )\n await loaded.config.db?.close?.()\n}\n\nexport async function studio(loaded: LoadedConfig, io: Io, options: { port?: number }) {\n const { startStudioServer } = await api()\n const credentials = loaded.config.db?.credentials?.()\n if (credentials === undefined) {\n throw new CliError(\n 'This database adapter cannot open Studio: pass `url` to dbAdapter(), or use typion/db/pglite.',\n )\n }\n io.out(`Studio on https://local.drizzle.studio (port ${options.port ?? 4983})`)\n await startStudioServer(schemaOf(loaded), credentials as never, { port: options.port })\n}\n\nexport function listMigrations(dir: string): string[] {\n try {\n return readdirSync(dir).filter((name) => name.endsWith('.sql'))\n } catch {\n return []\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport type { Io } from './output.js'\n\n// Agents do not know Typion from training, so the application's agent notes carry the rules that must always hold\n// and point at the guide shipped with the installed version. The block is delimited so that it can be rewritten\n// without touching the rest of the file, the way Next.js maintains its own (`next dev`).\nexport const START_MARKER = '<!-- BEGIN:typion-agent-rules -->'\nexport const END_MARKER = '<!-- END:typion-agent-rules -->'\n\nexport const AGENT_RULES = `${START_MARKER}\n\n# Typion\n\nThis application's data layer is Typion, which is newer than your training data. Before you add or change a\ncollection, an access rule, a hook, a query or an API route, read \\`node_modules/typion/docs/README.md\\` (resolved\nfrom this file's directory) and the page it points to for the task.\n\n- Read and write the application's data through Typion, bound to the caller: \\`getApp(config)\\` on Next.js,\n \\`c.var.typion\\` on Hono, \\`typion.$fromRequest(request)\\` elsewhere, \\`typion.$as(ctx)\\`. Never through\n \\`typion.$db\\`, Drizzle or SQL: they skip the access rules, tenants, soft delete, drafts, hooks and the history.\n- \\`typion.$system({ reason })\\` skips the access rules: for seeds, jobs and webhooks, never to answer a user's\n request.\n- Authorization lives in each collection's \\`access\\` rules, deny by default, not in pages, routes or server\n actions.\n- Every schema change ships a migration: \\`typion db generate --name <change>\\`.\n\nThis block is written by \\`typion init\\`; run it again after upgrading Typion.\n\n${END_MARKER}`\n\nconst SKILL_MARKER =\n '<!-- Written by `typion init`, which rewrites it: keep project notes in AGENTS.md. -->'\n\nexport const SKILL = `---\nname: typion\ndescription: Use for any change to this application's data layer with Typion — collections, access rules, hooks, queries and descriptors, API routes, seeds, migrations, or tests that touch typion.config.ts or the typion/ folder next to it.\n---\n\n${SKILL_MARKER}\n\nTypion is newer than your training data. Its guide ships with the installed version, in \\`node_modules/typion/docs/\\`.\n\n1. Read \\`node_modules/typion/docs/README.md\\`: the model, the rules, where things go.\n2. Read the page for the task:\n - \\`collections.md\\`: a collection, its columns and relations, a many-to-many\n - \\`access.md\\`: who reads and writes what, hidden columns, what a caller sees\n - \\`auth.md\\`: signing in, who the caller is\n - \\`hooks.md\\`: reacting to writes\n - \\`queries.md\\`: reads, writes, descriptors, transactions, errors\n - \\`http.md\\`: Next.js pages and server actions, Hono, the routes, the browser client, business operations\n - \\`database.md\\`: drivers, migrations, seed\n - \\`testing.md\\`: tests\n - \\`features/\\`: localization, multi-tenancy, soft delete, versions and drafts\n3. Before you call the change done: \\`tsc\\` passes, every new collection has its rules, a test covers a caller the\n rules allow and one they refuse, and a schema change has its migration.\n`\n\ntype Outcome = 'created' | 'updated' | 'unchanged' | 'kept'\n\nfunction upsert(existing: string): string {\n const eol = existing.includes('\\r\\n') ? '\\r\\n' : '\\n'\n const block = AGENT_RULES.replace(/\\n/g, eol)\n const start = existing.indexOf(START_MARKER)\n const end = existing.indexOf(END_MARKER, start)\n if (start !== -1 && end !== -1) {\n return existing.slice(0, start) + block + existing.slice(end + END_MARKER.length)\n }\n if (existing.length === 0) return `${block}${eol}`\n const body = existing.endsWith(eol) ? existing : `${existing}${eol}`\n return `${body}${eol}${block}${eol}`\n}\n\nfunction writeFile(path: string, next: string, previous: string | null): Outcome {\n if (previous === next) return 'unchanged'\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, next)\n return previous === null ? 'created' : 'updated'\n}\n\nfunction read(path: string): string | null {\n return existsSync(path) ? readFileSync(path, 'utf8') : null\n}\n\n// The block goes where the project keeps its notes: AGENTS.md, or CLAUDE.md when only that one exists; a project\n// with neither gets both, CLAUDE.md importing AGENTS.md. The skill is rewritten only while it is still Typion's.\nexport function writeAgentNotes(root: string, io: Io): void {\n const agentsPath = join(root, 'AGENTS.md')\n const claudePath = join(root, 'CLAUDE.md')\n const agents = read(agentsPath)\n const claude = read(claudePath)\n const report = (path: string, outcome: Outcome) => {\n const verb = { created: 'Created', updated: 'Updated', kept: 'Kept', unchanged: null }[outcome]\n if (verb !== null) io.out(`${verb} ${relative(process.cwd(), path)}.`)\n }\n\n const claudeHostsBlock = claude?.includes(START_MARKER) ?? false\n if (agents !== null && (agents.includes(START_MARKER) || !claudeHostsBlock)) {\n report(agentsPath, writeFile(agentsPath, upsert(agents), agents))\n } else if (claude !== null) {\n report(claudePath, writeFile(claudePath, upsert(claude), claude))\n } else {\n report(agentsPath, writeFile(agentsPath, upsert(''), null))\n report(claudePath, writeFile(claudePath, '@AGENTS.md\\n', null))\n }\n\n const skillPath = join(root, '.claude', 'skills', 'typion', 'SKILL.md')\n const skill = read(skillPath)\n if (skill !== null && !skill.includes(SKILL_MARKER)) {\n io.out(`Kept ${relative(process.cwd(), skillPath)} (it is not Typion's any more).`)\n } else {\n report(skillPath, writeFile(skillPath, SKILL, skill))\n }\n}\n","import { spawnSync } from 'node:child_process'\nimport { createInterface } from 'node:readline/promises'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative } from 'node:path'\nimport { writeAgentNotes } from './agents.js'\nimport { CliError, type Io } from './output.js'\n\ntype PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\n// npm's `latest` Drizzle is 0.x, and a later release candidate can break the engine (rc.5 does): the version the\n// engine is built on, which its `package.json` names as a peer.\nconst DRIZZLE = '1.0.0-rc.4'\n\nconst TRANSPORTS = ['@typion/rest', '@typion/rpc']\n\nfunction packageManager(root: string): PackageManager {\n if (existsSync(join(root, 'pnpm-lock.yaml'))) return 'pnpm'\n if (existsSync(join(root, 'yarn.lock'))) return 'yarn'\n if (existsSync(join(root, 'bun.lock')) || existsSync(join(root, 'bun.lockb'))) return 'bun'\n if (existsSync(join(root, 'package-lock.json'))) return 'npm'\n const agent = process.env.npm_config_user_agent ?? ''\n if (agent.startsWith('yarn')) return 'yarn'\n if (agent.startsWith('bun')) return 'bun'\n if (agent.startsWith('pnpm')) return 'pnpm'\n return 'npm'\n}\n\nfunction installCommand(\n manager: PackageManager,\n packages: readonly string[],\n dev: boolean,\n): { command: string; args: string[] } {\n const flag = dev ? (manager === 'npm' ? '--save-dev' : '-D') : ''\n const verb = manager === 'npm' ? 'install' : 'add'\n return {\n command: manager,\n args: [verb, ...(flag === '' ? [] : [flag]), ...packages],\n }\n}\n\nasync function confirm(question: string, io: Io): Promise<boolean> {\n if (!process.stdin.isTTY) {\n io.out(`${question} — not a terminal, so nothing was installed. Re-run with --yes.`)\n return false\n }\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n try {\n const answer = (await rl.question(`${question} [Y/n] `)).trim().toLowerCase()\n return answer === '' || answer === 'y' || answer === 'yes'\n } finally {\n rl.close()\n }\n}\n\nfunction run(command: string, args: readonly string[], cwd: string, io: Io): void {\n io.out(`> ${command} ${args.join(' ')}`)\n const result = spawnSync(command, [...args], { cwd, stdio: 'inherit' })\n if (result.error !== undefined || (result.status !== null && result.status !== 0)) {\n throw new CliError(`\\`${command} ${args.join(' ')}\\` failed; install them yourself and re-run.`)\n }\n}\n\ntype Project = {\n readonly root: string\n readonly src: string\n readonly framework: 'next' | 'hono' | 'none'\n readonly dependencies: ReadonlySet<string>\n readonly appDir: string | null\n}\n\nfunction readJson(path: string): Record<string, any> | null {\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as Record<string, any>\n } catch {\n return null\n }\n}\n\nfunction inspect(cwd: string): Project {\n const pkg = readJson(join(cwd, 'package.json'))\n if (pkg === null) throw new CliError(`No package.json in ${cwd}: run this inside your project.`)\n const deps = { ...pkg.dependencies, ...pkg.devDependencies } as Record<string, string>\n const src = existsSync(join(cwd, 'src')) ? join(cwd, 'src') : cwd\n const appDir = [join(src, 'app'), join(cwd, 'app')].find((dir) => existsSync(dir)) ?? null\n return {\n root: cwd,\n src,\n framework: deps.next !== undefined ? 'next' : deps.hono !== undefined ? 'hono' : 'none',\n dependencies: new Set(Object.keys(deps)),\n appDir,\n }\n}\n\nfunction write(path: string, contents: string, io: Io): boolean {\n if (existsSync(path)) {\n io.out(`Kept ${relative(process.cwd(), path)} (it exists already).`)\n return false\n }\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, contents)\n io.out(`Created ${relative(process.cwd(), path)}.`)\n return true\n}\n\nconst COLLECTION = `import { text } from 'drizzle-orm/pg-core'\nimport { collection } from 'typion'\n\nexport const pages = collection('pages', {\n columns: {\n title: text().notNull(),\n slug: text().notNull().unique(),\n },\n public: true,\n})\n`\n\nfunction configFile(driver: 'pglite' | 'postgres'): string {\n const db =\n driver === 'pglite'\n ? ` db: pglite({ dataDir: '.pglite' }),`\n : ` db: dbAdapter((relations) => drizzle(process.env.DATABASE_URL!, { relations }), {\\n url: process.env.DATABASE_URL,\\n }),`\n const imports =\n driver === 'pglite'\n ? `import { defineConfig, defineSetup } from 'typion'\\nimport { pglite } from 'typion/db/pglite'`\n : `import { drizzle } from 'drizzle-orm/node-postgres'\\nimport { dbAdapter, defineConfig, defineSetup } from 'typion'`\n return `${imports}\nimport { pages } from './typion/collections/pages.ts'\n\n// What the application knows about a caller: rules, hooks and field rules read it. Registered below as well, since\n// field rules are typed before this config exists.\nexport type AppContext = {\n actorId: string | null\n}\n\n// A constant of its own: the collections read it to type their options and their columns, which happens before\n// this config exists. It takes the features (\\`localization\\`, \\`multiTenant\\`) and the plugins (\\`plugins: […]\\`).\nexport const setup = defineSetup({})\n\nexport const config = defineConfig({\n setup,\n collections: [pages],\n${db}\n // Who is calling. Return your own shape; declare the return type, the body may query \\`system\\`.\n context: async ({ headers }): Promise<AppContext> => {\n void headers\n return { actorId: null }\n },\n})\n\ndeclare module 'typion' {\n interface Register {\n setup: typeof setup\n config: typeof config\n context: AppContext\n }\n}\n`\n}\n\n// Every import Typion writes ends in `.ts`, as Node needs to load the config the way the CLI does. TypeScript takes\n// them with `allowImportingTsExtensions` where nothing is emitted (Next.js), and with\n// `rewriteRelativeImportExtensions` where `tsc` builds the project.\nfunction allowTsImports(root: string, io: Io): void {\n const path = join(root, 'tsconfig.json')\n if (!existsSync(path)) return\n const json = readJson(path)\n const options = (json?.compilerOptions ?? {}) as Record<string, unknown>\n if (\n options.allowImportingTsExtensions === true ||\n options.rewriteRelativeImportExtensions === true\n ) {\n return\n }\n const flag =\n options.noEmit === true ? 'allowImportingTsExtensions' : 'rewriteRelativeImportExtensions'\n if (json === null) {\n io.out(\n `Add \"${flag}\": true to the compilerOptions of tsconfig.json: Typion's imports end in .ts.`,\n )\n return\n }\n json.compilerOptions = { ...options, [flag]: true }\n writeFileSync(path, `${JSON.stringify(json, null, 2)}\\n`)\n io.out(`Set ${flag} in tsconfig.json: Typion's imports end in .ts.`)\n}\n\n// The pnpm that will install: the version the project declares, which pnpm switches to; else the one running\n// `init`; else the one on the PATH.\nfunction pnpmMajor(root: string): number | null {\n const declared = /^pnpm@(\\d+)/.exec(String(readJson(join(root, 'package.json'))?.packageManager))\n const agent = /^pnpm\\/(\\d+)/.exec(process.env.npm_config_user_agent ?? '')\n const version =\n declared?.[1] ??\n agent?.[1] ??\n /^(\\d+)\\./.exec(\n spawnSync('pnpm', ['--version'], { cwd: root, encoding: 'utf8' }).stdout ?? '',\n )?.[1]\n return version === undefined ? null : Number(version)\n}\n\n// pnpm reads its settings from the workspace's root, the nearest pnpm-workspace.yaml up the tree.\nfunction workspaceFile(root: string): string {\n for (let dir = root; dirname(dir) !== dir; dir = dirname(dir)) {\n if (existsSync(join(dir, 'pnpm-workspace.yaml'))) return join(dir, 'pnpm-workspace.yaml')\n }\n return join(root, 'pnpm-workspace.yaml')\n}\n\n// From pnpm 11 a build script that is neither allowed nor denied fails the install, and drizzle-kit brings\n// esbuild's: `init` would stop at its own install. pnpm then leaves a placeholder under `allowBuilds`, which fails\n// every install after it, and a second `allowBuilds` added by hand is a duplicated key.\nfunction allowEsbuild(root: string, io: Io): void {\n const major = pnpmMajor(root)\n if (major === null || major < 11) return\n const path = workspaceFile(root)\n const name = relative(process.cwd(), path)\n const why = `pnpm ${major} fails an install on a build script it was not told to run, and drizzle-kit brings esbuild's`\n if (!existsSync(path)) {\n writeFileSync(path, 'allowBuilds:\\n esbuild: true\\n')\n io.out(`Created ${name} to allow esbuild's build script: ${why}.`)\n return\n }\n const text = readFileSync(path, 'utf8')\n const eol = text.includes('\\r\\n') ? '\\r\\n' : '\\n'\n const lines = text.split(/\\r?\\n/)\n const valueOf = (line: string) =>\n line\n .slice(line.indexOf(':') + 1)\n .replace(/(^|\\s)#.*$/, '')\n .trim()\n const key = lines.findIndex((line) => /^allowBuilds\\s*:/.test(line))\n if (key === -1) {\n if (lines.at(-1) === '') lines.pop()\n lines.push(...(lines.length === 0 ? [] : ['']), 'allowBuilds:', ' esbuild: true', '')\n } else if (valueOf(lines[key]!) !== '') {\n // A flow mapping, `allowBuilds: { … }`, is the project's to edit.\n if (!/\\besbuild\\b/.test(lines[key]!))\n io.out(`Add esbuild: true to allowBuilds in ${name}: ${why}.`)\n return\n } else {\n let end = key + 1\n while (end < lines.length && /^(\\s|#|$)/.test(lines[end]!)) end++\n const block = lines.slice(key + 1, end)\n const entry = block.findIndex((line) => /^\\s+(['\"]?)esbuild\\1\\s*:/.test(line))\n if (entry === -1) {\n const indent = block.map((line) => /^(\\s+)[^\\s#]/.exec(line)?.[1]).find(Boolean) ?? ' '\n lines.splice(key + 1, 0, `${indent}esbuild: true`)\n } else {\n // A value the project chose stays; anything else is pnpm's placeholder.\n if (/^(true|false)$/i.test(valueOf(block[entry]!))) return\n lines[key + 1 + entry] = `${/^\\s+/.exec(block[entry]!)![0]}esbuild: true`\n }\n }\n writeFileSync(path, lines.join(eol))\n io.out(`Set allowBuilds: esbuild: true in ${name}: ${why}.`)\n}\n\nconst ROUTE = `import { rest } from '@typion/rest'\nimport { rpc } from '@typion/rpc'\nimport { routeHandlers } from 'typion/next'\nimport { config } from '@/typion.config.ts'\n\n// What the app serves over HTTP: a resource per collection, and the endpoint the browser client posts to. Leave\n// out what you do not use.\nexport const { GET, POST, PATCH, PUT, DELETE, OPTIONS } = await routeHandlers(config, {\n transports: [rest(), rpc()],\n})\n`\n\nexport async function init(\n cwd: string,\n io: Io,\n options: { driver?: string; yes?: boolean; skipInstall?: boolean },\n): Promise<void> {\n const project = inspect(cwd)\n const driver = options.driver === 'postgres' ? 'postgres' : 'pglite'\n\n // The sample collection comes with a new config only: a run after an upgrade refreshes the notes and leaves the\n // project's collections as they are.\n if (write(join(project.src, 'typion.config.ts'), configFile(driver), io)) {\n write(join(project.src, 'typion', 'collections', 'pages.ts'), COLLECTION, io)\n }\n allowTsImports(project.root, io)\n\n if (project.framework === 'next' && project.appDir !== null) {\n write(join(project.appDir, 'api', '[...path]', 'route.ts'), ROUTE, io)\n }\n writeAgentNotes(project.root, io)\n\n const manager = packageManager(project.root)\n if (manager === 'pnpm') allowEsbuild(project.root, io)\n await installDependencies(project, manager, driver, io, options)\n\n io.out('')\n io.out('Next:')\n io.out(\n ' 1. turn on what you need: `softDelete` or `versions` on a collection, `localization`, `multiTenant` or `plugins` in `defineSetup`',\n )\n io.out(\n existsSync(join(project.root, 'typion', 'migrations'))\n ? ' 2. `typion db migrate` to apply the migrations, then `typion db seed`'\n : ' 2. `typion db push` to create the tables, then `typion db seed`',\n )\n if (project.framework === 'next') {\n io.out(\n ' 3. read from a server component with `const app = await getApp(config)` (typion/next)',\n )\n }\n // The app's entry is the developer's own file: what to add to it is said, not written. It may serve only routes\n // of its own, so the transports come with the step that mounts them rather than with what every app installs.\n if (project.framework === 'hono') {\n io.out(\n ' 3. bind the caller in your own routes with `typionMiddleware(config)`: `c.var.typion`',\n )\n const transports = TRANSPORTS.filter((name) => !project.dependencies.has(name))\n const add = installCommand(manager, transports, false)\n const install = transports.length === 0 ? '' : `\\`${add.command} ${add.args.join(' ')}\\`, then `\n io.out(\n ` 4. to serve the collections over HTTP: ${install}\\`.all('/api/*', typionRoutes(config, { transports: [rest(), rpc()] }))\\` (typion/hono)`,\n )\n }\n}\n\nasync function installDependencies(\n project: Project,\n manager: PackageManager,\n driver: 'pglite' | 'postgres',\n io: Io,\n options: { yes?: boolean; skipInstall?: boolean },\n): Promise<void> {\n const deps = [\n 'typion',\n 'drizzle-orm',\n driver === 'pglite' ? '@electric-sql/pglite' : 'pg',\n // The route `init` writes on Next.js imports them.\n ...(project.framework === 'next' ? TRANSPORTS : []),\n ]\n const dev = ['drizzle-kit']\n const spec = (name: string) => (name.startsWith('drizzle-') ? `${name}@${DRIZZLE}` : name)\n const missing = deps.filter((name) => !project.dependencies.has(name)).map(spec)\n const missingDev = dev.filter((name) => !project.dependencies.has(name)).map(spec)\n if (missing.length === 0 && missingDev.length === 0) return\n\n const lines = [\n ...(missing.length === 0 ? [] : [installCommand(manager, missing, false)]),\n ...(missingDev.length === 0 ? [] : [installCommand(manager, missingDev, true)]),\n ]\n io.out('')\n io.out('Missing packages:')\n for (const line of lines) io.out(` ${line.command} ${line.args.join(' ')}`)\n\n if (options.skipInstall === true) return\n const ok = options.yes === true || (await confirm(`Install them with ${manager}?`, io))\n if (!ok) return\n for (const line of lines) run(line.command, line.args, project.root, io)\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport type { LoadedConfig } from './config.js'\nimport { CliError, type Io } from './output.js'\n\nfunction pascal(name: string): string {\n return name.replace(/(^|[-_ ])(\\w)/g, (_, __, char: string) => char.toUpperCase())\n}\n\nfunction camel(name: string): string {\n const upper = pascal(name)\n return upper.charAt(0).toLowerCase() + upper.slice(1)\n}\n\n// Where the collections of this project live: next to the ones already there, else beside the config.\nfunction collectionsDir(loaded: LoadedConfig, given?: string): string {\n if (given !== undefined) return isAbsolute(given) ? given : resolve(process.cwd(), given)\n const candidates = [join(loaded.dir, 'typion', 'collections'), join(loaded.dir, 'collections')]\n return candidates.find((dir) => existsSync(dir)) ?? candidates[0]!\n}\n\n// No rule is written for the developer: a generated `read: true` would serve every row to anyone, anonymous callers\n// included, until someone noticed. In a multi-tenant application the rows belong to the caller's tenant.\nfunction template(name: string, tenant: boolean): string {\n return `import { text } from 'drizzle-orm/pg-core'\nimport { collection } from 'typion'\n\nexport const ${camel(name)} = collection('${camel(name)}', {\n columns: {\n // Plain Drizzle columns; the features and plugins add their own options next to \\`columns\\`.\n title: text().notNull(),\n },${tenant ? '\\n tenant: true,' : ''}\n}).define({\n // Deny by default: an operation without a rule is refused. Give each one the rule it needs, for example\n // \\`read: ({ ctx }) => ctx.actorId !== null\\`.\n access: {},\n})\n`\n}\n\nfunction importPath(from: string, to: string): string {\n const path = relative(from, to).replaceAll('\\\\', '/')\n return path.startsWith('.') ? path : `./${path}`\n}\n\n// Best effort: adds the import and the entry to `collections: [...]`. When the config does not match the\n// shape the CLI understands, it prints the two lines instead of guessing.\nfunction register(loaded: LoadedConfig, name: string, file: string, io: Io): void {\n const source = readFileSync(loaded.path, 'utf8')\n const specifier = importPath(loaded.dir, file).replace(/\\.ts$/, '.ts')\n const line = `import { ${camel(name)} } from '${specifier}'`\n const list = /collections:\\s*\\[([^\\]]*)\\]/.exec(source)\n if (source.includes(line) || list === null) {\n io.out('Add it to the config:')\n io.out(` ${line}`)\n io.out(` collections: [ …, ${camel(name)} ]`)\n return\n }\n const entries = list[1]!.trim()\n const updated = source\n .replace(/(^import .*\\n)(?![\\s\\S]*^import )/m, `$1${line}\\n`)\n .replace(\n /collections:\\s*\\[([^\\]]*)\\]/,\n `collections: [${entries === '' ? '' : `${entries.replace(/,\\s*$/, '')}, `}${camel(name)}]`,\n )\n writeFileSync(loaded.path, updated)\n io.out(`Registered it in ${relative(process.cwd(), loaded.path)}.`)\n}\n\nfunction pluginTemplate(name: string): string {\n const id = camel(name)\n const Kinds = `${pascal(name)}Kinds`\n const Options = `${pascal(name)}Options`\n return `import { definePlugin } from 'typion'\nimport type { CollectionKinds } from 'typion'\n\n// What this plugin adds to every collection. A collection that does not set the option gets nothing.\nexport type ${Options} = { ${id}?: boolean }\n\n// How the option turns into columns and into engine options, read from \\`this['options']\\`.\ninterface ${Kinds} extends CollectionKinds {\n readonly columns: this['options'] extends { ${id}: true } ? {} : {}\n readonly entity: this['options'] extends { ${id}: true } ? {} : {}\n}\n\nexport function ${id}() {\n return definePlugin({\n id: '${id}',\n collection: {\n $options: {} as ${Options},\n $kinds: {} as ${Kinds},\n // Option keys this plugin reads, so they never reach the engine as entity options.\n consumes: ['${id}'],\n columns: (options) => (options.${id} === true ? {} : {}),\n entity: (options) => (options.${id} === true ? {} : {}),\n },\n // Tables, relations, entities, hooks, api, routes, errors and context go here too; see @typion/audit.\n })\n}\n`\n}\n\nexport function makePlugin(\n loaded: LoadedConfig,\n io: Io,\n name: string,\n options: { dir?: string },\n): void {\n if (!/^[a-z][a-z0-9_-]*$/i.test(name)) {\n throw new CliError(`'${name}' is not a plugin name (letters, digits, dash, underscore)`)\n }\n const dir =\n options.dir === undefined\n ? join(loaded.dir, 'typion', 'plugins')\n : isAbsolute(options.dir)\n ? options.dir\n : resolve(process.cwd(), options.dir)\n const file = join(dir, `${camel(name)}.ts`)\n if (existsSync(file)) throw new CliError(`${relative(process.cwd(), file)} already exists`)\n mkdirSync(dir, { recursive: true })\n writeFileSync(file, pluginTemplate(name))\n io.out(`Created ${relative(process.cwd(), file)}.`)\n io.out('Install it in the config:')\n io.out(` import { ${camel(name)} } from './${relative(loaded.dir, file).replaceAll('\\\\', '/')}'`)\n io.out(` export const setup = defineSetup({ plugins: [ …, ${camel(name)}() ] })`)\n}\n\nexport function makeCollection(\n loaded: LoadedConfig,\n io: Io,\n name: string,\n options: { dir?: string },\n): void {\n if (!/^[a-z][a-z0-9_-]*$/i.test(name)) {\n throw new CliError(`'${name}' is not a collection name (letters, digits, dash, underscore)`)\n }\n const dir = collectionsDir(loaded, options.dir)\n const file = join(dir, `${camel(name)}.ts`)\n if (existsSync(file)) throw new CliError(`${relative(process.cwd(), file)} already exists`)\n mkdirSync(dirname(file), { recursive: true })\n const tenant = loaded.config.definition.plugins.some((plugin) => plugin.id === 'multiTenant')\n writeFileSync(file, template(name, tenant))\n io.out(`Created ${relative(process.cwd(), file)}.`)\n register(loaded, name, file, io)\n io.out('Then `typion db push` (or `typion db generate` + `typion db migrate`).')\n}\n","import { parseArgs } from 'node:util'\nimport { ConfigError } from '../errors.js'\nimport { loadConfig } from './config.js'\nimport * as db from './db.js'\nimport { init } from './init.js'\nimport { makeCollection, makePlugin } from './make.js'\nimport { CliError, consoleIo, type Io } from './output.js'\n\nconst HELP = `typion — the CLI of a Typion project\n\nUsage\n typion <group> <command> [options]\n\nDatabase (everything that touches the schema, through drizzle-kit)\n typion db push [--force] make the database match the config (development)\n typion db generate [--name x] write the SQL of what changed, with its snapshot\n typion db migrate apply the migrations the database has not applied\n typion db seed [--file path] run the project's seed through the engine\n [--random] ask drizzle-seed for rows instead (--count, --seed)\n [--reset] empty every table of the config first\n [--if-empty] do nothing when a collection already holds rows\n typion db status what is applied, what is pending\n typion db studio [--port n] open Drizzle Studio on this config\n\nProject\n typion make collection <name> [--dir path] a new collection, registered in the config\n typion make plugin <name> [--dir path] a plugin skeleton for this project\n typion init [--driver pglite|postgres] [--yes] [--skip-install]\n set Typion up in a project that exists, with the\n notes its agents read (run it again after upgrading)\n\nOptions\n --config <path> the config to read; by default the nearest typion.config.ts\n --help this text (also: typion db --help)\n`\n\nconst DB_HELP = `typion db — the database of a Typion config\n\n push [--force] make the database match the config (development)\n generate [--name x] write the SQL of what changed, with its snapshot\n migrate apply the migrations the database has not applied\n seed [--file|--random] fill the database: the project's seed, or drizzle-seed rows\n status what is applied, what is pending\n studio [--port n] open Drizzle Studio on this config\n`\n\nconst OPTIONS = {\n config: { type: 'string' },\n name: { type: 'string' },\n dir: { type: 'string' },\n driver: { type: 'string' },\n port: { type: 'string' },\n file: { type: 'string' },\n count: { type: 'string' },\n seed: { type: 'string' },\n force: { type: 'boolean' },\n random: { type: 'boolean' },\n reset: { type: 'boolean' },\n 'if-empty': { type: 'boolean' },\n 'skip-install': { type: 'boolean' },\n yes: { type: 'boolean' },\n help: { type: 'boolean' },\n} as const\n\nfunction port(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined\n if (!/^\\d+$/.test(raw)) throw new CliError('--port must be a number')\n return Number(raw)\n}\n\nexport async function run(argv: readonly string[], io: Io = consoleIo, cwd = process.cwd()) {\n const { values, positionals } = parseArgs({\n args: [...argv],\n options: OPTIONS,\n allowPositionals: true,\n strict: true,\n })\n const [group, command, argument] = positionals\n\n if (group === undefined || values.help === true) {\n io.out(group === 'db' ? DB_HELP : HELP)\n return\n }\n\n const config = async () => loadConfig(cwd, values.config)\n\n switch (`${group} ${command ?? ''}`.trim()) {\n case 'db push':\n return db.push(await config(), io, { force: values.force })\n case 'db generate':\n return db.generate(await config(), io, { name: values.name })\n case 'db migrate':\n return db.migrate(await config(), io)\n case 'db seed':\n return db.seed(await config(), io, {\n file: values.file,\n random: values.random,\n count: values.count === undefined ? undefined : Number(values.count),\n seed: values.seed === undefined ? undefined : Number(values.seed),\n reset: values.reset,\n ifEmpty: values['if-empty'],\n })\n case 'db status':\n return db.status(await config(), io)\n case 'db studio':\n return db.studio(await config(), io, { port: port(values.port) })\n case 'db':\n io.out(DB_HELP)\n return\n case 'make collection': {\n if (argument === undefined) throw new CliError('Usage: typion make collection <name>')\n return makeCollection(await config(), io, argument, { dir: values.dir })\n }\n case 'make plugin': {\n if (argument === undefined) throw new CliError('Usage: typion make plugin <name>')\n return makePlugin(await config(), io, argument, { dir: values.dir })\n }\n case 'make':\n throw new CliError('Usage: typion make collection|plugin <name>')\n case 'init':\n return init(cwd, io, {\n driver: values.driver,\n yes: values.yes,\n skipInstall: values['skip-install'],\n })\n default:\n throw new CliError(\n `Unknown command '${[group, command].filter(Boolean).join(' ')}'. Try \\`typion --help\\`.`,\n )\n }\n}\n\nexport async function main(argv: readonly string[]): Promise<number> {\n try {\n await run(argv)\n return 0\n } catch (error) {\n // What the user has to change, in a sentence: a stack trace would bury it.\n if (error instanceof CliError || error instanceof ConfigError) {\n console.error(error.message)\n return 1\n }\n console.error(error)\n return 1\n }\n}\n\nexport { CliError }\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { n as ConfigError } from "./errors-D-CKO-px.js";
|
|
2
|
+
import { getTableColumns } from "drizzle-orm";
|
|
3
|
+
//#region src/schema/column-kinds.ts
|
|
4
|
+
const COLUMN_KIND_MARKER = Symbol.for("typion:columnKind");
|
|
5
|
+
const registry = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function markerOf(column) {
|
|
7
|
+
return column.config?.[COLUMN_KIND_MARKER] ?? registry.get(column);
|
|
8
|
+
}
|
|
9
|
+
function defineColumnKind(id) {
|
|
10
|
+
return {
|
|
11
|
+
id,
|
|
12
|
+
mark(builder, meta) {
|
|
13
|
+
const config = builder.config;
|
|
14
|
+
if (config === void 0) throw new ConfigError(`Column kind '${id}': the builder has no runtime config to mark`);
|
|
15
|
+
config[COLUMN_KIND_MARKER] = {
|
|
16
|
+
id,
|
|
17
|
+
meta
|
|
18
|
+
};
|
|
19
|
+
return builder;
|
|
20
|
+
},
|
|
21
|
+
markColumns(table, columns) {
|
|
22
|
+
const built = getTableColumns(table);
|
|
23
|
+
for (const key of columns) {
|
|
24
|
+
const column = built[key];
|
|
25
|
+
if (column === void 0) throw new ConfigError(`Column kind '${id}': column '${String(key)}' does not exist on the table`);
|
|
26
|
+
registry.set(column, {
|
|
27
|
+
id,
|
|
28
|
+
meta: void 0
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
is(column) {
|
|
33
|
+
return markerOf(column)?.id === id;
|
|
34
|
+
},
|
|
35
|
+
metaOf(column) {
|
|
36
|
+
const marker = markerOf(column);
|
|
37
|
+
return marker?.id === id ? marker.meta : void 0;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function readColumnKind(column) {
|
|
42
|
+
return markerOf(column)?.id ?? null;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { defineColumnKind as n, readColumnKind as r, COLUMN_KIND_MARKER as t };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=column-kinds-Bkm4NJI2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-kinds-Bkm4NJI2.js","names":[],"sources":["../src/schema/column-kinds.ts"],"sourcesContent":["import { getTableColumns } from 'drizzle-orm'\nimport type { AnyPgColumn, PgTable } from 'drizzle-orm/pg-core'\nimport { ConfigError } from '../errors.js'\nimport type { ColumnKind } from '../types/plugin.js'\n\nexport type { ColumnKind }\n\n// A global symbol so a second copy of the package (or a plugin bundled separately) still reads\n// the same marker; it lives on the builder config because built columns keep a reference to it,\n// and `{ ...config }` copies symbol keys, so the marker survives pgTable() and column cloning.\nexport const COLUMN_KIND_MARKER: unique symbol = Symbol.for(\n 'typion:columnKind',\n) as typeof COLUMN_KIND_MARKER\n\ntype Marker = { readonly id: string; readonly meta: unknown }\n\ntype WithConfig = { config?: { [COLUMN_KIND_MARKER]?: Marker } }\n\n// Fallback registry for columns marked after the fact (`markColumns`): keyed by the built column\n// object, so it cannot leak across tables sharing a builder.\nconst registry = new WeakMap<object, Marker>()\n\nfunction markerOf(column: AnyPgColumn): Marker | undefined {\n const fromConfig = (column as unknown as WithConfig).config?.[COLUMN_KIND_MARKER]\n return fromConfig ?? registry.get(column)\n}\n\nexport function defineColumnKind<const TId extends string, TMeta = undefined>(\n id: TId,\n): ColumnKind<TId, TMeta> {\n return {\n id,\n mark(builder, meta) {\n const config = (builder as unknown as WithConfig).config\n if (config === undefined) {\n throw new ConfigError(`Column kind '${id}': the builder has no runtime config to mark`)\n }\n config[COLUMN_KIND_MARKER] = { id, meta }\n return builder\n },\n markColumns(table, columns) {\n const built = getTableColumns(table as PgTable) as Record<string, AnyPgColumn>\n for (const key of columns) {\n const column = built[key as string]\n if (column === undefined) {\n throw new ConfigError(\n `Column kind '${id}': column '${String(key)}' does not exist on the table`,\n )\n }\n registry.set(column, { id, meta: undefined })\n }\n },\n is(column) {\n return markerOf(column)?.id === id\n },\n metaOf(column) {\n const marker = markerOf(column)\n return marker?.id === id ? (marker.meta as TMeta) : undefined\n },\n }\n}\n\nexport function readColumnKind(column: AnyPgColumn): string | null {\n return markerOf(column)?.id ?? null\n}\n"],"mappings":";;;AAUA,MAAa,qBAAoC,OAAO,IACtD,mBACF;AAQA,MAAM,2BAAW,IAAI,QAAwB;AAE7C,SAAS,SAAS,QAAyC;CAEzD,OADoB,OAAiC,SAAS,uBACzC,SAAS,IAAI,MAAM;AAC1C;AAEA,SAAgB,iBACd,IACwB;CACxB,OAAO;EACL;EACA,KAAK,SAAS,MAAM;GAClB,MAAM,SAAU,QAAkC;GAClD,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,YAAY,gBAAgB,GAAG,6CAA6C;GAExF,OAAO,sBAAsB;IAAE;IAAI;GAAK;GACxC,OAAO;EACT;EACA,YAAY,OAAO,SAAS;GAC1B,MAAM,QAAQ,gBAAgB,KAAgB;GAC9C,KAAK,MAAM,OAAO,SAAS;IACzB,MAAM,SAAS,MAAM;IACrB,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,YACR,gBAAgB,GAAG,aAAa,OAAO,GAAG,EAAE,8BAC9C;IAEF,SAAS,IAAI,QAAQ;KAAE;KAAI,MAAM,KAAA;IAAU,CAAC;GAC9C;EACF;EACA,GAAG,QAAQ;GACT,OAAO,SAAS,MAAM,CAAC,EAAE,OAAO;EAClC;EACA,OAAO,QAAQ;GACb,MAAM,SAAS,SAAS,MAAM;GAC9B,OAAO,QAAQ,OAAO,KAAM,OAAO,OAAiB,KAAA;EACtD;CACF;AACF;AAEA,SAAgB,eAAe,QAAoC;CACjE,OAAO,SAAS,MAAM,CAAC,EAAE,MAAM;AACjC"}
|